Webhooks
Webhooks enable you to react to changes in our systems without having to poll for data.
Quiltt will notify your system in real time when a specific event has happened. Example events are when a Profile is created, updated or deleted, or when a Connection is synced or enters an error state.
Link to this section#How we use Webhooks
We provide multiple event types you can subscribe to. When relevant events occur, Quiltt will send a notification to the subscribed endpoint via HTTPS. The notification contains a JSON payload with the event types and the events that have occurred. This allows you to execute actions in your system based on changes in Quiltt.
Link to this section#How to manage Webhooks
You can manage your Webhooks in the Quiltt Dashboard, or via the API, using the /webhooks/subscriptions
endpoint.
Link to this section#Event Types
Below are some of the events you can subscribe to::
Type | Description |
---|---|
profile | All Profile-related events. |
profile.created | A Profile has been created. |
connection | All Connection-related events. |
connection.synced.successful | A Connection has synced successfully. |
connection.synced.errored.repairable | A Connection has entered an error that must be resolved using the Reconnect flow |
account.verified | An Account has been successfully verified and ACH numbers are now available via API. |
Each event payload will return information about the relevant data model and associated Profile. For example, the connection.created
event will include information about the created Connection, along with the associated Profile.
You can find the full list of event types and schemas in the Admin API Reference.
Link to this section#How to Subscribe to a Webhook via API
You can subscribe to events by sending a POST request to our webhooks subscriptions endpoint:
POSThttps://api.quiltt.io/v1/webhooks/subscriptions
Requests must include the following HTTP headers:
Authorization: Bearer <API_SECRET_KEY>
Content-Type: application/json
Requests must include a JSON body with the name of your subscription, a list of event types, and the target URL that should receive the webhooks.
{
"name": "Connection Created",
"targetUrl": "https://example.com/quiltt_webhook",
"eventTypes": ["connection.created"]
}
Here is an example request that will create a subscription to account.verified
events.
curl --request POST \
--url 'https://api.quiltt.io/v1/webhooks/subscriptions' \
--header 'Authorization: Bearer <API_SECRET_KEY>' \
--header 'Content-Type: application/json' \
--data-raw '{
"name": "Account Verified",
"targetUrl": "https://example.com/webhooks/quiltt",
"eventTypes": ["account.verified"]
}'
Successful responses will return a 201
HTTP response code.
Link to this section#How to Receive a Webhook
When subscribed events occur, Quiltt will send a POST request to your targetUrl
, with a JSON payload.
Your endpoint should respond back with a 2xx
HTTP response code to indicate that you've successfully processed the payload. In Production environments, Quiltt will retry sending the request several times until a 2xx
response is received, using an exponential backoff between attempts.
The JSON payload will contain the relevant data about the event(s) that triggered the webhook.
Link to this section#Webhook Payload
The webhook payload includes a list of eventTypes
and a list of events
.
Property | Type | Description |
---|---|---|
environment | objectrequired | Information about the Environment. |
eventTypes | array of stringsrequired | The types of events included in the Payload. |
events | array of objectsrequired | The events included in this Payload. |
Each event is structured as an object with an id
, type
, and a record
object.
Property | Type | Description |
---|---|---|
id | stringrequired | The ID of the Event. |
type | stringrequired | The type of Event that occurred. |
profile | object | The Profile associated with the Event. |
record | object | The record associated with the Event. |
See an example of the JSON payload below:
{
"environment": {
"id": "env_12uGLpOocVGvQYY9sFsOC6",
"name": "Production",
"mode": "PRODUCTION",
"metadata": null
},
"eventTypes": ["connection.synced.successful"],
"events": [
{
"id": "evt_12sDfIGkY96vVvNvTqNfn9",
"type": "connection.synced.successful",
"profile": {
"id": "p_12uGLpPexyTkZCcJJntSjb",
"uuid": "018a72f8-5434-7262-a029-a186fb0c5f33",
"metadata": null
},
"record": {
"id": "conn_12uGLpQUjSjdQqpIYoEVdQ",
"status": "SYNCED",
"metadata": null,
"createdAt": "2023-09-08T04:06:32Z",
"updatedAt": "2023-10-03T18:33:03Z"
}
}
]
}
Link to this section#Webhook Verification
Webhooks are provided with a timestamp and a HMAC256 Signature, with a per subscription key, to allow you to verify that each message is issued by Quiltt, is intended for you, is received unmodified, and is not being repeated.
To verify the message is valid:
- Ensure the Unix Epoch time
Quiltt-Timestamp
is current (within 5 minutes of current time in UTC) - Validate
Quiltt-Signature
matches a Base64 encoded HMAC-SHA256 ofversion+timestamp+payload
.- We are currently using version
1
.
- We are currently using version
Link to this section#Sample Implementation
The following example shows how you could parse the received JSON payload and decide how to process the data of each event, based on its type
. This example is using Ruby, but the logic will be similar in your language of choice.
require 'sinatra'
require 'json'
WEBHOOK_SECRET = '<WEBHOOK_SUBSCRIPTION_SECRET>'
WEBHOOK_VERSION = 1
WEBHOOK_WINDOW = 300 # Five minutes
# Using Sinatra
post '/quiltt_webhook' do
# Ensure the Unix Epoch time `Quiltt-Timestamp` is current (within 5 minutes)
if (timestamp = request['Quiltt-Timestamp']) < (Time.now.to_i - WEBHOOK_WINDOW)
halt 204
end
# Validate `Quiltt-Signature` matches a Base64 encoded HMAC-SHA256 of version+timestamp+payload.
payload = request.body.read
signature = OpenSSL::HMAC.base64digest('SHA256', WEBHOOK_SECRET, "#{WEBHOOK_VERSION}#{timestamp}#{payload}")
if request['Quiltt-Signature'] != signature
halt 204
end
# @note Only parse after payload is trusted by signature
webhook = JSON.parse(payload)
webhook['events'].each do |event|
# Optional: Ensure Message is Unique
# You may do this by either caching and blocking via event id. We only resend messages on failed delivery.
case event['type']
when 'connection.synced.successful'
connection = event['record'] # contains the Connection data
puts "Connection with ID #{connection['id']} has synced successfully!"
# Call the Quiltt API to fetch the latest data on associated accounts or accounts.
when 'account.verified'
account = event['record'] # contains the Account data
puts "Account with ID #{connection['id']} is ready for payment processing!"
# Call the Quiltt API to fetch the ACH numbers to send to your payment provider
else
puts "Unhandled event #{event['type']}"
end
end
status 204
end
Link to this section#Error Handling
In the event of a failed delivery, webhooks will automatically retry up to 3 times per attempted delivery, followed by up to 25 times redelivery attemps, with an exponential backoff between attempts. This is designed to handle both random network delivery errors and service outages on the receivers end.
Note that the redelivery behavior only enabled in production mode and will not function in non-production environments.
Link to this section#API Reference
See the Webhooks API Reference for full documentation of the subscription endpoint and the JSON payload we send to you.