Op deze paginaWebhooks

Webhooks.

Markdown

Welcome to the Gifty webhooks documentation. This documentation covers all information relevant to our event-driven webhooks.

If you have any questions, don't hesitate to reach out. You can contact us via our contact page.

Introduction

The following section describes generic usage information about webhooks.

Getting started

To start receiving webhooks from us, you'll need to register a webhook on the developer's page in your dashboard

When setting up your new webhook, you'll be asked to fill in several fields. These are explained below:

AttributeDescription
NameUsed to help you identify different webhooks. This field is only visible to you.
URLThis is the endpoint that we forward the events to. This must use HTTPS and accept POST requests.
EventsThe events you want to subscribe to.
SecretA private key used to verify webhook authenticity. For details on using this security feature, see "Verifying the authenticity".
ActiveSpecifies whether the webhook is active. When paused, it will not send or store events.

Example flow

In this flow, we'll show you how to verify the authenticity of a webhook request. After following these steps correctly, you can be sure that the request is authentic and originates from Gifty.

  • We send a webhook to your endpoint
  • You receive the webhook request
  • Verify the authenticity of the request (HMAC and timestamp)
  • Process the request

Verifying the authenticity

Every webhook includes the X-Gifty-Webhook-Signature header. This header contains a hash of the payload (body) using HMAC-SHA256, with the secret key you provided during the registration of the webhook. By hashing the payload of the request yourself using the same hashing algorithm and the secret key that only you and Gifty know, you can verify if the request is originating from Gifty.

Verifying the signature
const crypto = require("crypto");

const secret = "your_secret";
const payload = "payload_from_webhook";

const signature = crypto.createHmac("sha256", secret)
                      .update(payload)
                      .digest("hex");

Idempotence

Duplicate webhook deliveries can never be completely ruled out, as they may also occur outside our network, for example, due to retries by intermediaries or client-side issues. Because of this, you should never assume that a webhook will be delivered only once. Always design and build your integration to handle potential duplicates safely and idempotently.

You can verify whether a webhook has already been processed by tracking the X-Gifty-Webhook-Job-Id header. This identifier is unique to each individual event and remains the same if the same webhook is resent, such as during a retry. By keeping a record of processed job IDs, you can detect and safely ignore duplicates.

Headers

Every webhook we send comes with a set of headers, that are described as follows:

HeaderDescription
X-Gifty-Webhook-Job-IdThe unique identifier of this specific webhook request.
X-Gifty-Webhook-IdThe unique identifier of the webhook.
X-Gifty-Webhook-SignatureThe signature used to validate the authenticity of the request.
X-Gifty-Webhook-EventThe event that caused the webhook to be sent.
X-Gifty-Webhook-VersionThe version of our webhooks processor used to send the request.

Status codes

When your server responds to a webhook request, the HTTP status code you return determines how our system interprets the outcome. Please ensure that your endpoints return the appropriate status code based on the result of your processing logic.

CodeMeaning
2XXSuccessful request.
3XX*Redirections will not be followed, please change the endpoint URL if it changed.
4XX*The request cannot be processed due to client-side errors.
429*The endpoint is receiving too many requests.
5XX*The endpoint is unable to process the request at this time.

* We will attempt to deliver this webhook again later using an exponential back-off strategy.

If a Retry-After header is provided, we will use this instead. The maximum value for this header is 86,400 seconds (24 hours) and anything above that will be rounded down to this maximum.

Events

Event giftcard.issue

A gift card has been issued. Uses TransactionObject from the as a base.

Payload
JSON
{
    "id": "whj_XeLNZ7E9vQM0L8pvOw4BpoY3",
    "object": "event",
    "type": "giftcard.issue",
    "created_at": "2025-04-10T14:24:53+00:00",
    "data": {
        ...TransactionObject,
        "type": "issue",
        "object": "transaction"
    }
}

Event giftcard.redeem

A gift card has been (partially) redeemed. Uses TransactionObject from the as a base.

Payload
JSON
{
    "id": "whj_VmLwJwo19xKjSAkVpyooDJvl",
    "object": "event",
    "type": "giftcard.redeem",
    "created_at": "2025-04-10T14:25:52+00:00",
    "data": {
        ...TransactionObject,
        "type": "redeem",
        "object": "transaction"
    }
}

Event giftcard.expired

The expiry date of a gift card has passed. Uses TransactionObject from the as a base.

Payload
JSON
{
    "id": "whj_9dpEQ8BzkpQ7FPqz9jYMp5nE",
    "object": "event",
    "type": "giftcard.expired",
    "created_at": "2025-04-10T14:25:52+00:00",
    "data": {
        ...TransactionObject,
        "type": "expire",
        "object": "transaction"
    }
}

Event giftcard.extended

The expiry date of a gift card has been extended. Uses TransactionObject from the as a base.

Payload
JSON
{
    "id": "whj_VmLwJwo19xKjSAkVpyooDJvl",
    "object": "event",
    "type": "giftcard.extended",
    "created_at": "2025-04-10T14:25:52+00:00",
    "data": {
        ...TransactionObject,
        "type": "reverse_expire",
        "object": "transaction"
    }
}

Event giftcard.topped_up

A gift card has been topped up. Uses TransactionObject from the as a base.

Payload
JSON
{
    "id": "whj_VmLwJwo19xKjSAkVpyooDJvl",
    "object": "event",
    "type": "giftcard.topped_up",
    "created_at": "2025-04-10T14:25:52+00:00",
    "data": {
        ...TransactionObject,
        "type": "top_up",
        "object": "transaction"
    }
}

Event transaction.captured

A transaction has been captured.

Payload
JSON
{
    "id": "whj_GmW4O4axk7K3TQblDJ11N1d0",
    "object": "event",
    "type": "transaction.captured",
    "created_at": "2025-04-10T14:25:52+00:00",
    "data": {
        ...TransactionObject,
        "type": "redeem",
        "object": "transaction"
    }
}

Event transaction.released

A transaction has been released.

Payload
JSON
{
    "id": "whj_EmA076Zkd4z3TQElDJ11k0Ak",
    "object": "event",
    "type": "transaction.released",
    "created_at": "2025-04-10T14:25:52+00:00",
    "data": {
        ...TransactionObject,
        "type": "redeem",
        "object": "transaction"
    }
}

Event transaction.created

A transaction has been created.

Payload
JSON
{
    "id": "whj_9d4o7ZqkDWM7C4NaYW3gLWmA",
    "object": "event",
    "type": "transaction.created",
    "created_at": "2025-04-10T14:25:52+00:00",
    "data": {
        ...TransactionObject,
        "type": "expire",
        "object": "transaction"
    }
}

Event location.created

A new establishment has been added to the account.

Payload
JSON
{
    "id": "whj_lvqMRMONllO7T0pOB3PxEavN",
    "object": "event",
    "type": "location.created",
    "created_at": "2025-04-10T14:24:28+00:00",
    "data": {
        "id": "lc_NaxRrj0MXmGPRLdp5eok8bKZ",
        "street": "Floridalaan",
        "house_number": "8",
        "addition": null,
        "postal_code": "3404WV",
        "city": "IJsselstein",
        "country_code": "NL",
        "geometry": {},
        "object": "location"
    }
}

Event location.updated

An establishment has been modified.

Payload
JSON
{
    "id": "whj_QmyxMxq3WNelIybjO7gB9yvP",
    "object": "event",
    "type": "location.updated",
    "created_at": "2025-04-10T14:24:32+00:00",
    "data": {
        "id": "lc_NaxRrj0MXmGPRLdp5eok8bKZ",
        "street": "Floridalaan",
        "house_number": "8",
        "addition": null,
        "postal_code": "3404WV",
        "city": "IJsselstein",
        "country_code": "NL",
        "geometry": {},
        "object": "location"
    }
}

Event location.deleted

An establishment has been removed from the account.

Payload
JSON
{
    "id": "whj_lvgRQRqJXPZru8V4A38ALrng",
    "object": "event",
    "type": "location.deleted",
    "created_at": "2025-04-10T14:24:35+00:00",
    "data": {
        "id": "lc_NaxRrj0MXmGPRLdp5eok8bKZ",
        "street": "Floridalaan",
        "house_number": "8",
        "addition": null,
        "postal_code": "3404WV",
        "city": "IJsselstein",
        "country_code": "NL",
        "geometry": {},
        "object": "location"
    }
}