GoGift v2 Processor and API
This reference is for operations and customer-service teams. It describes the GoGift v2 basket and webhook lifecycle, the fields required before a sale can complete, and the evidence to collect before retrying or escalating.
What GoGift v2 does
GoGift v2 is an asynchronous basket processor with catalogue support and webhook delivery. The application creates a basket, adds one product, finalises the basket, and stores the resulting order ID. GoGift v2 then sends fulfilment data to the configured webhook; retrieval reads that locally stored response.
| Property | Behaviour |
|---|---|
| Processor type | SKU per denomination with a brand-level product ID |
| Processing | Asynchronous basket update and finalisation, followed by webhook-backed retrieval |
| Delivery | Digital gift-card URL with a PIN appended during mapping |
| Balance lookup | Unsupported |
| Cancellation | Unsupported |
| Catalogue | Supported through product list and product-by-ID operations |
| Provider completion evidence | A valid webhook payload containing orderId, giftcardUri, and pin |
Order lifecycle
- The sale supplies the brand, face value, currency, transaction reference, and delivery method.
- The interaction reads the brand
product_idattribute and the denomination SKU for the requested face value. - A basket is created with sales channel ID
109. The returnedidis required and is cached against the transaction reference for seven days. - The basket is updated with the B2B department, product ID, SKU, currency, integer gift-card value, transaction reference, and the application confirmation webhook URL. The update clears existing basket products and adds one product with delivery method
Webhook. - The basket is finalised with payment method
InvoiceByFinance. The returnedorderIdbecomes the processor reference. - GoGift v2 sends a signed webhook. The handler validates the request headers and signature, validates the first
contentitem, finds the sale by processor reference, stores the encrypted payload, writes a response audit record, and dispatches asynchronous code retrieval. - Retrieval validates the stored payload and maps its URL and PIN. After a successful sale response is produced, a cleanup job is delayed by 30 seconds before deleting the stored webhook response.
Example API order flow
The following examples use illustrative values. API keys, bearer tokens, webhook signatures, PINs, and live gift-card URLs are intentionally omitted.
Create, update, and finalise a basket
The API uses bearer authentication. Create sends POST baskets/:
{ "salesChannelId": 109 }
The response must contain a basket ID:
{ "id": "<basket-id>" }
Update sends PUT baskets/ with an idempotency key of <basket-id>-update:
{
"id": "<basket-id>",
"buyer": {
"accountId": "<b2b-department-id>",
"accountType": "B2BDepartment",
"name": "Tillo",
"email": "noreply@tillo.io",
"phone": "[REDACTED]",
"address": { "countryCode": "GB" }
},
"addProducts": {
"deliveryMethod": "Webhook",
"recipientName": "Tillo",
"recipientWebhookUrl": "https://<application-host>/webhook/<processor>/confirmation",
"stockKeepingUnit": "<denomination-sku>",
"productId": "<product-id>",
"quantity": 1,
"valueCurrency": "GBP",
"giftCardValue": 10,
"productReference": "<transaction-reference>"
},
"doClearProducts": true,
"reference": "<transaction-reference>"
}
Finalise sends POST baskets/finalize/ with idempotency key <basket-id>-finalize:
{
"basketId": "<basket-id>",
"paymentMethod": "InvoiceByFinance"
}
The finalisation response must contain the provider order ID:
{ "orderId": "<gogift-order-id>" }
Webhook and retrieval
The webhook request must contain Signature, X-Request-Datetime, X-Client-ID, and X-Request-ID. The signature header has a signature="..." value; the application verifies it using the request method, those headers, a SHA-256 body digest, and the configured webhook secret. A redacted body example is:
{
"content": [
{
"orderId": "<gogift-order-id>",
"giftcardUri": "https://<provider-host>/giftcard/<redacted>",
"pin": "[REDACTED]",
"expiresAt": "<provider-expiry-or-omitted>"
}
]
}
The handler returns HTTP 200 after validation and processing. Retrieval then maps the stored payload to:
{
"processor_reference": "<gogift-order-id>",
"url": "https://<provider-host>/giftcard/<redacted>/[REDACTED]",
"expiration_date": "<ISO-8601-or-null>"
}
The URL above is illustrative only. Do not place a real provider URL or PIN in an incident record.
Response mapping and validation
| Provider response or record | Application result |
|---|---|
Create basket id | Cached as go-gift-v2-basket-id-<transaction-reference>; missing id prevents issuance |
Finalise response orderId | Returned as processor_reference; missing orderId prevents issuance |
Webhook content.0.orderId | Used to locate the sale and returned as processor_reference; required |
Webhook content.0.giftcardUri | Must be a URL; concatenated with / and content.0.pin to form the returned url |
Webhook content.0.pin | Required and appended to the provider URI; never copy it into support notes |
Webhook content.0.expiresAt | Optional; when present it is converted to an ISO-8601 expiration_date |
| Webhook payload | Stored against sale_uuid in go_gift_v2_webhook_responses and encrypted by the model cast |
Only the first item, content.0, is validated and mapped. Update-basket response content is not parsed for completion; finalisation and the later webhook provide the required evidence. A missing or invalid webhook field raises webhook handling or response validation failure rather than producing a partial voucher response.
Provider states and retry behaviour
| Condition | Integration behaviour | Operational consequence |
|---|---|---|
Network failure, HTTP 429, or unexpected server-side failure during create, update, or finalise | Raises RetryableRequestException | Retry the same operation only after checking the existing basket and audit trail |
| Other HTTP client failures, such as authentication, malformed request, not found, or resource conflict | Raises ProcessorInteractionException | Correct configuration or data, or escalate; do not blindly repeat the sale |
Create response missing id | Response validation failure | No basket ID is available to continue; inspect the raw response |
Finalise response missing orderId | Response validation failure | The basket outcome is uncertain; check the basket and provider audit before any new order |
| Valid webhook for a processing sale | Stores or updates the response, audits it, and dispatches AsyncFetchCode | Retrieval can process the voucher payload |
Webhook for SUCCESS, ERROR, or CANCELLED sale | Returns HTTP 200 without storing a new payload | A duplicate or late callback is acknowledged and ignored |
| No stored webhook response during retrieval | Raises WebhookResponseNotFoundException | Treat fulfilment as unresolved; there is no API status fallback in this interaction |
The basket ID cache lasts 604800 seconds (one week). Update and finalise use idempotency keys derived from that basket ID, so a retry with the same cached basket can be correlated to the original provider actions. A manual re-order or a retry after the cache has expired can create a new basket and duplicate fulfilment; resolve the original basket and order first.
Audit comparison fields
Compare the following values across application and provider records:
- Internal sale UUID and transaction reference against
productReference,reference, and the cache key used for the basket. - Brand
product_id, denomination SKU, currency, integer gift-card value, and basket ID against the update payload. - Update and finalise idempotency keys against the basket ID and operation (
<basket-id>-updateand<basket-id>-finalize). - Finalise
orderIdagainst the stored processor reference and webhookcontent.0.orderId. - Webhook
X-Request-ID, request timestamp, sale UUID, webhook-response record ID, and the response-audit timestamp. - Sale status and the presence of a stored payload before retrying retrieval. Inspect voucher-field presence without copying the URL or PIN into a ticket.
The webhook handler writes the received body to the processor interaction response audit. Treat that audit and the encrypted database payload as sensitive evidence; record field names, identifiers, states, and timestamps rather than voucher values.
Settings
Processor settings
config/go-gift-v2.php reads these environment-backed settings:
| Setting | Environment variable |
|---|---|
| API base URI | GO_GIFT_V2_API_URI |
| OAuth/token base URI | GO_GIFT_V2_AUTH_URI |
| API secret | GO_GIFT_V2_API_SECRET |
| OAuth client ID | GO_GIFT_V2_CLIENT_ID |
| B2B department/client ID | GO_GIFT_V2_B2B_DEPARTMENT_ID |
| HTTP timeout | GO_GIFT_V2_TIMEOUT |
| Webhook signature secret | GO_GIFT_V2_WEBHOOK_SIGNATURE |
The API client obtains an OAuth client-credentials token from <auth-base-uri>/connect/token, caches the access token, and sends it as a bearer token. Never expose the token, API secret, client ID, or webhook secret in an audit or escalation.
Brand settings
Each enabled brand requires the GoGift v2 product_id brand attribute and a denomination-level SKU mapping. The processor type migration changed the fixed type to SKU per denomination. Check both values for the requested face value; a valid product ID with a missing or incorrect SKU can produce a basket that does not represent the requested product.
API operations
| Client operation | Provider path | Method | Purpose |
|---|---|---|---|
createBasket | baskets/ | POST | Create a basket with sales channel ID 109 |
updateBasket | baskets/ | PUT | Replace basket products with one webhook-delivered item |
finalizeBasket | baskets/finalize/ | POST | Finalise the basket using invoice finance |
listAllProducts | products/filter/ | POST | Catalogue product listing |
getProductById | products/<product-id>/ | GET | Retrieve one catalogue product |
| Webhook confirmation | /webhook/<processor>/confirmation | POST | Receive signed fulfilment data; the application stores it locally |
Customer-service investigation
For a delayed or failed sale, collect the internal sale UUID, transaction reference, brand product_id, requested denomination and SKU, currency, basket ID, processor reference/order ID, sale status, and timestamps. Review the ordered create, update, finalise, webhook, and retrieval evidence. For webhook failures, also check the four required headers, client-ID match, signature verification result, and X-Request-ID without recording their secret values.
Before retrying, determine whether create returned a basket ID, whether update and finalise used the expected idempotency keys, and whether finalise may already have returned or created an order. Check the webhook-response record and its sale_uuid before dispatching another retrieval. Do not start a new order until the original basket and provider order have been reconciled.
If the webhook is absent, check provider delivery evidence and the local sale status; retrieval cannot query GoGift v2 for the voucher as a fallback. If the webhook exists but validation fails, compare only the required field names, order ID, URL validity, expiration presence, and audit timestamps. Keep the URI and PIN redacted.
Limitations
Escalations should include the internal sale UUID, transaction reference, basket ID, provider order ID, idempotency keys, webhook request ID and timestamp, sale status, and redacted audit evidence. Do not include bearer tokens, API secrets, webhook signatures, gift-card URLs, or PINs.
Related code
app/Processors/GoGiftV2/GoGiftV2Processor.php— asynchronous processor and webhook capability.app/Processors/Interaction/Integrations/GoGiftV2/GoGiftV2ProcessorInteraction.php— basket issue flow, cache, idempotency keys, webhook retrieval, validation, and cleanup dispatch.app/Processors/GoGiftV2/GoGiftV2WebhookHandler.php— webhook authentication, sale lookup, storage, auditing, and retrieval dispatch.app/Http/Clients/GoGiftV2/GoGiftV2Api.php— OAuth token handling, transport, headers, and provider operations.app/Http/Clients/GoGiftV2/Requests/CreateBasketRequestData.php— create payload.app/Http/Clients/GoGiftV2/Requests/UpdateBasketRequestData.php— basket update payload.app/Http/Clients/GoGiftV2/Requests/FinalizeBasketRequestData.php— finalisation payload.app/Http/Clients/GoGiftV2/Requests/ListAllProductsRequestData.php— catalogue listing request.app/Http/Clients/GoGiftV2/Requests/GetProductByIdRequestData.php— catalogue product request.config/go-gift-v2.php— API, OAuth, B2B, timeout, and webhook settings.database/migrations/2024_11_11_205846_create_go_gift_v2_processor.php— processor capabilities and technical contact.database/migrations/2024_11_13_095635_rcc-15266_create_go_gift_v2_webhook_responses_table.php— webhook-response storage schema.database/migrations/2025_02_13_141933_modify_go_gift_v2_fixed_processor_type_column.php— denomination SKU processor type.tests/Unit/Processors/Interaction/Integrations/GoGiftV2/GoGiftV2ProcessorInteractionTest.php— basket, retrieval, validation, and retry scenarios.tests/Unit/Processors/GoGiftV2/GoGiftV2WebhookHandlerTest.php— webhook header, signature, payload, sale-state, storage, and dispatch scenarios.