Gift Card Hero REST API¶
The REST API lets you manage gift cards programmatically from external systems — CRMs, analytics dashboards, loyalty platforms, fulfillment services, and more.

Base URL¶
All API requests use the following base URL:
https://gifthero.syncu.be/api/external
Authentication¶
Every request must include a Bearer token in the Authorization header:
Authorization: Bearer YOUR_API_TOKEN
To obtain your API token, go to For developers in the left navigation, tick Enable REST API and save. Click Send me access token — the token is sent to the shop contact email address shown on the page.
The token does not expire until you replace or revoke it. Keep it like a password: store it in your integration's secret settings, and do not paste it into chats, tickets or shared documents.
Managing your API token¶
One token at a time. Your store has a single API token. Every system that calls the API — a POS, a CRM, a partner's service — uses that same token.
Sending a new token replaces the old one. Each click on Send me access token issues a new token, and the previous one stops working immediately. Update every integration with the new token right away. If you only need to look the token up again, find the earlier email instead of sending a new token.
Revoking a token. If a token may have leaked, or a partner who had it no longer works with you, click Revoke access token on the For developers page and confirm. The token stops working at once, and no new token is issued. When you are ready, click Send me access token to issue a new one.
Turning the REST API off. Switching Enable REST API off and saving also revokes the token. After you turn the API back on, send yourself a new token.
What your integration sees. A request with a replaced or revoked token is answered with 401:
{
"error": {
"statusCode": 401,
"name": "UnauthorizedError",
"message": "Error verifying token : The token has been revoked or replaced."
}
}
The fix is always the same: put the current token in the Authorization header.
Tokens issued before token ids were introduced keep working until the first time you send a new token or revoke the token.
Other authentication errors:
| Status | Meaning |
|---|---|
401 |
The Authorization header is missing or is not of type Bearer, or the token is not valid |
402 |
The store has no active Gift Card Hero plan |
Endpoints¶
List gift cards¶
GET /gift-cards
Parameters:
| Parameter | Type | Description |
|---|---|---|
status |
string | Filter by gift card status |
limit |
integer | Maximum number of results (max 250) |
since_id |
string | Return results after this gift card ID |
fields |
string | Comma-separated list of fields to include |
The request is passed to Shopify's gift card list, so Shopify's own parameters for it apply. Every card in the response carries a recipient object (id, email, name) or null. A code field is included when Gift Card Hero has the full code on record (see Important notes).
A HEAD /gift-cards request returns 200 with no body. Some HTTP clients use it as a preflight check.
List gift cards with transactions¶
GET /gift-cards/transactions
Returns gift cards, newest first, each with up to its 50 most recent transactions. Supports cursor-based pagination.
Pagination:
| Parameter | Type | Description |
|---|---|---|
limit |
integer | Gift cards per page (default 50) |
page_info |
string | Cursor for the next page of results |
Filters:
| Filter | Type | Description |
|---|---|---|
query |
string | Search query, in Shopify's gift card search syntax |
balance_status |
string | One of: full, partial, empty, full_or_partial |
created_at |
string | Filter by creation date |
expires_on |
string | Filter by expiration date |
source |
string | One of: manual, purchased, api_client |
status |
string | One of: disabled, enabled, expired, expiring |
initial_value |
string | Filter by initial value |
id |
string | Filter by gift card ID |
All filters use AND logic when combined.
Response:
Each gift card has id, balance, currency, initial_value, created_at, updated_at, disabled_at, customer_id, recipient, note, expires_on, template_suffix, last_characters, order_id, transactions and issued_by. The response does not include the gift card code. Each transaction has id, amount (negative for a debit), processed_at, note, pos_user and pos_order_name.
Transaction ids:
transactions[].id is the numeric Shopify id of the gift card transaction — the number at the end of its gid://shopify/GiftCardDebitTransaction/… or gid://shopify/GiftCardCreditTransaction/… GID. Earlier versions of the API returned null here.
POS fields:
Gift cards issued or redeemed through the Gift Card Hero POS carry the cashier who did it. These fields are added to the standard response:
| Field | Type | Description |
|---|---|---|
transactions[].pos_user |
object or null | { "username": "woodgrove", "name": "Woodgrove" } for a debit made at the POS; null otherwise |
transactions[].pos_order_name |
string or null | Order name entered at the POS for that debit, if any; null otherwise |
issued_by |
object or null | { "username", "name", "issued_at" } for a card issued at the POS; null otherwise |
The POS activity log does not store Shopify transaction ids, so a debit is matched to a POS redemption by card, amount and time (the redemption must be logged within a few seconds before to one minute after the transaction). Online payments, changes made in the Shopify admin and debits with no matching POS record get null. name is null if the POS user has since been deleted.
Get a single gift card¶
GET /gift-cards/{gift_card_id}
Returns the details of a single gift card by its ID, with its recipient and, when Gift Card Hero has it, its code.
Create a gift card¶
POST /gift-cards
Request body:
{
"note": "Loyalty reward",
"initial_value": "50.00",
"code": "ABCD-EFGH-IJKL-MNOP",
"template_suffix": "custom"
}
| Field | Type | Required | Description |
|---|---|---|---|
note |
string | No | Internal note for the gift card |
initial_value |
string | Yes | Starting balance |
code |
string | No | Custom gift card code (must be unique; auto-generated if omitted) |
template_suffix |
string | No | Shopify template suffix |
customer_id |
integer | No | Shopify customer who owns the card |
email |
string | No | Customer email, used when customer_id is not sent. Gift Card Hero finds the customer, or creates one tagged gifthero:import |
The body is passed to Shopify's gift card endpoint, which accepts further fields such as expires_on. The response is Shopify's gift card, including the full code.
Important: Store the full code from the creation response if you need it. Later responses include the full
codeonly for cards where Gift Card Hero has it on record; otherwise only the last 4 characters (last_characters) are returned.
Update gift card balance¶
PUT /gift-cards/{gift_card_id}/balance
Request body:
{
"balance": "100.00"
}
Sets the gift card's balance to the specified value. A value with a leading sign, such as "+25.00" or "-10.00", is applied as an adjustment to the current balance instead. If the balance does not change, the current balance is returned and nothing is recorded. When the store has Increase limit on, a top-up can go above the standard Shopify gift card limit.
This is a balance correction: it sends no notification to the customer and records no branch. When a customer spends the card at a till, use Redeem a gift card instead.
Redeem a gift card¶
POST /gift-cards/{gift_card_id}/redeem
Debits (redeems) a gift card from a third-party POS or till app, outside Shopify checkout. The card holder receives your store's redemption notification (email or SMS) with the branch name — or the purchaser instead, or both, if Who gets notified in your Redemption notifications settings says so — and the redemption appears with its branch in Gift Card Hero reports. Use this method instead of calling Shopify's giftCardDebit directly — a direct debit sends no branch and no notification.
Redeem vs. update balance: use Update gift card balance to set the balance to a value without notifying anyone. Use Redeem when a customer spends the card and you want the notification and the branch recorded.
Request body:
{
"amount": "1500.00",
"branch": "Westgate",
"reference": "pos-app:7f3c2b9e-0d1a-4c55-9b7e-2f8a6c1d3e4f",
"note": "Table 12"
}
| Field | Type | Required | Description |
|---|---|---|---|
amount |
string | Yes | Amount to redeem. Must be greater than 0 and not more than the card balance, in the card's currency, with up to 2 decimals |
branch |
string | Yes | Branch or location name. Shown in the redemption email and SMS (when Include the store location is on in Redemption notifications) and in reports |
reference |
string | Yes | Your unique ID for this redemption, up to 255 characters. See Retries and duplicates |
note |
string | No | Written to the gift card transaction in Shopify. Gift Card Hero appends [ref:<reference>] to the note, so you can match every API redemption to its reference in the Shopify admin |
Response (200):
{
"id": 661944893757,
"last_characters": "7nsf",
"amount": "1500.00",
"currency": "KES",
"balance_before": "5090.00",
"balance": "3590.00",
"branch": "Westgate",
"reference": "pos-app:7f3c2b9e-0d1a-4c55-9b7e-2f8a6c1d3e4f",
"processed_at": "2026-10-12T10:30:00Z",
"notification": "queued",
"duplicate": false
}
| Field | Description |
|---|---|
notification |
queued — the redemption notification was handed to your store's Redemption notifications settings, which decide whether to send it (every redemption, or only when the card is used up). disabled — redemption notifications are turned off for your store |
duplicate |
true when this reference was already processed and the response is the original result |
Errors:
Errors use the usual format: {"error": {"statusCode": 422, "name": "...", "message": "..."}}.
| Status | Meaning | What to do |
|---|---|---|
400 |
amount, branch or reference is missing or invalid |
Fix the request body |
401 |
The token is missing, invalid, revoked or replaced by a newer one | Check the Authorization header. If the token was revoked or replaced, request a new one |
403 |
The app is missing an access scope on your store | The store owner must approve the app's updated permissions in the Shopify admin |
404 |
Gift card not found | Check the gift card ID |
409 |
The reference was already used for another card or amount, or a request with this reference is still being processed |
For a new redemption, use a new reference. If a request is still processing, wait a few seconds and retry with the same reference |
422 |
The card is disabled or expired, or the amount is above the balance. The message says which. The balance is unchanged |
Fix the cause. The reference is not used up, so retry with the same one |
429 |
Shopify is rate limiting your store | Back off and retry with the same reference |
500 |
The outcome could not be confirmed with Shopify | Retry with the same reference: the card is not charged twice |
A failed request (404 or 422) does not use up the reference.
Retries and duplicates¶
Generate one reference per redemption and reuse it only when you retry that same redemption. If a request times out or fails on the network, retry with the same reference. This is always safe: the card is never debited twice, and you get the original result back with "duplicate": true.
Update a gift card¶
PUT /gift-cards/{gift_card_id}
Only the following fields can be updated:
| Field | Type | Description |
|---|---|---|
expires_on |
string | Expiration date |
note |
string | Internal note |
template_suffix |
string | Shopify template suffix |
customer_id |
integer | Shopify customer who owns the card. You can send email instead, as when creating a card |
The response includes the code when Gift Card Hero has it on record.
Disable a gift card¶
POST /gift-cards/{gift_card_id}/disable
Permanently disables the gift card. This action cannot be undone. Returns the disabled gift card.
Search gift cards¶
GET /gift-cards/search
Parameters:
| Parameter | Type | Description |
|---|---|---|
order |
string | Sort order |
query |
string | Search query, for example last_characters:mnop. Use recipient:name@example.com to find cards sent to a recipient |
limit |
integer | Maximum number of results |
fields |
string | Comma-separated list of fields to include |
Indexed fields (available for search queries):
created_at, updated_at, disabled_at, balance, initial_value, amount_spent, last_characters
Assign gift card codes to an order¶
POST /gift-cards/assign-to-order
Assigns your own gift card codes to a Shopify order, for stores that generate codes outside the app. It works only when Skip gift codes generation is on in Regular products as gift cards settings; otherwise it returns 400. It also returns 400 if orderId is not numeric or if a code already exists in your store, and 404 if the order is not found.
Supports both single and multiple code assignment.
Single code:
{
"orderId": "1234567890",
"giftCode": "ABCD-EFGH-IJKL-MNOP"
}
Multiple codes:
{
"orderId": "1234567890",
"giftCodes": [
{ "lineItemId": "111", "code": "ABCD-EFGH-IJKL-MNOP" },
{ "lineItemId": "222", "code": "QRST-UVWX-YZ12-3456" }
]
}
Response:
{
"scheduled": true
}
scheduled is false when the order has no gift cards to process.
Pagination¶
The transactions endpoint uses cursor-based pagination. The response includes a Link header with the cursor for the next page:
Link: <https://gifthero.syncu.be/api/external/gift-cards/transactions?page_info=CURSOR>; rel="next"
The header is absent on the last page. Parse the page_info value from the Link header and pass it as a query parameter in your next request, with the same filters. The next-page URL already contains them.
Important notes¶
- Code uniqueness — when creating gift cards with custom codes, each code must be unique. The API returns an error if a duplicate code is submitted.
- Code visibility — the creation response includes the full code. In later responses a
codefield appears only for cards where Gift Card Hero has the full code on record (cards it generated, and codes you assigned). Otherwise only the last 4 characters (last_characters) are returned. The transactions endpoint never returns codes. - Redemption retries — always send a unique
referencewhen redeeming a gift card, and retry with the samereferenceafter a timeout. See Retries and duplicates. - Rate limits — requests are passed on to Shopify, so Shopify's limits for your store apply. If you receive a
429response, back off and retry. - Postman collection — covers the gift card endpoints except
/gift-cards/transactionsand/gift-cards/assign-to-order.
Postman collection¶
Download the Postman collection for quick API exploration: