Payment Subscriptions
Subscribe to webhook events to receive real-time notifications about payment-related activities. All webhook payloads require HMAC authentication to verify authenticity.
Authorization (HMAC)
To verify that the payloads your webhooks receive actually come from Shift4, you must implement HMAC authentication schema.
HMAC constructs an information-rich header that contains information about the sender, while providing security to ensure that the request has not been forged or tampered with in transit.
For comprehensive information about implementing HMAC authentication, see the Subscriptions Overview documentation.
Verification process
When you receive a webhook payload:
- Extract the signature from the request headers
- Compute the expected signature using your webhook secret
- Compare the signatures using a timing-safe comparison
- Only process the webhook if signatures match
Verify HMAC signature
import crypto from 'crypto';
function verifyHmacSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
app.post('/webhooks/payments', (req, res) => {
const signature = req.headers['x-signature'];
const payload = req.body;
if (!verifyHmacSignature(payload, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
// Process the webhook
handlePaymentWebhook(payload);
res.status(200).send('OK');
});
Available Subscriptions
The Payments Integration API currently supports the following webhook subscriptions:
- Payment Auth Token Created - Notifies when a new auth token is created after installation
Additional payment-related webhook events may be added in future releases.
Payment Auth Token Created
Sends a payment auth token creation notification after the installation is finalized. This webhook is triggered when a merchant completes the marketplace app installation process.
Event structure
The webhook payload contains two main sections:
Event metadata - Information about the webhook event itself including the event name, component, action, version, subscription ID, and dispatch time.
Payload data - The actual data about the created auth token, including the location ID and token GUID needed to retrieve the full auth token.
Webhook event properties
- Name
event.name- Type
- string
- Description
Event identifier:
payments.AuthToken.created
- Name
event.component- Type
- string
- Description
Component that generated the event:
payments
- Name
event.resource- Type
- string
- Description
Resource type:
AuthToken
- Name
event.action- Type
- string
- Description
Action that occurred:
created
- Name
event.version- Type
- string
- Description
API version:
v1
- Name
event.subscriptionId- Type
- integer
- Description
Your subscription identifier
- Name
event.dispatchedAt- Type
- string
- Description
ISO 8601 timestamp when the webhook was dispatched
Payload properties
- Name
payload.locationId- Type
- integer
- Description
The Lighthouse location ID where the installation occurred. Required.
- Name
payload.guid- Type
- string
- Description
Payment auth token GUID in UUID format. Use this to retrieve the full auth token. Required.
Webhook Payload
{
"event": {
"name": "payments.AuthToken.created",
"component": "payments",
"resource": "AuthToken",
"action": "created",
"version": "v1",
"subscriptionId": 1,
"dispatchedAt": "2019-10-15T17:00:00.000Z"
},
"payload": {
"locationId": 1,
"guid": "d0511bae-1099-4ac1-bf48-1d8640575330"
}
}
Response requirements
Your webhook endpoint must respond with a 2xx HTTP status code to acknowledge successful receipt. Any other response code will be treated as a failure, and the webhook may be retried.
Webhook handler example
app.post('/webhooks/payments', async (req, res) => {
const { event, payload } = req.body;
if (event.name === 'payments.AuthToken.created') {
const { locationId, guid } = payload;
console.log(`Auth token created for location ${locationId}`);
console.log(`Token GUID: ${guid}`);
// Retrieve the full auth token
try {
const authToken = await retrieveAuthToken(locationId, guid);
// Exchange for access token
const accessToken = await exchangeAuthToken(authToken);
// Store access token securely
await storeAccessToken(locationId, accessToken);
res.status(200).send('OK');
} catch (error) {
console.error('Failed to process auth token:', error);
res.status(500).send('Processing failed');
}
} else {
res.status(200).send('Event not handled');
}
});
Best practices
Respond quickly
Always respond with a 200 status code as quickly as possible. Process the webhook asynchronously to avoid timeouts. The webhook delivery system expects a response within 10 seconds.
Verify HMAC signatures
Always verify the HMAC signature of incoming webhook payloads before processing them. This ensures the webhook came from Shift4 and hasn't been tampered with.
Handle idempotency
Webhooks may be delivered multiple times. Implement idempotency by tracking processed event IDs or using the combination of locationId and guid to prevent duplicate processing.
Retrieve immediately
When you receive an auth token creation event, retrieve and exchange the auth token immediately. Auth tokens expire and can only be used once.
Error handling
Implement proper error handling and logging. If processing fails, consider whether to return a 500 status (which may trigger a retry) or 200 (acknowledging receipt even if processing failed).
Testing
Test your webhook handlers thoroughly in development before deploying to production. Use test mode events to verify your HMAC verification and event processing logic.
After receiving this webhook, use the Retrieve Auth Token endpoint with the provided locationId and guid to get the full auth token, then exchange it for an access token via the Lighthouse API.