Skip to main content

Webhooks

Overview

When a payment is successfully processed for a MiniStore order, Giftme sends a webhook notification to the MiniStore's configured webhook_url. This allows your system to be notified in real-time when payments are completed.

Webhook Configuration

To receive webhooks, configure the following in your MiniStore settings:

  • webhook_url - The HTTPS endpoint where webhooks will be sent
  • api_secret - Your secret key used to verify webhook signatures

Webhook Request

HTTP Method

POST

Headers

HeaderDescription
Content-Typeapplication/json
X-SignatureHMAC-SHA256 signature of the payload

Request Body

{
"transaction_id": "MINISTORE-ABC1234567",
"original_order_id": "your-order-id-123",
"external_reference": "your-external-ref",
"amount": 1500.00,
"currency": "JMD",
"payment_method_type": "split",
"sources": [
{
"source_type": "gift_card",
"source_id": "123",
"amount": 500.00
},
{
"source_type": "smart_card",
"source_id": "456",
"amount": 1000.00
}
],
"status": "completed",
"mode": "live",
"created_at": "2025-12-17T15:30:00+00:00",
"updated_at": "2025-12-17T15:30:05+00:00"
}

Payload Fields

FieldTypeDescription
transaction_idstringGiftme's unique transaction ID (format: MINISTORE-XXXXXXXXXX)
original_order_idstringThe order ID you provided in the order token
external_referencestring|nullExternal reference you provided (if any)
amountnumberOrder amount (excluding service fees)
currencystringCurrency code (e.g., JMD, USD)
payment_method_typestringAlways split for multi-source payments
sourcesarrayList of payment sources used
sources[].source_typestringType of payment source (see below)
sources[].source_idstringID of the payment source
sources[].amountnumberAmount charged to this source
statusstringTransaction status (completed, failed, pending)
modestringlive or sandbox
created_atstringISO 8601 timestamp when transaction was created
updated_atstringISO 8601 timestamp when transaction was last updated

Source Types

Source TypeDescription
gift_cardMerchant-specific gift card
smart_cardGiftme Smart Card
expense_cardGiftme Expense Card
payment_methodBank card (Visa/Mastercard)
giftme_balanceUser's main Giftme wallet balance
sandbox_cardTest card (sandbox mode only)
sandbox_walletTest wallet (sandbox mode only)

Signature Verification

Always verify the webhook signature to ensure the request is authentic.

How to Verify

  1. Get the raw JSON payload from the request body
  2. Compute HMAC-SHA256 of the payload using your api_secret
  3. Compare with the X-Signature header

PHP Example

<?php
function verifyWebhookSignature($payload, $signature, $secret) {
$expectedSignature = hash_hmac('sha256', $payload, $secret);
return hash_equals($expectedSignature, $signature);
}

// In your webhook handler:
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_SIGNATURE'] ?? '';
$secret = 'your-api-secret';

if (!verifyWebhookSignature($payload, $signature, $secret)) {
http_response_code(401);
exit('Invalid signature');
}

$data = json_decode($payload, true);
// Process the webhook...

Node.js Example

const crypto = require('crypto');

function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expectedSignature),
Buffer.from(signature)
);
}

// In your Express handler:
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const payload = req.body.toString();
const signature = req.headers['x-signature'];
const secret = 'your-api-secret';

if (!verifyWebhookSignature(payload, signature, secret)) {
return res.status(401).send('Invalid signature');
}

const data = JSON.parse(payload);
// Process the webhook...

res.status(200).send('OK');
});

Python Example

import hmac
import hashlib

def verify_webhook_signature(payload: bytes, signature: str, secret: str) -> bool:
expected_signature = hmac.new(
secret.encode(),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected_signature, signature)

# In your Flask handler:
@app.route('/webhook', methods=['POST'])
def handle_webhook():
payload = request.get_data()
signature = request.headers.get('X-Signature', '')
secret = 'your-api-secret'

if not verify_webhook_signature(payload, signature, secret):
return 'Invalid signature', 401

data = request.get_json()
# Process the webhook...

return 'OK', 200

Response

Your webhook endpoint should respond with:

  • HTTP 2xx (200-299) to indicate successful receipt
  • Any other status code will be logged as a failed delivery

Timeout

Giftme waits 5 seconds for your webhook response. Ensure your endpoint responds quickly. If you need to perform long-running operations, acknowledge the webhook first and process asynchronously.

Retry Policy

Currently, webhooks are not automatically retried on failure. Failed webhook deliveries are logged and can be viewed in the webhook logs.

Best Practices

  1. Always verify signatures - Never trust webhook data without verification
  2. Respond quickly - Return 200 OK immediately, process async if needed
  3. Handle duplicates - Use transaction_id to detect and ignore duplicate deliveries
  4. Use HTTPS - Only configure HTTPS webhook URLs
  5. Log everything - Keep logs of received webhooks for debugging

Example Webhook Payloads

Successful Live Payment

{
"transaction_id": "MINISTORE-A1B2C3D4E5",
"original_order_id": "ORDER-2024-001",
"external_reference": "POS-TXN-789",
"amount": 2500.00,
"currency": "JMD",
"payment_method_type": "split",
"sources": [
{
"source_type": "gift_card",
"source_id": "gc_12345",
"amount": 1000.00
},
{
"source_type": "payment_method",
"source_id": "pm_67890",
"amount": 1500.00
}
],
"status": "completed",
"mode": "live",
"created_at": "2025-12-17T10:30:00-05:00",
"updated_at": "2025-12-17T10:30:02-05:00"
}

Sandbox Test Payment

{
"transaction_id": "MINISTORE-TEST123456",
"original_order_id": "test-order-001",
"external_reference": null,
"amount": 500.00,
"currency": "JMD",
"payment_method_type": "split",
"sources": [
{
"source_type": "sandbox_card",
"source_id": "sandbox_card",
"amount": 500.00
}
],
"status": "completed",
"mode": "sandbox",
"created_at": "2025-12-17T10:00:00-05:00",
"updated_at": "2025-12-17T10:00:01-05:00"
}