> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.paywithatoa.co.uk/llms.txt
> Use this file to discover all available pages before exploring further.

# Introduction | Webhooks API

> Atoa webhooks: subscribe to payment, refund and payout events so your system is notified in real time. Setup, event types and payloads.

Webhooks allow you to receive real-time notifications when events occur on Atoa, delivered directly to an HTTP endpoint of your choice. They eliminate the need to poll the Atoa API for status updates, saving time and resources.

## Event types

Subscribe to the event types relevant to your integration:

| Event type           | Description                                                                    | Payload reference                                                 |
| -------------------- | ------------------------------------------------------------------------------ | ----------------------------------------------------------------- |
| `PAYMENTS_STATUS`    | Pay by Bank and Card on File payment completed, pending, or failed             | [Payload](/api-reference/Webhook/processPaymentWebhookResponse)   |
| `EXPIRED_STATUS`     | Payment request expired before the customer completed payment                  | [Payload](/api-reference/Webhook/expiredStatusWebhookResponse)    |
| `REFUND_STATUS`      | Refund completed, cancelled, or failed                                         | [Payload](/api-reference/Webhook/refundStatusWebhookResponse)     |
| `POS_PAYMENT_STATUS` | POS terminal payments (Pay by Bank and card) and POS-initiated refunds (voids) | [Payload](/api-reference/Webhook/posPaymentStatusWebhookResponse) |

<Note icon="lightbulb" href="/api-reference/Payment/process-payment" title="Payment Expiry">
  Payments expire after the [expiresIn](/api-reference/Payment/process-payment#payment-expiration) duration. See the [refunds](/api-reference/Refund/initiateRefund) API for refund event details.
</Note>

## Multiple endpoints per event type

You can register up to **3 endpoints per event type**. When an event fires, Atoa delivers the webhook to all registered endpoints for that event simultaneously — each endpoint receives its own independent delivery with its own retry tracking.

This lets different systems subscribe to the same event independently without coupling them together. For example:

| Endpoint                                    | Subscribed events                   |
| ------------------------------------------- | ----------------------------------- |
| `https://orders.your-server.com/webhook`    | `PAYMENTS_STATUS`, `REFUND_STATUS`  |
| `https://analytics.your-server.com/webhook` | `PAYMENTS_STATUS`                   |
| `https://crm.your-server.com/webhook`       | `PAYMENTS_STATUS`, `EXPIRED_STATUS` |

All three endpoints above receive `PAYMENTS_STATUS` webhooks independently. A failure at one endpoint does not affect delivery to the others.

<Note>
  The limit is **3 endpoints per event type**. Attempting to register a fourth endpoint for an event type that already has 3 returns a `400` error. Use [List endpoints](/api-reference/Webhook/v2/listEndpoints) to review your current registrations. Multiple endpoints per event type is a **v2-only** feature — v1 supports one endpoint per event type.
</Note>

## API versions

Atoa provides two webhook API versions. **Use v2 for all new integrations.**

|                         | v1 (Legacy)             | v2 (Recommended)                  |
| ----------------------- | ----------------------- | --------------------------------- |
| **Events per endpoint** | Single                  | Multiple                          |
| **Full CRUD**           | Create only             | Create, read, update, delete      |
| **Description field**   | —                       | ✓                                 |
| **Failure tracking**    | —                       | `failureCount`, `lastDeliveredAt` |
| **Base path**           | `/api/webhook/merchant` | `/api/webhook/v2/endpoints`       |

v1 remains supported for existing integrations. For new implementations, use the [v2 API](/api-reference/Webhook/v2/createEndpoint), which lets you subscribe to multiple event types per endpoint and manage authentication after creation.

## Getting started

<Steps>
  <Step title="Register your webhook endpoint">
    Use the [Create Endpoint (v2)](/api-reference/Webhook/v2/createEndpoint) API to register your endpoint URL and subscribe to one or more event types in a single call.

    ```bash theme={null}
    curl --request POST \
      --url https://api.atoa.me/api/webhook/v2/endpoints \
      --header 'Authorization: Bearer <token>' \
      --header 'Content-Type: application/json' \
      --data '{
        "url": "https://your-server.com/webhook",
        "events": ["PAYMENTS_STATUS", "REFUND_STATUS"]
      }'
    ```

    Use [List Endpoints](/api-reference/Webhook/v2/listEndpoints) to view, [Update Endpoint](/api-reference/Webhook/v2/updateEndpoint) to modify, or [Delete Endpoint](/api-reference/Webhook/v2/deleteEndpoint) to remove subscriptions.
  </Step>

  <Step title="Handle incoming payloads">
    Return HTTP `200` on success — any other response triggers [retries](#retry-mechanism). Each event type has a different payload structure — see the [Event types](#event-types) table for payload references.
  </Step>

  <Step title="Verify the signature">
    Every webhook delivery is signed so you can verify it genuinely came from Atoa. See [Signature verification](#signature-verification) below for the two available methods.
  </Step>
</Steps>

## Testing your webhook

Send a test webhook to your sandbox URL without creating a real payment. The body and signature match a production event, so you can verify your integration end-to-end before going live.

Use the [Trigger test webhook event](/api-reference/Webhook/testWebhookEvent) endpoint:

```bash theme={null}
curl --request POST \
  --url https://api.atoa.me/api/webhook/test \
  --header 'Authorization: Bearer <sandbox-token>' \
  --header 'Content-Type: application/json' \
  --data '{
    "eventType": "PAYMENTS_STATUS"
  }'
```

Override fields like `orderId`, `amount`, `paymentMethod`, and `status` to simulate specific scenarios. See the [Trigger test webhook event](/api-reference/Webhook/testWebhookEvent) reference for all available fields and per-event rules.

<Note>
  Test triggers are **sandbox-only** — production keys are rejected. You must have an active subscription for the event type before the trigger will deliver.
</Note>

## Signature verification

Atoa supports two methods for verifying webhook authenticity. **We recommend V2 signing for all new integrations.**

|                    | V1 (Legacy)                                | V2 (Recommended)               |
| ------------------ | ------------------------------------------ | ------------------------------ |
| **How it works**   | `signatureHash` field inside the JSON body | `X-Atoa-Signature` HTTP header |
| **What is signed** | `orderId \| paymentRequestId`              | The entire JSON request body   |
| **Algorithm**      | HMAC-SHA256                                | HMAC-SHA256                    |

### V2 Signing

V2 signing covers the entire request body with HMAC-SHA256, making it more secure than field-level V1 signing. V2 is **required** for `POS_PAYMENT_STATUS` webhooks.

1. Generate a signing secret from the [Atoa Dashboard](https://dashboard.paywithatoa.co.uk/my-account/settings/webhooks) under **Settings → Webhooks**.
2. For every incoming webhook, compute `HMAC-SHA256(signingSecret, rawRequestBody)` and compare the hex digest against the `X-Atoa-Signature` header value (after stripping the `v1=` prefix).
3. Use a timing-safe comparison function to prevent timing attacks.

See the [V2 Webhook Signing guide](/api-reference/Webhook/v2-signing) for full setup instructions and code samples in Node.js, Python, Java, Go, and PHP.

### V1 Signing

V1 signing verifies authenticity using the `signatureHash` field included in the webhook body. It signs only the `orderId` and `paymentRequestId` (or `refundId` for refund webhooks).

See the [V1 Webhook Signing guide](/api-reference/Webhook/v1-signing) for full verification steps and code samples.

<Note>
  If you enable V2 signing, the `signatureHash` and `signature` fields are removed from the webhook body and an `eventType` field is added instead. V1 and V2 cannot be used simultaneously for the same merchant.
</Note>

## Endpoint authentication

Optionally configure authentication so Atoa includes credentials in every delivery, in addition to signature verification.

| Method         | Description                                                                                                                                                                |
| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **None**       | No additional authentication. Rely on [signature verification](#signature-verification) to validate deliveries.                                                            |
| **OAuth 2.0**  | Atoa obtains access tokens from your authorisation server and includes them in webhook requests. Pass `clientId`, `clientSecret`, and `authUrl` when creating the webhook. |
| **Basic Auth** | Atoa includes a username and password in the Authorization header. Pass `username` and `password` when creating the webhook.                                               |

<Note icon="shield-check" title="Security Best Practice">
  Signature verification cryptographically proves requests come from Atoa. For maximum security, combine it with OAuth or Basic Authentication.
</Note>

## Retry mechanism

When a webhook response is anything other than HTTP `200`, it is considered a failure. Our system retries using an exponential back-off strategy. If the webhook continues to fail over 24 hours, Atoa stops the retry attempts and sends an email notification to the business owner with the failing webhook URL.
