Super Payments triggers a webhook whenever a significant event occurs within a transaction lifecycle.

- **Real-time Updates:** Receive immediate notice when a transaction status changes.
- **Monitoring:** You can verify your configuration and monitor webhook performance through the [Webhook Insights](https://business.superpayments.com/dashboard/developers/webhooks) section of your business portal, click on your webhook URL to view the events.

## Endpoint Configuration

To begin receiving events, you must register your webhook endpoint URL within the Super Payments Portal. This URL is where our server will send POST requests containing event data.

### Registering your Endpoint URL

1. **Access the Portal:** Log in to your business portal and navigate to the integrations section.
2. **Enter your URL:** Locate the webhook configuration field and enter the full destination URL of your server (e.g., [https://your-api.com/webhooks/super](https://your-api.com/webhooks/super)).
3. **Retrieve your Secret:** Once configured, you will see your Confirmation ID (starting with `PWH_`). Save this securely, as it is required for signature verification.

## Securing your Webhook

To ensure that requests are authentic and originated from Super Payments, every webhook includes a `super-signature` header.

### Signature Format

The `super-signature` header contains a timestamp and a cryptographic signature, separated by a comma.

- Timestamp: Prefixed by `t:` (e.g., t:1669219987926).
- Signature: Prefixed by `v1:` (e.g., v1:bc2719322a2...).

### Verifying the Signature

To verify the signature, you will need your Confirmation ID, which acts as your webhook secret. This ID starts with PWH\_ and is located in the Integrations section of your portal, click on the arrow "View this integration".

1. **Extract Data:** Split the header by the `,` character to separate the timestamp and signature.
2. **Parse Pairs:** Split the resulting components by the `:`character to retrieve the actual values.
3. **Prepare Message:** Create a single message string by concatenating the timestamp value and the raw request body.
4. **Compute Hash:** Generate an HMAC signature using the **SHA256** hash function. Use your Confirmation ID as the key and the string from step 3 as the message.
5. **Compare:** Ensure the generated hash matches the signature provided in the header.

Example Signature

```http
super-signature: t:1669219987926,v1:bc2719322a26335c486df9dffeb0c555c758b2a7470de6f62421cfb8437e8b5b
```

## Reliability & Retries

If your server is unavailable or returns an error, Super Payments will automatically retry sending the webhook notification using an exponential backoff strategy.

| Attempt | Resend Interval |
| --- | --- |
| 1 | 8 seconds |
| 2 | 1 minute |
| 3 | 8 minutes |
| 4 | 1 hour |
| 5 | 8 hours |
| 6 | 12 hours |

> 🚧
>
> Following the **sixth** attempt, we continue to retry every 12 hours for a maximum of 7 additional attempts.

## Event Types

Super Payments sends webhooks for the following event types. Each payload includes an `eventType` field identifying the event, a unique `eventId`, an `eventDatetime` timestamp, and a `data` object containing the event-specific details.

| Event Type | Triggered When |
| --- | --- |
| `payment.success` | A payment has been successfully authorised and completed. |
| `payment.failed` | A payment was not completed. Check the `status` field for the specific reason. |
| `refund.success` | A refund has been successfully processed. |
| `refund.failed` | A refund could not be processed. |
| `customer.payment_method.requires_action` | A saved customer payment method requires further action before it can be used. |
| `customer.payment_method.enabled` | A saved customer payment method has been successfully enabled. |
| `customer.payment_method.disabled` | A saved customer payment method has been disabled. |

### payment.success
Triggered when a payment has been successfully authorised and funds captured. The `fundingSummary` object details how the transaction was funded.

Example Payload - Checkout Session

```json
{
  "data": {
    "amount": {
      "amount": 15000,
      "currency": "GBP",
      "amountMultiplier": 100
    },
    "source": "checkoutSession",
    "status": "PaymentSuccess",
    "brandId": "123-123-123-123",
    "paymentId": "123-123-123-123",
    "fundingSummary": {
      "superFundedAmount": {
        "amount": 0,
        "currency": "GBP",
        "amountMultiplier": 100
      },
      "customerFundedAmount": {
        "amount": 15000,
        "currency": "GBP",
        "amountMultiplier": 100
      },
      "merchantFundedAmount": {
        "amount": 0,
        "currency": "GBP",
        "amountMultiplier": 100
      },
      "cashPayableToMerchant": {
        "amount": 15000,
        "currency": "GBP",
        "amountMultiplier": 100
      }
    },
    "surchargeAmount": {
       "amount": 600,
       "currency": "GBP",
       "amountMultiplier": 100
    },
    "paymentReference": "PAYMENT123",
    "externalReference": "TestOrder123",
    "paymentInitiatorId": "123-123-123-123"
  },
  "eventId": "evt_test_123",
  "eventType": "payment.success",
  "eventDatetime": "2026-03-15T11:09:09.000Z"
}
```

Example Payload - Payment Link

```json
{
  "data": {
    "amount": {
      "amount": 5000,
      "currency": "GBP",
      "amountMultiplier": 100
    },
    "source": "paymentLink",
    "status": "PaymentSuccess",
    "brandId": "123-123-123-123",
    "paymentId": "123-123-123-123",
    "fundingSummary": {
      "superFundedAmount": {
        "amount": 0,
        "currency": "GBP",
        "amountMultiplier": 100
      },
      "customerFundedAmount": {
        "amount": 5000,
        "currency": "GBP",
        "amountMultiplier": 100
      },
      "merchantFundedAmount": {
        "amount": 0,
        "currency": "GBP",
        "amountMultiplier": 100
      },
      "cashPayableToMerchant": {
        "amount": 5000,
        "currency": "GBP",
        "amountMultiplier": 100
      }
    },
    "surchargeAmount": {
       "amount": 600,
       "currency": "GBP",
       "amountMultiplier": 100
    },
    "paymentReference": "PAYMENT123",
    "externalReference": "TestOrder123",
    "paymentInitiatorId": "123-123-123-123"
  },
  "eventId": "evt_test_123",
  "eventType": "payment.success",
  "eventDatetime": "2026-03-15T10:20:28.000Z"
}
```

### payment.failed
Triggered when a payment was not completed. The `status` field in the `data` object indicates the specific reason:

| Status | Description |
| --- | --- |
| `PaymentFailed` | The transaction was declined or could not be processed by the provider. |
| `PaymentCancelled` | The customer manually cancelled the transaction before completion. |
| `PaymentAbandoned` | The customer closed the checkout session without taking action. |

> **Note:**`fundingSummary` will be `null` for all failed payment events.

Example Payload - PaymentCancelled

```json
{
  "data": {
    "amount": {
      "amount": 15000,
      "currency": "GBP",
      "amountMultiplier": 100
    },
    "source": "checkoutSession",
    "status": "PaymentCancelled",
    "brandId": "123-123-123-123",
    "paymentId": "123-123-123-123",
    "fundingSummary": null,
    "paymentReference": "PAYMENT123",
    "externalReference": "TestOrder123",
    "paymentInitiatorId": "123-123-123-123"
  },
  "eventId": "evt_test_123",
  "eventType": "payment.failed",
  "eventDatetime": "2026-03-15T08:54:24.000Z"
}
```

Example Payload - PaymentAbandoned

```json
{
  "data": {
    "amount": {
      "amount": 15000,
      "currency": "GBP",
      "amountMultiplier": 100
    },
    "source": "checkoutSession",
    "status": "PaymentAbandoned",
    "brandId": "123-123-123-123",
    "paymentId": "123-123-123-123",
    "fundingSummary": null,
    "paymentReference": "PAYMENT123",
    "externalReference": "TestOrder123",
    "paymentInitiatorId": "123-123-123-123"
  },
  "eventId": "evt_test_123",
  "eventType": "payment.failed",
  "eventDatetime": "2026-03-14T13:32:28.000Z"
}
```

### refund.success
Triggered when a refund has been successfully processed against an original transaction.

Example Payload

```json
{
  "data": {
    "amount": {
      "amount": 15000,
      "currency": "GBP",
      "amountMultiplier": 100
    },
    "status": "RefundSuccess",
    "brandId": "123-123-123-123",
    "refundId": "123-123-123-123",
    "refundReference": "REFUND123",
    "refundComponents": {
      "superAmount": {
        "amount": 0,
        "currency": "GBP",
        "amountMultiplier": 100
      },
      "customerAmount": {
        "amount": 15000,
        "currency": "GBP",
        "amountMultiplier": 100
      },
      "merchantAmount": {
        "amount": 0,
        "currency": "GBP",
        "amountMultiplier": 100
      }
    },
    "externalReference": "TestOrder123",
    "originatingPaymentId": "123-123-123-123",
    "originatingPaymentSource": "checkoutSession",
    "originatingPaymentExternalReference": "TestOrder123"
  },
  "eventId": "evt_test_123",
  "eventType": "refund.success",
  "eventDatetime": "2026-03-15T10:46:27.000Z"
}
```

### refund.failed
Triggered when a refund could not be processed against an original transaction.

Example Payload

```json
{
  "data": {
    "amount": {
      "amount": 15000,
      "currency": "GBP",
      "amountMultiplier": 100
    },
    "status": "RefundFailed",
    "brandId": "123-123-123-123",
    "refundId": "123-123-123-123",
    "refundReference": "REFUND123",
    "refundComponents": {
      "superAmount": {
        "amount": 0,
        "currency": "GBP",
        "amountMultiplier": 100
      },
      "customerAmount": {
        "amount": 15000,
        "currency": "GBP",
        "amountMultiplier": 100
      },
      "merchantAmount": {
        "amount": 0,
        "currency": "GBP",
        "amountMultiplier": 100
      }
    },
    "externalReference": "TestOrder123",
    "originatingPaymentId": "123-123-123-123",
    "originatingPaymentSource": "checkoutSession",
    "originatingPaymentExternalReference": "TestOrder123"
  },
  "eventId": "evt_test_123",
  "eventType": "refund.failed",
  "eventDatetime": "2026-03-15T10:46:27.000Z"
}
```

### customer.payment_method.requires_action
Triggered when a saved customer payment method requires further action before it can be used for off-session payments. You should prompt the customer to re-authenticate or update their payment details.

Example Payload

```json
{
  "data": {
    "type": "CARD",
    "usage": "OFF_SESSION",
    "status": "REQUIRES_ACTION",
    "customerId": "cus_123",
    "merchantId": "123-123-123-123",
    "paymentMethodId": "pm_123"
  },
  "eventId": "evt_test_123",
  "eventType": "customer.payment_method.requires_action",
  "eventDatetime": "2026-03-12T16:21:16.000Z"
}
```

### customer.payment_method.enabled
Triggered when a saved customer payment method has been successfully enabled and is ready to be used for off-session payments.

Example Payload

```json
{
  "data": {
    "type": "CARD",
    "usage": "OFF_SESSION",
    "status": "ENABLED",
    "customerId": "cus_123",
    "merchantId": "123-123-123-123",
    "paymentMethodId": "pm_123"
  },
  "eventId": "evt_test_123",
  "eventType": "customer.payment_method.enabled",
  "eventDatetime": "2026-03-10T13:12:40.000Z"
}
```

### customer.payment_method.disabled
Triggered when a saved customer payment method has been disabled and can no longer be used for off-session payments.

Example Payload

```json
{
  "data": {
    "type": "CARD",
    "usage": "OFF_SESSION",
    "status": "DISABLED",
    "customerId": "cus_123",
    "merchantId": "123-123-123-123",
    "paymentMethodId": "pm_123"
  },
  "eventId": "evt_test_123",
  "eventType": "customer.payment_method.disabled",
  "eventDatetime": "2026-03-10T13:16:06.000Z"
}
```

## Payment Identification

Every webhook payload includes a `paymentId` that uniquely identifies the payment transaction. This is the same value as the `paymentIntentId` returned in the [`/proceed` endpoint](https://docs.superpayments.com/reference/proceed-payment-via-checkout-session) and the `id` returned in the [`/payments` endpoint](https://docs.superpayments.com/reference/create-payment-intent) response.

| Source | Field | Description |
| --- | --- | --- |
| `/proceed` \| `/payments` response | `paymentIntentId` \| `id` | Unique identifier assigned to the payment transaction |
| Webhook payload | `paymentId` | The same identifier, referencing the transaction in status updates |

Use this shared identifier to correlate webhook events with the payment transactions initiated from your server.

## Matching Webhooks to Orders

The `externalReference` field in the webhook payload is a pass-through value set by the merchant at payment creation. Super Payments does not use this field to deduplicate or relate transactions.

Because multiple transactions can share the same `externalReference`, you should use the `paymentId` as the primary identifier when processing webhook events.

**Recommended approach:**

1. When calling `/proceed`\| `/payments`, store the returned `paymentIntentId`\|`id` against your order.
2. If the customer retries the payment, call the relavent endpoint again and update the stored ID with the new value.
3. When a webhook is received, validate that the incoming `paymentId` matches the `paymentIntentId` \| `id`currently associated with your order.
4. Discard any webhook where the `transactionId` does not match.

Example Approach

```text
ON /proceed response:
    order.paymentIntentId = response.paymentIntentId
    SAVE order

ON webhook received:
    order = FIND order BY webhook.externalReference

IF webhook.paymentId != order.paymentIntentId:
        LOG "Ignoring webhook for outdated transaction"
        RETURN 200 OK
    ELSE:
        UPDATE order status
        RETURN 200 OK
```

## Supported Payment Methods

Webhooks are triggered for the following:

- **Payments**: created through the embedded checkout components, the Payment Intents API, and the Payment Links API.
- **Refunds**: processed through the Refunds API.
- **Saved Cards**: state changes to customer payment methods (enabled, disabled, or requires action) for merchants using off-session payments.

## Best Practices

### Return a 2xx response

Your endpoint must quickly return a successful status code (2xx) prior to executing any complex logic that could cause a timeout. For example, you should return a 200 response immediately upon receiving the event, before performing tasks like updating your database or triggering order fulfillments. This prevents Super from marking the attempt as a failure and initiating retries.
