Gift Cards API
Issue and manage your store's gift cards. A gift card is store credit a
buyer spends at checkout. Cards are either bought, as a product whose
delivery is gift_card (see Products), or
issued by you, such as to make up for a late parcel.
Endpoints
- List Gift Cards -
GET /api/v1/gift-cards/ - Issue Gift Card -
POST /api/v1/gift-cards/ - Get Gift Card -
GET /api/v1/gift-cards/{gift_card_id}/ - Update Gift Card -
PUT /api/v1/gift-cards/{gift_card_id}/ - Adjust Balance -
POST /api/v1/gift-cards/{gift_card_id}/adjustments/ - Disable Gift Card -
POST /api/v1/gift-cards/{gift_card_id}/disable/ - Enable Gift Card -
POST /api/v1/gift-cards/{gift_card_id}/enable/ - List Transactions -
GET /api/v1/gift-cards/{gift_card_id}/transactions/
How Gift Cards Work
- Codes are secret. A code is 28 characters from Crockford's base32
alphabet, shown in groups of four (7K2M-…-QX4P), and holds 140 random
bits. Easel keeps only its SHA-256 hash, so a code is returned exactly once:
in the response that issues the card, or in the email to its recipient.
last4tells cards apart. - Currency. A card's balance is in the store's currency when it was
issued, and it only pays at checkouts in that currency. - Checkout. A buyer enters a code at checkout. Checkout holds as much of
the balance as the order costs, for as long as its payment can be made, so
two checkouts can't spend the same balance. The buyer's card is charged
only the rest. A card that pays the whole order needs no card payment at
all. Paying turns the hold into aredeemedtransaction in the same
database transaction that records the order. - Gift cards bought. Each unit of a
gift_cardproduct creates a card
worth the price paid for it once the order is paid. It is emailed to the
recipient the buyer named in the cart, with their message, or to the buyer.
Discount codes don't apply to gift cards, and they have no stock. - Tax. A gift card is a way to pay, not a discount. Tax is quoted on
the whole order, and the card pays as much of the total, tax included, as
its balance allows. Buying a gift card isn't taxed: tax is due on what the
card buys when it's spent, so gift card lines are left out of the
order'staxes. - Refunds. A refund of an order goes back to the buyer's card first, up
to what was charged to it, and the rest back onto the gift card that paid
for the order. See Refunds.
A refund'staxis its share of the order's tax whichever way the money
goes back. - Expiry. Cards never expire unless you set
expires_at. Many places
limit or forbid gift cards that expire.
List Gift Cards
Retrieve the store's gift cards, newest first.
Endpoint: GET /api/v1/gift-cards/
Permission Required: Read
Query Parameters
| Parameter | Type | Description |
|---|---|---|
status |
string | Only cards with this status: active, used, expired, or disabled |
after |
string | Cursor for pagination. Gift card ID to return cards after |
limit |
integer | Number of cards to return (default 10, max 100) |
The response reports has_more, which is true when another page follows.
An unknown status, a malformed after, or an invalid limit returns
INVALID_REQUEST_ERROR.
Request
curl -X GET "https://studio.easel.engineering/api/v1/gift-cards/?status=active&limit=20" \
-H "Authorization: Bearer your_api_key_here"
Response
Status: 200 OK
{
"data": [
{
"id": "gcd_d0b6fmv28q6vn14peun0",
"last4": "QX4P",
"currency": "USD",
"initial_value": 5000,
"balance": 3500,
"status": "active",
"recipient_email": "friend@example.com",
"message": "Happy birthday!",
"note": null,
"expires_at": null,
"disabled_at": null,
"created_at": "2026-10-19T10:00:00Z",
"updated_at": "2026-10-19T12:00:00Z"
}
],
"has_more": false
}
Issue Gift Card
Issue a gift card in the store's currency. The response is the only time
the code is returned.
Endpoint: POST /api/v1/gift-cards/
Permission Required: Write
Request Body
{
"value": 2500,
"recipient_email": "friend@example.com",
"message": "Sorry your parcel was late.",
"note": "Order #1042 arrived a week late"
}
| Field | Type | Required | Description |
|---|---|---|---|
value |
integer | Yes | Value in the store's smallest currency unit, from 1 to 10000000 |
site_id |
string | No | Site whose name and address the card's email carries; defaults to the store's first site |
recipient_email |
string | No | When set, the code is emailed to this address |
message |
string | No | Message to the recipient, up to 500 characters; only kept with a recipient_email |
note |
string | No | Your own note, never shown to the buyer, up to 500 characters |
expires_at |
string | No | RFC 3339 time the card stops working; must be in the future |
Request
curl -X POST "https://studio.easel.engineering/api/v1/gift-cards/" \
-H "Authorization: Bearer your_api_key_here" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: unique-request-id-12345" \
-d '{"value": 2500, "recipient_email": "friend@example.com"}'
Response
Status: 201 Created
The gift card object with its code:
{
"id": "gcd_d0b6fmv28q6vn14peun0",
"last4": "QX4P",
"currency": "USD",
"initial_value": 2500,
"balance": 2500,
"status": "active",
"recipient_email": "friend@example.com",
"message": null,
"note": null,
"expires_at": null,
"disabled_at": null,
"created_at": "2026-10-19T10:00:00Z",
"updated_at": "2026-10-19T10:00:00Z",
"code": "7K2M-A9QD-0FZT-3HWB-P6NR-K1XV-QX4P"
}
Error Responses
Invalid value, email, expiry, or text
Status: 400 Bad Request
{
"error": "value must be between 1 and 10000000",
"code": "INVALID_FIELD"
}
Get Gift Card
Endpoint: GET /api/v1/gift-cards/{gift_card_id}/
Permission Required: Read
curl -X GET "https://studio.easel.engineering/api/v1/gift-cards/gcd_d0b6fmv28q6vn14peun0/" \
-H "Authorization: Bearer your_api_key_here"
Status: 200 OK with the gift card object, or
404 Not Found.
Update Gift Card
Replace a card's expiry and note. A null or absent value clears it.
Endpoint: PUT /api/v1/gift-cards/{gift_card_id}/
Permission Required: Write
{
"expires_at": "2027-12-31T23:59:59Z",
"note": "Goodwill credit"
}
| Field | Type | Required | Description |
|---|---|---|---|
expires_at |
string|null | No | RFC 3339 time the card stops working; a new expiry must be in the future |
note |
string|null | No | Your own note, up to 500 characters |
Status: 200 OK with the updated gift card object.
Adjust Balance
Raise a card's balance by a positive amount or lower it by a negative one.
The change is added to the card's history with your note.
Endpoint: POST /api/v1/gift-cards/{gift_card_id}/adjustments/
Permission Required: Write
{
"amount": -500,
"note": "Spent in the shop"
}
| Field | Type | Required | Description |
|---|---|---|---|
amount |
integer | Yes | Change in the store's smallest currency unit; not zero |
note |
string | No | Why, up to 500 characters |
Status: 200 OK with the updated gift card object.
The balance can't go below zero, below what open checkouts hold of it, or
above 10000000; such a change returns 400 Bad Request with
INVALID_FIELD.
Disable and Enable
A disabled card can't be applied at checkout until you enable it again. Its
balance is kept. A checkout that already holds part of the card may still
spend that part, since its buyer may already have paid the rest. Disabling
a disabled card, or enabling an enabled one, changes nothing.
Endpoints:
POST /api/v1/gift-cards/{gift_card_id}/disable/ and
POST /api/v1/gift-cards/{gift_card_id}/enable/
Permission Required: Write
Status: 200 OK with the updated gift card object.
List Transactions
A card's history, newest first. Entries are only ever added: every change to
the balance or status has one.
Endpoint: GET /api/v1/gift-cards/{gift_card_id}/transactions/
Permission Required: Read
| Parameter | Type | Description |
|---|---|---|
after |
string | Cursor. Transaction ID to return older entries after |
limit |
integer | Number of entries to return (default 10, max 100) |
{
"data": [
{
"id": "gct_d0b6fmv28q6vn14peun1",
"type": "redeemed",
"amount": -1500,
"balance": 3500,
"order_id": "ord_d0b6fmv28q6vn14peun0",
"note": null,
"actor": {"type": "customer", "name": null},
"created_at": "2026-10-19T12:00:00Z"
},
{
"id": "gct_d0b6fmv28q6vn14peun0",
"type": "issued",
"amount": 5000,
"balance": 5000,
"order_id": "ord_d0b6fmv28q6vn14peuaa",
"note": null,
"actor": {"type": "system", "name": null},
"created_at": "2026-10-19T10:00:00Z"
}
],
"has_more": false
}
Transaction Types
issued- The card was made with its initial balanceredeemed- Balance spent on an order (negativeamount)refunded- Balance put back by a refund of an orderadjusted- You raised or lowered the balancedisabled,enabled- You disabled or enabled the card (amountis0)
The actor is who made the change, as in an
order's history.
Gift Card Object
| Field | Type | Description |
|---|---|---|
id |
string | Gift card public ID |
last4 |
string | Last four characters of the code |
currency |
string | ISO 4217 currency of the balance |
initial_value |
integer | Value when issued |
balance |
integer | What's left to spend |
status |
string | active, used (no balance left), expired, or disabled, judged when read |
recipient_email |
string|null | Who the card was emailed to |
message |
string|null | The buyer's message to the recipient |
note |
string|null | Your note |
expires_at |
string|null | When the card stops working, or null for never |
disabled_at |
string|null | When the card was disabled |
created_at |
string | ISO 8601 timestamp |
updated_at |
string | ISO 8601 timestamp |