Webhooks

Webhooks allows you to receive notifications in your own backend whenever the company account of one of your subcompanies or your payment objects change state (you can find a visual of payment states in the Payments page ). This guide describes how to setup a webhook and verify the integrity of the notification.

  1. The notification payload
  2. Setting up a webhook
  3. Retries
  4. Webhook signatures

Webhook Setup and Verification Guide

The notification payload:

All notifications contains a message type which is either Company, Payment, or Payfac and the id and current state of the payment/company. A payment notification also contains type of payment, and optionally a parent id, if the payment is linked to another payment.

{
    "message_type": "Payment",
    "id": 123,
    "state": "PROCESSED",
    "type": "WITHDRAWAL",
    "parent": 1121
}
{
    "message_type": "Company",
    "id": 123,
    "state": "ACTIVE"
}
{
  "id": "<payFacMerchantId>",
  "state": "ACTIVE",
  "mid": "<merchantId>",
  "currency": "EUR",
  "message_type": "Payfac"
}

The fields expained:

  • id: The unique identifier of the object.
  • message_type: Payment, Company, Payfac
  • state: The current state of the object. Possible states include:
    • For payments (see also the Payments page):
      • PENDING
      • REJECTED_COMPLIANCE
      • REJECTED_APPROVAL
      • REJECTED_SIGNING
      • INITIATED_PAYMENT
      • PROCESSING_PAYMENT
      • PROCESSED
      • FAILED
      • DECLINED
      • REVERSED
      • REFUNDED
      • CANCELED
    • For companies (sent to the parent company when one of its subcompanies changes state):
      • ACTIVE
      • DEACTIVATED
      • PENDING_KYC
      • FAILED_KYC
      • PENDING_KYC_APPROVAL
    • For Payfac merchants:
      • CREATED
      • PENDING
      • ACTIVE

The following are relevant for payment objects only:

  • type: The PaymentType of the payment Object. Possible values:
    • TRANSFER
    • PAY_IN
    • WITHDRAWAL
    • FX
    • FX_RETURN
  • parent: Id of the parent PaymentObject, e.g. 123. The field is left out of the payload when the payment has no parent.

Setting Up a Webhook

To set up a webhook, follow these steps:

  1. Create an HTTP POST endpoint that accepts the JSON notification payload shown above. The endpoint must return a successful status code (200) as quickly as possible, before performing any complex logic that could cause a timeout.
  2. Register the endpoint with ComplyPay using the Create Payment Webhook endpoint.

Retries

Your endpoint must accept the connection within 10 seconds and respond with a 2xx status within 30 seconds. Any other response, or no response, counts as a failed delivery.

A failed delivery is retried up to four times, about 5 minutes, 20 minutes, 4 hours and 18 hours after the previous attempt. After the last retry the notification is not sent again automatically. You can send it again with Resend webhook log.

A disabled webhook receives no notifications, and notifications created while it is disabled are not delivered later. Use Toggle webhook to enable it again.

Webhook Signatures

ComplyPay signs every webhook notification it sends to your endpoint by including an X-Payload-Signature header with the payload's signature. It is recommended to use these signatures to verify that the webhook request is legitimate and was generated by ComplyPay.

Steps to Verify a Webhook Request

  1. Retrieve the X-Payload-Signature header from the request.
  2. Retrieve the webhook HTTP body as bytes.
  3. Generate a signature by signing the body from step 2 with the secret key generated when creating the webhook (the full value, including the whsec_ prefix). Use the HmacSHA512 algorithm for signing.
  4. Verify that the X-Payload-Signature header matches the signature generated in step 3.

Below is an example implementation in Java:

@ResponseBody
@PostMapping(produces = MediaType.APPLICATION_JSON_VALUE, value = "/payment-webhook-consume", consumes = MediaType.APPLICATION_JSON_VALUE)
public void consumeData(@RequestBody byte[] body, @RequestHeader(name = "X-Payload-Signature") String signature) throws NoSuchAlgorithmException, InvalidKeyException {
    String ALGORITHM = "HmacSHA512";
    String SECRET = "<YOUR_WEBHOOK_SECRET_KEY>";
    SecretKey key = new SecretKeySpec(SECRET.getBytes(StandardCharsets.UTF_8), ALGORITHM);

    Mac mac = Mac.getInstance(ALGORITHM);
    mac.init(key);

    byte[] calculatedSignature = mac.doFinal(body);
    String calculatedSignatureString = Base64.getEncoder().encodeToString(calculatedSignature);
    boolean isValid = calculatedSignatureString.equals(signature);

    if (isValid) {
        // Process the webhook payload
    } else {
        // Handle the invalid signature
    }
}

By following these instructions, you can ensure that your application receives and verifies webhook notifications securely and efficiently.