Hello Clever webhooks let your server receive real-time notifications whenever a payment’s status changes (for example, when a payment moves from pending to authorised, or from authorised to waiting). Instead of polling the API, you register an endpoint and Hello Clever sends a POST request to it automatically on each status transition.

How webhooks work

When a payment status changes, Hello Clever sends a POST request to your configured endpoint_url with a JSON payload describing the current state of the transaction. Your endpoint must return HTTP 200 to acknowledge receipt. If it does not, Hello Clever retries up to 3 times with a 15-minute delay between each attempt.
Because retries can deliver the same payload more than once, implement idempotent handling in your webhook endpoint. Deduplicate on the transaction identifier: uuid for the standard payload, or transaction_info.uuid for the Payment Gateway 3 payload.

Setting up webhooks

You can configure your webhook endpoint in two ways: SDK integration: Contact Hello Clever to register your default webhook URL. Any payment created via the SDK will send notifications to that URL. API integration: Include a webhook_notification object in your payment creation request. If provided, it overrides the default webhook URL for that payment.
object
Webhook configuration to include in a payment creation request.

Payment statuses

Hello Clever sends a webhook notification whenever a payment transitions to any of the following statuses:
When a payment is in in_dispute status, contact Hello Clever support to submit evidence for the dispute resolution process.

Webhook object

Hello Clever sends two different payload shapes. Which one you receive depends on the product that created the payment, so confirm which applies to your integration before you map fields:

Standard payload

Payment APIs, Multi-Currency Payment APIs, and Card APIs all send this shape. Each webhook POST body contains the following fields:

Example payload: card payment

Example payload: bank transfer

For bank transfer and QR methods, pay_code carries the details the customer needs to complete the payment instead of a 3DS URL:

Payment Gateway 3 payload

Payment Gateway 3 sends a payment link object rather than a flat transaction object. The differences matter when you write your handler:
  • Payment status is at transaction_info.status, not at the top level.
  • Amounts are JSON numbers, not strings.
  • The customer arrives as sender_info, not as top-level name and email.
  • transaction_info is null until the customer starts a payment against the link.

Example payload

Deduplicate Payment Gateway 3 deliveries on transaction_info.uuid. The top-level uuid identifies the payment link, which can produce more than one transaction.

Token for authorised cards

When a card payment reaches authorised or waiting status, Hello Clever includes a token object in the webhook payload. Save this token securely: you can use it to create future payments for the same customer without requiring them to re-enter their card details.
The token object is only present in webhook notifications when the status changes to authorised or waiting. It is not included in notifications for any other status.

Webhook security

Hello Clever supports two security mechanisms you can use independently or together.

Authorization header

If you set an authorization_header in your webhook configuration, Hello Clever will send that value in the Authorization header of every webhook request to your endpoint:
Verify this header on your server against your known secret to confirm the request is from Hello Clever.

HTTP webhook signature (HMAC-SHA256)

Hello Clever also signs each webhook payload using HMAC-SHA256 and sends the signature in the HTTP-WEBHOOK-SIGNATURE header:
To verify the signature, recompute the HMAC-SHA256 of the raw request body using your Webhook Secret Key and compare it with the header value.
1

Find your Webhook Secret Key

In the Merchant Portal, go to Dashboard → Developer → Authentication → Webhook tab and copy the value from the Webhook secret key field.
2

Compute the expected signature

Use the raw request body (do not parse and re-stringify JSON) and your Webhook Secret Key:
3

Compare and accept or reject

If the signatures match, the payload is authentic and unmodified. If they differ, reject the request; it may have been tampered with or sent by an untrusted source.
For maximum security, validate both the Authorization header and the HTTP-WEBHOOK-SIGNATURE. The Authorization header confirms the sender; the signature confirms the payload has not been tampered with.

Testing your signature verification

If your verification is rejecting valid requests, check your computation against the delivered signature by hand before changing your code.
1

Capture the raw request body

Open your request log and copy the raw body of the webhook request exactly as it arrived. Do not reformat it, and do not parse and re-serialise the JSON: whitespace and key order are part of what was signed.
2

Compute the HMAC outside your application

Run the raw body through any HMAC-SHA256 calculator, using your Webhook Secret Key as the key. Set the input encoding to UTF-8 and the output encoding to lowercase hex.
3

Compare against the delivered header

Find the http-webhook-signature header on the same request and compare the two values:
If they match, the signature is valid and the bug is in your application’s handling. If they differ, the request was either tampered with or signed with a different key: confirm you are using the Webhook Secret Key for the correct merchant.
Use a calculator you trust with the secret. Pasting your Webhook Secret Key into a third-party website exposes it. Prefer a local tool, for example openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" body.json.

Error handling and retries

If your endpoint does not return HTTP 200, Hello Clever retries the webhook call up to 3 times with a 15-minute delay between each attempt. To handle retries correctly:
  • Return 200 immediately upon receiving the webhook, before performing any heavy processing.
  • Process the event asynchronously (e.g. via a queue) to avoid timeouts.
  • Use the transaction identifier to detect and discard duplicate deliveries: uuid, or transaction_info.uuid on Payment Gateway 3.

Error codes

When a payment fails, the pay_code object includes error_code and error_message. The following table lists all possible error codes:

Best practices

  1. Verify the Authorization header or HTTP-WEBHOOK-SIGNATURE on every incoming request before processing.
  2. Implement idempotency using the transaction identifier (uuid, or transaction_info.uuid on Payment Gateway 3) to prevent duplicate side effects from retried deliveries.
  3. Return 200 OK as soon as you receive the request; process the payload asynchronously.
  4. Keep your webhook endpoint URL private; avoid sharing it publicly.
  5. Use HTTPS for your webhook endpoint to protect the payload in transit.
  6. Test your endpoint during development using tools like webhook.site or a local tunnel such as ngrok.