Api - Liquid Tag Reference
On this page
The api block tag makes an outbound HTTP request (an “API callout”) from a Liquid template. It runs server-side during the render, so you can integrate with external services — payment providers, shipping rate calculators, auth servers, any REST endpoint — without writing Apex, and without exposing credentials to the browser.
The result of the request is available inside the block as the response object.
Syntax
```liquid
{% api url: ‘
| Property | Value |
|---|---|
| Tag Name | api |
| Type | Block tag |
| Source | StoreConnect |
Parameters
| Parameter | Type | Description |
|---|---|---|
url |
String | The endpoint to call. Required. |
method |
String | The HTTP method: 'GET', 'POST', 'PUT', 'PATCH', or 'DELETE'. |
headers |
Map | Request headers. Build with a new Map — either from a JSON string or with the set_key filter (e.g. to add an Authorization header). |
data |
Map | The request body, sent as JSON. Use for POST/PUT/PATCH. |
bearer |
String | Bearer token; sent as an Authorization: Bearer header. |
username |
String | HTTP basic-auth username (pair with password). |
password |
String | HTTP basic-auth password. |
async |
Boolean | Set false to make a blocking request so the response is available inside the block. With true the request is dispatched fire-and-forget and no response is returned. |
Description
When async: false, the body of the block runs after the request completes and the response object exposes response.status, response.body (parsed automatically when the endpoint returns JSON), and response.headers. Always check response.status for success before reading response.body.
Examples
GET request
```liquid
{% liquid new Map headers = ‘{ “Accept”: “application/json” }’ assign forecast = ‘’ api url: ‘https://api.example.com/v1/forecast?city=denver’, method: ‘GET’, headers: headers, async: false if response.status >= 200 and response.status < 300 assign forecast = response.body.summary endif endapi %} {{ forecast }} ```
POST request with a JSON body
Build the request body as a Map with the set_key filter; StoreConnect serializes it to JSON:
```liquid
{% liquid new Map headers = ‘{ “Content-Type”: “application/json”, “Accept”: “application/json” }’
new Map body assign body = body | set_key: ‘name’, ‘Ada Lovelace’ assign body = body | set_key: ‘email’, ‘ada@example.com’
api url: ‘https://api.example.com/v1/contacts’, method: ‘POST’, headers: headers, data: body, async: false if response.status >= 200 and response.status < 300 assign new_id = response.body.id else debug status: response.status, error: response.body endif endapi %} ```
Authenticated request
Pass a bearer token with the bearer parameter — the tag adds the Authorization: Bearer header for you:
```liquid
{% api url: ‘https://api.example.com/v1/account’, method: ‘GET’, bearer: access_token, async: false %} {% assign account = response.body %} {% endapi %} ```
Additional recommendations
- Cache expensive or rate-limited calls. Wrap the block in a
cachetag so the storefront does not call the external service on every render — for example, cache an auth token for less than its stated lifetime and reuse it across requests. - Keep secrets server-side. Because the callout runs during the render, API keys and secrets never reach the browser. Store them in store or theme variables rather than hardcoding them in the template.
- Guard on
status. Treat only2xxas success; logresponse.bodyon failure while developing with thedebugtag.
Was this article helpful?
Thanks for your feedback! It helps us improve our docs.