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.

Verification process

When you receive a webhook payload:

  1. Extract the signature from the request headers
  2. Compute the expected signature using your webhook secret
  3. Compare the signatures using a timing-safe comparison
  4. 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:

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.

Was this page helpful?