3.2 Using HTTPS outcalls
Since blockchains are a form of replicated state machine, where each replica must perform the same computations within the same state to make the same transitions each round, doing computations with results from an external source may lead to a state divergence. Tools like oracles have been used in the past to facilitate retrieving external data. However, on ICP, canisters can communicate directly with external servers or other blockchains through HTTPS outcalls. The response of these HTTP calls can then be used by canisters in a way that the replica can safely be updated using the response without the risk of a state divergence.
This guide uses the term HTTPS to refer to both the HTTP and HTTPS protocols. This is because typically all traffic on a public network uses the secure HTTPS protocol.
HTTPS outcalls enable many use cases and have several advantages compared to using third-party services like oracles to handle external requests. HTTPS outcalls use a stronger trust model since there are no external intermediaries required. Most real-world dapps have a need for accessing data stored in off-chain entities, as most digital data is still stored in traditional 'Web 2' servers.
Supported HTTP methods
Currently, HTTPS outcalls support GET
, HEAD
, and POST
methods for HTTP requests. In this guide, you'll look at examples for the GET
method.
Cycles
Cycles used to pay for an HTTPS call must be explicitly transferred with the call. They will not be automatically deducted from the caller's balance.
HTTPS outcalls API
A canister can make an HTTPS outcall by using the http_request
method with the following parameters:
url
: Specifies the requested URL; must be valid per the standard RFC-3986. The length must not exceed8192
and may include a custom port number.max_response_bytes
: Specifies the maximum size of the request in bytes and must not exceed 2MB. This field is optional; if this field is not specified, the maximum of 2MB will be used.
It is recommended to set max_response_bytes
, since using it appropriately can save developers a significant amount of cycles.
method
: Specifies the method; currently, onlyGET
,HEAD
, andPOST
are supported.headers
: Specifies the list of HTTP request headers and their corresponding values.body
: Specifies the content of the request's body. This field is optional.transform
: Specifies a function that transforms raw responses to sanitized responses and a byte-encoded context that is provided to the function upon invocation, along with the response to be sanitized. This field is optional; if it is provided, the calling canister itself must export this function.
The returned response, including the response to the transform
function if specified, will contain the following content:
status
: Specifies the response status (e.g., 200, 404).headers
: Specifies the list of HTTP response headers and their corresponding values.body
: Specifies the response's body.
IPv6
When deploying applications to ICP, HTTPS outcalls can only be made to APIs that support IPv6. You can check if an API supports IPv6 by using a tool such as https://ready.chair6.net/.
HTTP GET
To demonstrate how to use the HTTPS GET
outcall, open the ICP Ninja Daily Planner example, which uses HTTPS outcalls to retrieve an "On this day" fact.
In the project's backend/app.mo
file, the HTTPS outcall is defined through the following lines:
// Update function to fetch and store "On This Day" data via HTTPS outcall.
public func fetchAndStoreOnThisDay(date : Text) : async Result.Result<Text, Text> {
let currentData : DayData = switch (HashMap.get(dayData, thash, date)) {
case null { { notes = []; onThisDay = null } };
case (?data) { data };
};
// Perform HTTPS outcall only if needed.
if (currentData.onThisDay == null) {
let parts = Iter.toArray(Text.split(date, #char '-'));
let month = Option.get(Nat.fromText(parts[1]), 1);
let day = Option.get(Nat.fromText(parts[2]), 1);
// Prepare the https request.
// "transform" is used to specify how the HTTP response is processed before consensus tries to agree on a response.
// This is useful to e.g. filter out timestamps out of headers that will be different across the responses the different replicas receive.
// You can read more about it here: https://internetcomputer.org/docs/building-apps/network-features/using-http/https-outcalls/overview
let http_request : IC.http_request_args = {
// API must support IPv6
url = "https://byabbe.se/on-this-day/" # Nat.toText(month) # "/" # Nat.toText(day) # "/events.json";
max_response_bytes = null; //optional for request
headers = [];
body = null; //optional for request
method = #get;
transform = ?{
function = transform;
context = Blob.fromArray([]);
};
};
// Perform HTTPS outcall using roughly 100B cycles.
// See https outcall cost calculator: https://7joko-hiaaa-aaaal-ajz7a-cai.icp0.io.
// Unused cycles are returned.
Cycles.add<system>(100_000_000_000);
// Execute the https outcall
let http_response : IC.http_request_result = await IC.http_request(http_request);
...
// Transforms the raw HTTPS call response to an HttpResponsePayload on which the nodes can run consensus on.
public query func transform({
context : Blob;
response : IC.http_request_result;
}) : async IC.http_request_result {
{
response with headers = []; // not intersted in the headers
};
};
};
The code above is annotated with detailed notes and explanations. Take a moment to read through the code's content and annotations to fully understand the code's functionality.
A few important points to note are:
All methods that include HTTPS outcalls must be update calls because they go through consensus, even if the HTTPS outcall is a
GET
.The code above adds
20_949_972_000
cycles. This is typically enough forGET
requests, but this may need to change depending on your use case.
The transform
function
The transform
function in the code above is important because it takes the raw content and transforms it into a raw HTTP payload. This step sets the payload's headers, which include the Content Security Policy and Strict Transport Security headers.
When developing locally, this function doesn't have much of an effect since only the local replica (one node) is making the call.
When HTTPS calls are used on the mainnet, a common error message may appear that indicates not all replicas on the subnet get the same response:
Reject text: Canister http responses were different across replicas, and no consensus was reached
This error occurs when the replicas on the subnet don't all return the same value for a piece of data within the HTTPS response. For example, if you have an application that sends an HTTPS request to the Coinbase API for the current price of a token, due to latency the replicas will not all return the same response. To remedy this, you can request the token price for a specific timestamp to assure that the replicas all return the same response.
Calling the HTTP GET
request
Click 'Deploy" within the ICP Ninja code editor to deploy the project, then open the project's frontend URL and click "Get data from the Internet" to call the backend canister's HTTPS outcall method fetchAndStoreOnThisDay
.
HTTP POST
To demonstrate how to use the HTTP POST
outcall, you'll create a simple canister that has one public method named send_http_post_request()
. This method will trigger an HTTP POST
request to a public API service where the HTTP request can be inspected, and you can inspect the request's headers and body to validate that it reflects what the canister sent.
The following are some important notes on POST
requests:
Since HTTPS outcalls go through consensus, it is expected that any HTTP
POST
request may be sent several times to its destination. This is because it is common for clients to retry requests for a variety of reasons.It is recommended that HTTP
POST
requests add the idempotency keys in the header of the request so that the destination knows whichPOST
requests from the client are identical.Developers should be cautious using idempotency keys since the destination server may not know how to understand and use them.
To learn more about HTTPS POST
requests, view the GitHub HTTPS POST
example.

Did you get stuck somewhere in this tutorial, or do you feel like you need additional help understanding some of the concepts? The ICP community has several resources available for developers, like working groups and bootcamps, along with our Discord community, forum, and events such as hackathons. Here are a few to check out:
- Developer Discord
- Developer Liftoff forum discussion
- Developer tooling working group
- Motoko Bootcamp - The DAO Adventure
- Motoko Bootcamp - Discord community
- Motoko developer working group
- Upcoming events and conferences
- Upcoming hackathons
- Weekly developer office hours to ask questions, get clarification, and chat with other developers live via voice chat.
- Submit your feedback to the ICP Developer feedback board