What are webhooks?

There are two mechanisms for consuming updates from an API; polling and webhooks. Polling is a pull-based mechanism that requires the consumer (you) to make requests against the API to check for changes. Webhooks are a push-based mechanism, where the producer (Crezco) will send an event to an endpoint of your choosing to let you know something happened.

How do they work?

First, you register the endpoint you want to receive the events to via the Crezco API. You can select which event types you want to receive events for.

Crezco will then send webhook events as HTTP POST payloads to any endpoint(s) you have registered whenever an event occurs. All your endpoint needs to do is return 200 (OK) in response and we know you've received the message. If you don't return a 200 we will try again.

All of this is explained in more detail below.

Event Types

EventTypeDescription
PayRunA status change has occurred to a Payrun
BatchA status change has occurred to a Batch
GroupA status change has occurred to a Group
PayableA status change has occurred to a Payable
AuthorisationA status change has occurred to a Payment Authorisation attempt
OrganisationOnboardingA status change has occurred to an Organisation Onboarding attempt
BankAccountA status change has occurred to a Bank Account

See Statuses

More event types may be available in future updates to the API. These will be added in a backwards-compatible fashion.

Managing endpoints

Consumers are required to register their desired webhook endpoints via the API. This allows for programmatic registration and avoids the need to manage endpoints via dashboards or set them up in advance.

For applications that depend on webhooks for their operation we recommend checking that a webhook exists upon startup.

Requirements for registering an endpoint

An endpoint registration:

  • Must contain at least 1 EventType
  • Must be unique by URL
  • Must be HTTPS
  • Must not contain query parameters

Registering an endpoint

In order to receive webhooks you must register at least one endpoint. This can be done by making a POST - Register webhook request with the endpoint and desired event type(s).

Example payload

{
  "eventType": "PayRun",
  "callback": "https://webhooks.example.org/crezco/payruns"
}

Listing your endpoints

To get a list of all registered webhook endpoints you can make a GET - List existing webhooks for Partner request.

Example response

{
  "webHooks": [
    {
      "webHookId": "8cefae8a-ab99-4ce0-b364-1e4426c4dfda",
      "eventType": "PayRun",
      "callback": "https://webhooks.example.org/crezco/payruns"
    }
  ]
}

Updating an endpoint

To update an existing endpoint registration you can make a PUT - Update webhook call with the updated information.

Deleting an endpoint

To delete an endpoint make a DELETE - Delete existing webhook call with the ID of the webhook you wish to delete.

Payloads

All payloads are sent as a JSON payload with a consistent format.

Fields

FieldDescription
EventsAn array of events. Will contain at least 1 event

Note that metadata fields to help with ingestion and observability may be added in future, in a backwards-compatible fashion.

Event Fields

FieldDescriptionEvent Types
EventIdUnique numeric id to identify the event.All
TypeThe Event Type. For more details on event types see the definitions above.All
IdId of the resource the event relates to. For example, if the Event Type is PayRun then this will be the PayRunId.All
ParentTypeType of the resource's parent. Note: This is expected to be PayRun unless the Event Type is Authorisation in which case it will be BatchBatch, Group, Payable, Authorisation
ParentIdId of the resource's parent. See ParentType for which type this relates to.Batch, Group, Payable, Authorisation
StatusThe new status for the resource. For specific status values please see the Statuses pageAll
TimestampThe UTC timestamp that the status change was made.All
OrganisationIdThe Id of the Organisation that the resource belongs to.All
PartnerClientIdThe partner-provided Id that the resource belongs to.All
PartnerEntityIdThe partner-provided Id for the related resource, where applicable. For example, if the Event Type is PayRun then this will be the partner-supplied PayRunId.PayRun Group Payable
ParentPartnerEntityIdThe partner-provided Id related to the resource's parent. To simplify processing this is only ever set to the partner entity ID for the owning PayRun.Batch, Group, Payable
VersionThe API version that this webhook was raised fromAll
PayloadJSON payload with additional event informationOrganisationOnboarding

ParentType and ParentId are only present on Payment events. A payment's parent may be either a payable or a group.

Headers

HeaderDescription
Crezco-SignaturesThe HMACSHA256 signature for the payload. For more information see the section on Signatures below.

Example payload

{
  "Events": [
    {
      "EventId": 998,
      "Type": "PayRun",
      "Id": "63fa43a7-d54f-48fb-aa31-3658870e9301",
      "Status": "Completed",
      "Timestamp": "12:34:56T01:01:01.001",
      "OrganisationId": "13fea469-3a23-490c-85ec-4ece15041203",
      "PartnerClientId": "abcd123",
      "PartnerEntityId": "Your-PayRun-ID1",
      "Version": "2023-02-01"
    },
    {
      "EventId": 999,
      "Type": "Payable",
      "Id": "48ffcfaa-b081-4cfc-af1d-949efe1d7c4b",
      "Status": "Completed",
      "Timestamp": "12:34:56T01:01:01.001",
      "OrganisationId": "13fea469-3a23-490c-85ec-4ece15041203",
      "PartnerClientId": "abcd123",
      "PartnerEntityId": "Your-Payment-ID1",
      "Version": "2023-02-01"
    }
  ]
}

Delivery

Requirements for receiving payloads

For payload delivery the following apply:

  • Endpoint must respond with 200 (OK) to confirm acceptance.
    • Any other response will be treated as a failure.
  • Endpoint must respond within 5 seconds.
    • After this time any response will be treated as a failure due to timeout.
  • Payloads shall be delivered at least once.
    • Consumers must be prepared to receive duplicate payloads due to timeout and retry policies.
  • Payloads may arrive out-of-order.
    • Consumers must be prepared to receive out-of-order payloads due to timeout and retry policies.
  • Payloads may contain events for multiple unrelated pay-runs.
    • We try to batch events to minimise traffic where possible. The ability to do this is based on downstream banking dependencies and may vary, and is therefore done on a best-efforts basis.

Retries

If a payload cannot be delivered then Crezco will retry using an exponential backoff policy. If the webhook cannot be delivered successfully within 48 hours we will mark your endpoint as inactive and notify you.

All undelivered payloads will be stored for 30 days and replayed to endpoints when they are marked as active again.

Signatures

A signature should be used to verify the webhook payload has been sent from Crezco. The process of computing a signature is:

  • Get the raw UTF8 bytes of the body of the webhook message
  • Get your API Secret. If no secret has been created, use your API Key. Whichever you use, we will refer to it as your "API Secret" from here on out
  • Get the UTF8 bytes of your API Secret
  • Instantiate a HMACSHA256 implementation using the UTF8 bytes of your API Secret as the key
  • Concatenate the bytes of your API Secret to the bytes of the webhook message
  • Compute the HMACSHA256 signature of the concatenated webhook message and API Secret bytes
  • Convert the HMACSHA256 signature to Base64 encoding
  • Compare the signature to the crezco-signature field in the webhook request.
  • If multiple API Secrets are associated with your account, the crezco-signature query parameter will contain a comma separated list of signatures, one for each secret. You should be able to match against one

A sample pseudo-implementation in C# may be:

	var apiKey = "CZSB01ABCDEFGHIJKL15";
	var apiKeyBytes =  Encoding.UTF8.GetBytes(apiKey);
	
	using var hmac = new HMACSHA256(apiKeyBytes);	
	byte[] allBytes = Encoding.UTF8.GetBytes(webhookBody).Concat(apiKeyBytes).ToArray();
	
	var signature = hmac.ComputeHash(allBytes);
	Console.WriteLine(Convert.ToBase64String(signature));

You should verify all incoming webhooks using this method. If the signature does not match you should reply with a 401 (Unauthorized) status code.

Webhook Signature Implementation Testing

As a test vector for your signature implementation given a webhook body:

{
  "Events": [
    {
      "Type": "PayRun",
      "Id": "63fa43a7-d54f-48fb-aa31-3658870e9301",
      "Status": "Completed",
      "Timestamp": "12:34:56T01:01:01.001",
      "OrganisationId": "13fea469-3a23-490c-85ec-4ece15041203",
      "PartnerClientId": "abcd123",
      "EventId": 998,
      "Version": "2023-02-01"
    },
    {
      "Type": "Payable",
      "Id": "48ffcfaa-b081-4cfc-af1d-949efe1d7c4b",
      "Status": "Completed",
      "Timestamp": "12:34:56T01:01:01.001",
      "OrganisationId": "13fea469-3a23-490c-85ec-4ece15041203",
      "PartnerClientId": "abcd123",
      "EventId": 999,
      "Version": "2023-02-01"
    },
  ]
}

and an API Secret:

CZSB01ABCDEFGHIJKL15

The value of your signature should be U00FjfqJiCZHrFFiwdQIIszyVIkwg/9yNXbQonZ+na8=

Testing and Troubleshooting

We recommend the use of a tool such as webhook.site to aid with testing payload receipt from our Sandbox environment. You should be able to capture payloads and replay them to yourself, or craft your own test payloads and signatures.

Please make sure your endpoint is able to accept inbound internet traffic and is not blocked by any firewall or routing rules. If you have any difficulty please reach out to our technical team.

Webhooks and API Versions

Webhooks are created in the context of an API Version. When you call the Register webhook endpoint you will create a webhook for the version of the API that you are currently using (see Versioning for more details on API Versions).

Webhook registrations are triggered by state changes in objects created in the same version. For example if you register a webhook against v1 of the API then it will be triggered for pay runs created with v1 of the API. If you then create a pay run using v2 of the API you will also need to register v2 webhooks as the v1 webhook registration will not be triggered.

Webhook Migration for API Version Changes

When you migrate to a new version of the API you should perform the following steps to migrate your webhooks:

  • Call Register webhook for each of the webhook events that you wish to subscribe to in the new version of the API
  • Ensure that your existing handlers remain running for the maximum lifetime of webhook events from the last pay run created against the prior version
  • (Optional clean up) Call Delete existing webhookfor each webhook for the old version to which you are still subscribed

You may have webhooks registered for multiple versions of the API at any time.