A Wrapped webhook is a POST of a single JSON object to the HTTPS URL you registered. This article documents every field in that object. To create and list webhooks, see The Wrapped API; for the endpoints themselves, see the API reference.
Topics
Every delivery carries a webhookTopic. There is no filtering — a webhook receives all five.
| Topic | Sent when |
|---|---|
giftcard/updated | A gift card is issued, or its balance changes, and Wrapped sends its gift card notifications |
giftcard/gifted | A gift card is delivered to a recipient as a gift |
giftcard/reminder | A balance reminder is sent for a gift card |
giftcard/voided | A gift card is voided |
giftcard/expired | A gift card expires |
Adjustments added through the API don't send a giftcard/updated delivery.
Example payload
Property names are PascalCase, as shown. RequestId is new for every delivery — use it to discard duplicates.
{
"RequestId": "6f1e8b6a-2c9d-4f3a-9d41-0b7c2f5ae913",
"GiftCardId": "66f0a1b2c3d4e5f60718293a",
"Code": "WRAP-XY7Q-4KLM",
"CreatedAt": "2026-09-14T03:21:55.412Z",
"InitialValue": 50.0,
"FormattedInitialValue": "$50.00",
"Balance": 42.5,
"FormattedBalance": "$42.50",
"Currency": "AUD",
"TotalIssuedAmount": 50.0,
"FormattedTotalIssuedAmount": "$50.00",
"ExpiresAtUtc": "2027-09-14T00:00:00Z",
"RecipientName": "Alex Fraser",
"RecipientEmailAddress": "alex@example.com",
"BuyerName": "Sam Rivers",
"BuyerEmail": "sam@example.com",
"GiftCardMessage": "Happy birthday!",
"Status": "Active",
"IsPromotional": false,
"IsStoreCredit": false,
"AppleWalletUrl": "https://manage.wrappedgiftcards.com/applewallet/generate/<accountId>/<giftCardId>",
"GoogleWalletUrl": "https://manage.wrappedgiftcards.com/googlewallet/generate/<accountId>/<giftCardId>",
"PdfUrl": "https://manage.wrappedgiftcards.com/Giftcard/Pdf/<giftCardId>",
"ViewBalanceUrl": "https://manage.wrappedgiftcards.com/pc/check-balance/<accountId>?code=WRAP-XY7Q-4KLM",
"GiftToFriendUrl": "https://manage.wrappedgiftcards.com/public/gift-to-friend/<giftCardId>",
"GiftCardBatchId": null,
"AutomationId": null,
"CampaignId": null,
"ApiEventName": null,
"ApiEventProperties": null,
"WebhookTopic": "giftcard/updated"
}
Fields
| Field | Type | Notes |
|---|---|---|
RequestId | string | A new GUID per delivery. Not stable across retries of your own processing — it identifies the delivery, not the gift card. |
GiftCardId | string | Wrapped's ID for the card. Use this with GET /api/GiftCard/GetById/{id}. |
Code | string | The gift card code. |
CreatedAt | datetime | When the card was created. |
InitialValue / FormattedInitialValue | number / string | The value the card started with; formatted in the account's currency. |
Balance / FormattedBalance | number / string | The balance after whatever triggered this delivery. |
TotalIssuedAmount / FormattedTotalIssuedAmount | number / string | Everything ever loaded onto the card, including top-ups. |
Currency | string | The card's currency. |
ExpiresAtUtc | datetime, nullable | Null when the card doesn't expire. |
RecipientName, RecipientEmailAddress | string, nullable | Who the card is for. |
BuyerName, BuyerEmail | string | Who it's from. Falls back to the recipient when the card wasn't gifted. |
GiftCardMessage | string, nullable | The gift message. |
Status | string | The card's display status, for example Active, Redeemed, Voided, Expired. |
IsPromotional | bool | True for cards issued as promotional credit rather than sold. |
IsStoreCredit | bool | True when this is a store credit account rather than a gift card. |
AppleWalletUrl, GoogleWalletUrl | string | Wallet pass links for the recipient. |
PdfUrl | string | The printable gift card. |
ViewBalanceUrl | string | The public balance page for this card. |
GiftToFriendUrl | string, nullable | Null on store credit accounts, which can't be gifted on. |
GiftCardBatchId | string, nullable | Set when the card came from a batch. |
AutomationId | string, nullable | Set when an automation issued the card. |
CampaignId | string, nullable | Set when a campaign sent the card. |
ApiEventName, ApiEventProperties | string / object, nullable | The event that triggered the automation that issued this card, when it came from POST /api/AutomationTriggerEvents. ApiEventProperties is omitted entirely when empty. |
WebhookTopic | string | One of the five topics above. |
Verifying a delivery
If you set requestHeaderVerificationToken when creating the webhook, every delivery carries an HMAC-Signature-SHA256 header. Its value is the Base64-encoded HMAC-SHA256 of the raw request body, keyed with your token. The token itself is never sent.
Compute the signature over the bytes you received, before any JSON parsing or re-serialising — re-serialising changes whitespace and key order, and the signature won't match.
const crypto = require("crypto");
function isFromWrapped(rawBody, signatureHeader, token) {
const expected = crypto.createHmac("sha256", token).update(rawBody, "utf8").digest("base64");
const received = signatureHeader || "";
return expected.length === received.length &&
crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(received));
}
Without a token, deliveries are unsigned and anyone who learns your URL can post to it. Set one.
Delivery behaviour
- Each delivery is attempted once. A failure is never retried, so don't rely on Wrapped to redeliver — return
2xxquickly and do your work afterwards. - A webhook that has failed six times over its lifetime is disabled and stops appearing in
GET /api/Webhook/List. The count doesn't reset after a success, so those six failures can be spread over months. Create the webhook again once your endpoint is healthy. - Deliveries only go out while your Wrapped subscription is active.
Common questions
Can I subscribe to only one topic?
No. A webhook receives all five topics; filter on WebhookTopic at your end.
Why did I get two deliveries for the same change?
Each registered webhook receives its own delivery, so two webhooks on the same URL means two POSTs. Check GET /api/Webhook/List, and use RequestId to tell genuine duplicates apart.
My webhook stopped receiving anything. What happened?
Most likely it hit six lifetime failures and was disabled — it will no longer be in GET /api/Webhook/List. Fix your endpoint, then create the webhook again.
What does IsStoreCredit mean?
It marks the record as a balance account rather than a gift card. The payload is otherwise the same, except GiftToFriendUrl is null because those balances can't be gifted on.
