Webhooks for COS
Webhooks events return information about API calls you send. The event returns a resource object that contains relevant details about the subject of each event.
The system typically aggregates event objects every 30 seconds.
EXAMPLE
Core.Account.Opened
webhook event in the extended webhook format.
-
The first half of the webhook event includes information about the webhook event itself.
The
resources
object of the webhook event shows that an account was created. -
The
details
object contains information related to the API call.-
The
accountType
field object shows that the account is a deposit account. -
The
accountNumber
field shows the account number of the created account . -
The
status
field shows that the account is active.
-
Event report
{
"id": "fdsl7c99-mmns-a90b-bms7-7bs9b2mjszkl",
"eventName": "Core.Account.Opened",
"status": "Pending",
"partnerId": "8gj76s99-jhso-89as-nsl8-119nss8ch7ab",
"createdAt": "2022-07-26T03:48:55.969Z",
"lastAttemptedAt": "2022-07-26T04:45:15.128Z",
"resources": [
"core/v1/dda/accounts/2001231231",
],
"details": [
{
"accountNumber": "2001231231",
"accountType": "Deposit",
"customerId": "1dbef48f-0097-42f1-8613-af0300d533f1",
"status": "Active",
"productId": "a7d5415b-071e-4b33-bc0a-afda014e95fd",
"title": "Dim Mak",
"clientIdentifier": null
}
]
}
Event formatting
An event object is delivered in the same standard format and contains the resources it's reporting on.
Our system supports 2 different event formats:
Format |
Description |
Sample |
---|---|---|
Basic |
Use basic format webhook events for any The ID in the resources object (in this example 73da01c7-b85b-4a58-9395-b04900de43cf) corresponds to the Basic events have a small payload and can deliver up to 50k resources at once. |
Copy
Sample response with basic formatting
|
Extended |
We recommend using extended webhooks for all events except for This format returns all the information included in the basic format and a Extended events deliver up to 1k resources at once |
Copy
Sample response with extended formatting
|
Event status
Whenever you receive an event, it is always in Pending
status and refers to the registration status (an event was created but not yet delivered), and not the resource status.
If you want to see if webhooks were delivered successfully, call GET /webhooks/v1/events/{id}
. If the event was delivered successfully you will see status:Success
.
Status |
Description |
---|---|
Pending |
Event has been created. |
Success |
Internal status only. Event was successfully delivered to the registered URL. |
Failed |
Internal status only. We could not deliver the event to the registered URL. See the event logs for more detail on the failure reason. |
Webhook delivery is guaranteed at-least-once. While rare, it's technically possible to receive the same event twice. Your message handlers should account for that edge case and be idempotent.
Event registration
To keep informed of the status of relevant activity in our system, we offer many event notifications for each product. There are several ways to receive event notifications:
-
Push
Webhook events that are reported to a registered partner endpoint (a callback URL).
-
Poll
Events that are reported after a partner polls the events API.
The POST
calls for the registration methods are the same. Make sure to select the correct registration type
, either Push
or Poll
. We recommend that you use Push registration.
Register for webhook event reports (Push)
Use POST /webhooks/v1/registrations
to register the callback URLs where event reports should be delivered.
In this example, your partnerId
identifies you as the entity requesting webhook registration to the eventName:
Core.Account.Opened
, which is a Push
registration. The eventName
is being registered to the callbackUrl:
https://cos.yourcompanysite.com/account-events
.
Sample webhook push registration
{
"partnerId": "8gj76s99-jhso-89as-nsl8-119nss8ch7ab",
"eventName": "Core.Account.Opened",
"type": "Push",
"callbackUrl": "https://cos.yourcompanysite.com/account-events",
"authUsername": "{userName}",
"authPassword": "{password}",
"format": "Basic"
}
To confirm your callback URL is registered, call PUT /v1/registrations{id}/ping
. It simulates a webhook event sent to your callback URL but doesn't include any resources.
Register to Poll for events
Use POST /webhooks/v1/registrations
to register as a partner to poll for event status.
We recommend you poll for events only if you're not able to receive webhooks.
In the example below, your partnerId
identifies you as the entity requesting registration to be able to poll the eventName
: Core.Account.Opened
. Click here for information on the format
.
Sample Poll Registration
{
"partnerId": "8gj76s99-jhso-89as-nsl8-119nss8ch7ab",
"eventName": "Core.Account.Opened",
"type": "Poll",
"format": "Basic"
}
Retrieving registration status
Call GET /webhooks/v1/events/poll
to poll for events.
When you poll the system, the events are sent in status
: Pending
and every event has to be manually acknowledged.
Don't poll more than once every 30 seconds.
In the example below, the eventName
:Core.Account.Opened
polls the deposit account resources
: https://sandbox.crbcos.com/core/v1/dda/accounts/...
to check the registration status.
Poll Event Response
{
"id": "g98sxnbv-9000-nks7-jjsy-xn6554bv9h10",
"eventName": "Core.Account.Opened",
"status": "Pending",
"partnerId": "8gj76s99-jhso-89as-nsl8-119nss8ch7ab",
"createdAt": "2022-11-04T17:12:34.806Z",
"lastAttemptedAt": "2022-11-04T17:12:34.806Z",
"resources": [
"https://sandbox.crbcos.com/core/v1/dda/accounts/1234567890",
"https://sandbox.crbcos.com/core/v1/dda/accounts/1234567891"
],
"isPing": false
}
Attribute | Description |
---|---|
id
|
ID of the event being polled |
eventName
|
Name of the event being polled |
status
|
When polling for an event, the status will always be Pending |
|
Your ID in the CR system. This ID is in GUID format. |
|
When the event was created. |
|
|
|
Elements (such as an account number or an event name) that the event is reporting on. |
|
|
Acknowledging an event
Call POST /webhooks/v1/events/{id}/acknowledge
to acknowledge that you received the event.
Use the id
you received when you checked the event status in this call. When you acknowledge an event, the status
changes from Pending
to Success
.
Deleting a registration
Use the event registration id
you received when you polled the event to delete an event registration.
Event delivery unsuccessful
Monitor the status of your webhook registrations.
If the system can't deliver an event to one of your registrations, it makes several attempts to re-send the event. If we still can't deliver the event after several retries, its registration status changes to Suspended
and we start to queue all your events for your registration. No further attempts are made to deliver previous or future events to this endpoint until your registration returns to an Active status.
When a suspended webhook is restarted, all queued webhook notifications are delivered immediately.
If you get a Suspended
status, review the logs of recent failed events to identify the issue. When the issue is resolved, restart your registration with the PUT /v1/registrations/{id}/restart
webhooks API.
The status transitions to Restarting
. If we can deliver an event successfully the status returns to Active
. When the status returns to Active
we deliver all the queued events from when your registration status was suspended. If we can't successfully deliver at least 1 event, the status returns to Suspended
.
Delivery failure
If there is an event delivery failure, don't delete a registration and re-register for the same event. This prevents you from retrieving any events that were queued for delivery, as well as any events that fired in the time between deletion and re-registration.
Authentication
Our system optionally supports basic authentication on each registration. You can supply an AuthUsername
and AuthPassword
which will be base64 encoded and included as an Authorization header on each webhook you receive.
The preferred security practice is to use webhook signature verification instead of basic authentication.
Signatures
Every webhook is signed with a standard HMAC with SHA256 hash. This provides an added layer of protection from replay attacks. Without a signature, an attacker could intercept a valid payload and retransmit it.
The signature can be found in the event's request header and includes the event timestamp. Our system generates a timestamp and signature each time we send an event to your endpoint. If our system retries an event after a previous failure, we generate a new signature and timestamp for the new delivery attempt. If a timestamp is subsequently changed, the signature is then invalid.
Sample Request Header
cos-signature:t:2019-04-02T11:33:26.6672036-04:00,
v1:adT6JQ7y+fbL2a0uq4infc6VOX+VPyJizRTMSz158Vs=
If you receive an event with an old timestamp we recommend you discard or flag it. The recommended tolerance between timestamp and time of delivery will vary by your application's requirements, but should usually be less than 20 minutes. We do however, recommend special consideration for situations where there has been an extended outage at either party.
-
All signatures are version 1 (v1). Any other schemes besides v1 should ignored.
-
The signature is a standard HMAC with SHA256 hash.
Validating the Signature
-
Extract the timestamp and signature from the cos-signature header.
-
Concatenate the timestamp with the event body with a period in between the two values (as illustrated below).
-
Compute an HMAC with the SHA256 hash function. Use the signing secret (provided by the Integration Team) as the key and use the string created in step #2 as the message. Also be sure to base64 encode the computed hash value.
-
Compare the hash generated in step #3 with the signature extracted from the cos-signature header. If the hash and signature match, this is a valid request from COS.
-
Compare the timestamp to the time received. If the difference exceeds your tolerance for accepting messages, you can reject the message or flag it for further review.
Sample Timestamp and Body Concatenation
2019-04-02T11:33:26.6672036-04:00.{"id":"123","eventName":"Core.Customer.Email.Added","partnerId":"123","createdAt":"2019-04-02T11:33:26-04:00","resources":["core/v1/cm/customers/123"]}
A Node.js script that shows how a webhook signature would typically be validated.
Sample Validation Script
const crypto = require('crypto');
function validateSignature(header, payload, signingSecret) {
let headerParts = header.split(',');
let timestamp = headerParts[0].replace('t:', '');
let signature = headerParts[1].trim().replace('v1:', '');
let secret_buffer = Buffer.from(signingSecret, 'base64');
let hmac = new crypto.createHmac('sha256', secret_buffer);
let hmac_digest = hmac.update(`${timestamp}.${payload}`, 'binary').digest('base64');
console.log(hmac_digest);
return hmac_digest === signature;
}
let payload = '{"id":"e7ead744-d6ff-4521-863d-abab0176f849","eventName":"Core.Transaction.Completed","status":0,"partnerId":"d6b4c661-b38a-46a3-8963-a9a40131eacf","createdAt":"2020-04-28T18:45:14.57-04:00","resources":["core/v1/transactions/6aa7e3b2-3c85-4647-aa6f-abab0176e18b"],"details":[{"transactionId":"6aa7e3b2-3c85-4647-aa6f-abab0176e18b","transactionCode":"Account Transfer","debitSubAccount":"2058112745","debitMasterAccount":"2058112745","debitResult":"OK","creditSubAccount":"2101120877","creditMasterAccount":"2101120877","creditResult":"OK","rail":"Internal","railId":"0","amount":"100"}]}';
let signatureHeader = 't:2020-04-28T18:45:15.6360965-04:00, v1:MvGXdx1O1P8+YjWglbmxAxkrAgVlMglSPpCzsR/Ly/w=';
let secret = 'uVdwwB9HIFZ+5/8nmta5PXu6p1kxZcQmXPCNBRhiVNuKNBhIgth8MvmlD7FYoVfHOmcpHO5QYN/3HHnJ+6TO6Q==';
let result = validateSignature(signatureHeader, payload, secret);
console.log(result);
Reference information
Webhook registration delivery status
Status |
Description |
---|---|
Active |
Everything is OK |
Suspended |
Something went wrong. Several attempts to send events to this registration failed. No further attempts will be made until registration is restarted. |
Restarting |
We are attempting to restart this registration. An event must be successfully transmitted before the status will transition back to Active. |
FAQ
Why is my webhook status Suspended?
Suspended status means that we could not successfully deliver an event to one of your registrations. See Webhooks for COS.
What is the retention period of webhooks?
Currently there is no limitation to the retention period.
What webhook events are available?
All available webhook events can be retrieved via Swagger by calling https://sandbox.crbcos.com/webhooks/swagger/ui/index#!/Meta/Meta_GetAll
.
What is the maximum number of resources included in a single webhook event?
50k for events received in basic format
1k for events in extended format.
How are webhook failures handled?
After a delivery failure, COS will retry 3 additional times after approximately 30 - 60 seconds before your registration updates to a Suspended status. If we still can't deliver the event after several retries, its registration status changes to Suspended and we start to queue all your events for your registration. No further attempts are made to deliver previous or future events until your registration returns to an Active status.
What is the IP address from which COS webhooks are sent?
For sandbox it’s 66.206.202.40 and for production its 66.206.202.41.