Loading...
Loading...
The easiest way to manage Webhook subscriptions is in the Quiltt Dashboard. You can also interact with your Webhook subscriptions via API, using the /webhooks/subscriptions endpoint.
The following endpoint can be used to create a new Webhook subscription via API:
POSThttps://api.quiltt.io/v1/webhooks/subscriptionsCopy endpoint URL to clipboardThe following HTTP headers must be provided:
Authorization: Bearer <API_SECRET_KEY>
Content-Type: application/json
Requests must include a JSON body with the name of your subscription, a list of eventTypes, and the targetUrl that should receive the webhooks.
{
"name": "Connection Created",
"targetUrl": "https://example.com/webhooks/quiltt",
"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", "connection.synced.successful"]
}'
{
"id": "wh_14OYtCKXE7UeehJCdfPuV6e",
"name": "ACME Webhook",
"targetUrl": "https://example.com/webhooks/quiltt",
"eventTypes": ["account.verified", "connection.synced.successful"],
"disabled": false
}
When a Webhook event is triggered, Quiltt will send a POST request to the targetUrl specified in the subscription. The request will include a JSON payload with the details of the event.
The following examples show how you could parse the received JSON payload and decide how to process the data of each event, based on its type.
require 'sinatra'
require 'json'
QUILTT_WEBHOOK_SECRET = '<QUILTT_WEBHOOK_SUBSCRIPTION_SECRET>'
QUILTT_WEBHOOK_VERSION = 1
QUILTT_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'].to_i) < (Time.now.to_i - QUILTT_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', QUILTT_WEBHOOK_SECRET,
"#{QUILTT_WEBHOOK_VERSION}#{timestamp}#{payload}"
)
# @note Abort if payload fails signature verification
if request['Quiltt-Signature'] != signature
halt 204
end
# Parse verified webhook payload
webhook = JSON.parse(payload)
# Handle each event
webhook['events'].each do |event|
case event['type']
when /^connection\.synced\.successful(\.\w+)*/ # Connection has synced successfully
connection = event['record']
puts "Connection with ID #{connection['id']} has synced successfully!"
# Fetch the latest data on associated accounts or transactions
# ...
when 'account.verified' # Account has been verified for payment processing
account = event['record']
account_id = account['id']
puts "Account with ID #{account_id} is ready for payment processing!"
# Fetch the ACH numbers to pass to your payment provider
endpoint = URI("https://api.quiltt.io/v1/accounts/#{account_id}/ach_numbers")
response = Net::HTTP.get_response(endpoint, Authorization: "Bearer #{ENV['QUILTT_API_KEY_SECRET']}")
else
puts "Unhandled event #{event['type']}"
end
end
status 204
end
import express, { Request, Response } from 'express';
import crypto from 'crypto';
import https from 'https';
const app = express();
const PORT = 3000;
const QUILTT_WEBHOOK_SECRET = '<QUILTT_WEBHOOK_SUBSCRIPTION_SECRET>';
const QUILTT_WEBHOOK_VERSION = 1;
const QUILTT_WEBHOOK_WINDOW = 300; // Five minutes
app.use(express.json());
interface WebhookEvent {
type: string;
record: any; // Use a more specific type if the structure of record is known
}
app.post('/quiltt_webhook', (req: Request, res: Response) => {
const timestamp = req.header('Quiltt-Timestamp');
if (!timestamp || (Date.now() / 1000 - Number(timestamp)) > QUILTT_WEBHOOK_WINDOW) {
return res.status(204).send();
}
const payload = JSON.stringify(req.body);
const signature = crypto.createHmac('sha256', QUILTT_WEBHOOK_SECRET)
.update(`${QUILTT_WEBHOOK_VERSION}${timestamp}${payload}`)
.digest('base64');
if (req.header('Quiltt-Signature') !== signature) {
return res.status(204).send();
}
const webhook: { events: WebhookEvent[] } = req.body;
webhook.events.forEach(event => {
if (event.type.startsWith('connection.synced.successful')) {
const connection = event.record;
console.log(`Connection with ID ${connection.id} has synced successfully!`);
// Additional logic to fetch latest data...
} else if (event.type === 'account.verified') {
const account = event.record;
const account_id = account.id;
console.log(`Account with ID ${account_id} is ready for payment processing!`);
const options = {
hostname: 'api.quiltt.io',
path: `/v1/accounts/${account_id}/ach_numbers`,
method: 'GET',
headers: { Authorization: `Bearer ${process.env.QUILTT_API_KEY_SECRET}` },
};
https.get(options, response => {
// Handle the HTTP response
// Note: Add error handling and response parsing as needed.
});
} else {
console.log(`Unhandled event ${event.type}`);
}
});
res.status(204).send();
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
from flask import Flask, request, jsonify
from datetime import datetime
import hmac
import hashlib
import base64
import requests
app = Flask(__name__)
QUILTT_WEBHOOK_SECRET = '<QUILTT_WEBHOOK_SUBSCRIPTION_SECRET>'
QUILTT_WEBHOOK_VERSION = '1'
QUILTT_WEBHOOK_WINDOW = 300 # Five minutes
@app.route('/quiltt_webhook', methods=['POST'])
def quiltt_webhook():
timestamp = request.headers.get('Quiltt-Timestamp')
if not timestamp or (datetime.now().timestamp() - int(timestamp)) > QUILTT_WEBHOOK_WINDOW:
return '', 204
payload = request.get_data(as_text=True)
signature = hmac.new(
QUILTT_WEBHOOK_SECRET.encode(),
f'{QUILTT_WEBHOOK_VERSION}{timestamp}{payload}'.encode(),
hashlib.sha256
).digest()
encoded_signature = base64.b64encode(signature).decode()
if request.headers.get('Quiltt-Signature') != encoded_signature:
return '', 204
webhook = request.json
for event in webhook.get('events', []):
if event['type'].startswith('connection.synced.successful'):
connection = event['record']
print(f"Connection with ID {connection['id']} has synced successfully!")
# Additional logic to fetch latest data...
elif event['type'] == 'account.verified':
account = event['record']
account_id = account['id']
print(f"Account with ID {account_id} is ready for payment processing!")
response = requests.get(f"https://api.quiltt.io/v1/accounts/{account_id}/ach_numbers", headers={"Authorization": f"Bearer {YOUR_QUILTT_API_KEY_SECRET}"})
# Ensure to handle the response properly here
else:
print(f"Unhandled event {event['type']}")
return '', 204
if __name__ == '__main__':
app.run(debug=True)
<?php
$QUILTT_WEBHOOK_SECRET = '<QUILTT_WEBHOOK_SUBSCRIPTION_SECRET>';
$QUILTT_WEBHOOK_VERSION = '1';
$QUILTT_WEBHOOK_WINDOW = 300; // Five minutes
// Ensure the request is a POST
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
exit;
}
// Verify timestamp is present and within the window
$timestamp = isset($_SERVER['HTTP_QUILTT_TIMESTAMP']) ? $_SERVER['HTTP_QUILTT_TIMESTAMP'] : 0;
if (time() - (int)$timestamp > $QUILTT_WEBHOOK_WINDOW) {
http_response_code(204);
exit;
}
// Read the payload
$payload = file_get_contents('php://input');
// Validate signature
$signature = base64_encode(
hash_hmac(
'sha256',
$QUILTT_WEBHOOK_VERSION . $timestamp . $payload,
$QUILTT_WEBHOOK_SECRET,
true
)
);
if ($_SERVER['HTTP_QUILTT_SIGNATURE'] !== $signature) {
http_response_code(204);
exit;
}
// Parse the payload
$webhook = json_decode($payload, true);
// Handle the events
foreach ($webhook['events'] as $event) {
if (strpos($event['type'], 'connection.synced.successful') === 0) {
$connection = $event['record'];
error_log("Connection with ID {$connection['id']} has synced successfully!");
// Additional logic here...
} elseif ($event['type'] === 'account.verified') {
$account = $event['record'];
$account_id = $account['id'];
error_log("Account with ID {$account_id} is ready for payment processing!");
// Use cURL to fetch ACH numbers
$ch = curl_init("https://api.quiltt.io/v1/accounts/{$account_id}/ach_numbers");
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: Bearer YOUR_QUILTT_API_KEY_SECRET'));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
// Handle the response
} else {
error_log("Unhandled event {$event['type']}");
}
}
http_response_code(204);