Webhooks
Receive real-time notifications when important events happen during the loan lifecycle. Get instant updates on application status, document signing, funding progress, and more.
Webhooks
Webhooks let you receive automatic notifications when important events happen in Thrive. Instead of repeatedly checking for updates, we'll send the information directly to your system the moment something changes.
Getting Started with Webhooks
You can manage webhook subscriptions directly through our API endpoints, or contact your Thrive representative for assistance. See Managing Webhook Subscriptions below for API details.
What You'll Receive
When an event occurs, Thrive sends an HTTP POST request to your endpoint with a JSON payload containing the event details. All payloads include:
| Field | Description |
|---|---|
application_id | The unique identifier for the loan application |
status | The current status or state change |
timestamp | When the event occurred (ISO 8601 format) |
Additional fields are included depending on the event type.
Available Events
Application Events
These events notify you when a loan application's status or terms change.
application.status.update
application.status.updateSent when the application status changes (e.g., Approved, Declined, Pending Review).
{
"timestamp": "2025-01-15T10:30:00.000Z",
"status": "Approved",
"application_id": "c4ff1199-a135-4739-b110-91f7c1bf9d2f",
"data": {
"approved_offer": {
"term": "60",
"interest_rate": "8.99",
"borrower_max_approved_amount": "25000.00",
"project_max_approved_amount": "30000.00",
"max_amount": "25000.00",
"approved_amount": "25000.00",
"merchant_fee_percentage": "7.00"
}
}
}Offer Fields Explained:
| Field | Description |
|---|---|
term | Loan term in months |
interest_rate | Annual interest rate (percentage) |
borrower_max_approved_amount | Maximum amount the borrower qualifies for |
project_max_approved_amount | Maximum amount allowed for the project |
max_amount | The lesser of borrower and project maximums |
approved_amount | The actual approved loan amount |
merchant_fee_percentage | Your merchant fee as a percentage |
application.amount.update
application.amount.updateSent when the approved loan amount changes after initial approval.
The payload follows the same structure as application.status.update.
application.offer.update
application.offer.updateSent when loan terms change (rate, term, or fees) after a hard credit pull. This payload includes both the previous and updated offer so you can see exactly what changed.
{
"timestamp": "2025-01-15T10:30:00.000Z",
"status": "Terms Updated",
"application_id": "c4ff1199-a135-4739-b110-91f7c1bf9d2f",
"data": {
"previous_approved_offer": {
"term": "60",
"interest_rate": "9.99",
"borrower_max_approved_amount": "20000.00",
"project_max_approved_amount": "25000.00",
"approved_amount": "20000.00",
"merchant_fee_percentage": "7.00"
},
"updated_approved_offer": {
"term": "60",
"interest_rate": "8.99",
"borrower_max_approved_amount": "25000.00",
"project_max_approved_amount": "30000.00",
"approved_amount": "25000.00",
"merchant_fee_percentage": "6.50"
}
}
}Document Events
These events track the loan document signing process.
document.sent
document.sentSent when loan documents are delivered to the borrower for e-signature.
{
"timestamp": "2025-01-15T10:30:00.000Z",
"status": "DOCUMENT_SENT",
"application_id": "c4ff1199-a135-4739-b110-91f7c1bf9d2f"
}document.signed
document.signedSent when the borrower completes signing all required loan documents.
{
"timestamp": "2025-01-15T10:30:00.000Z",
"status": "DOCUMENT_SIGNED",
"application_id": "c4ff1199-a135-4739-b110-91f7c1bf9d2f"
}Disbursement Events
These events track the funding process from request to settlement.
disbursement.funding.status-changed
disbursement.funding.status-changedSent when the funding status changes. You'll receive this event when funding is requested and again when it begins processing.
{
"timestamp": "2025-01-15T10:30:00.000Z",
"status": "FUNDING_REQUESTED",
"application_id": "c4ff1199-a135-4739-b110-91f7c1bf9d2f"
}Possible Status Values:
| Status | Meaning |
|---|---|
FUNDING_REQUESTED | A funding request has been submitted |
FUNDING_PROCESSING | The funding request is being processed |
disbursement.funding.settled
disbursement.funding.settledSent when funds have been successfully transferred.
{
"timestamp": "2025-01-15T10:30:00.000Z",
"status": "FUNDING_SETTLED",
"application_id": "c4ff1199-a135-4739-b110-91f7c1bf9d2f"
}Task Events
These events notify you when tasks are created or updated on loan applications.
task.created
task.createdSent when a new task is added to an application (e.g., document upload required).
{
"timestamp": "2025-01-15T10:30:00.000Z",
"status": "Pending",
"application_id": "c4ff1199-a135-4739-b110-91f7c1bf9d2f",
"task_title": "Upload proof of income"
}task.updated
task.updatedSent when a task's status changes (e.g., completed, cancelled).
{
"timestamp": "2025-01-15T10:30:00.000Z",
"status": "Completed",
"application_id": "c4ff1199-a135-4739-b110-91f7c1bf9d2f",
"task_title": "Upload proof of income"
}Setting Up Your Endpoint
Endpoint Requirements
Your webhook endpoint must meet these requirements:
- HTTPS only - We do not send webhooks to HTTP URLs
- Publicly accessible - Must be reachable from the internet
- Responds quickly - Return a response within 30 seconds
- Returns 2xx status - Any 2xx status code confirms successful receipt
Choosing Your Events
When setting up webhooks with your Thrive representative, you can choose to receive:
- Specific events - Only the events you need (e.g., just
disbursement.funding.settled) - All events - Every event type listed above
Most integrations subscribe to these key events:
| Use Case | Recommended Events |
|---|---|
| Track funding progress | disbursement.funding.status-changed, disbursement.funding.settled |
| Monitor full loan lifecycle | application.status.update, document.signed, disbursement.funding.settled |
| Stay informed of everything | All events |
Handling Webhooks
Responding to Webhooks
Always return a 200 OK response as quickly as possible. This confirms you received the webhook. If you need to do additional processing, do it after sending the response.
app.post('/webhooks/thrive', (req, res) => {
// Respond immediately
res.status(200).json({ received: true });
// Then process the webhook
processWebhook(req.body);
});Processing Different Event Types
You can identify the event type by examining the payload:
app.post('/webhooks/thrive', (req, res) => {
const { status, application_id, data, task_title } = req.body;
// Task events include task_title
if (task_title) {
console.log(`Task "${task_title}" is now: ${status}`);
}
// Application events include offer data
else if (data?.approved_offer || data?.updated_approved_offer) {
console.log(`Application ${application_id} updated: ${status}`);
}
// Document events have DOCUMENT_ prefix
else if (status.startsWith('DOCUMENT_')) {
console.log(`Document status: ${status}`);
}
// Disbursement events have FUNDING_ prefix
else if (status.startsWith('FUNDING_')) {
console.log(`Funding status: ${status}`);
}
res.status(200).json({ received: true });
});Securing Your Endpoint
HMAC Signature Verification (Recommended)
If you choose HMAC authentication, we'll sign each webhook using a shared secret. The signature is included in the x-hmac-signature header.
To verify the signature, compute the HMAC-SHA256 hash of the raw request body using your secret, then compare it to the signature we sent:
const crypto = require('crypto');
function verifySignature(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload, 'utf8')
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature, 'hex'),
Buffer.from(expected, 'hex')
);
}
app.post('/webhooks/thrive', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-hmac-signature'];
if (!verifySignature(req.body.toString(), signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Signature valid - process the webhook
const payload = JSON.parse(req.body);
// ...
});import hmac
import hashlib
def verify_signature(payload: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode('utf-8'),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)Bearer Token Authentication
Alternatively, we can include a Bearer token in the Authorization header. Your endpoint should verify this token matches the one provided during setup.
Handling Retries and Duplicates
Automatic Retries
If your endpoint doesn't respond with a 2xx status code (or times out), we'll retry the webhook up to 3 times. Make sure your endpoint is reliable to avoid missing events.
Duplicate Handling
Because of retries, you may occasionally receive the same webhook more than once. To handle this, track which webhooks you've already processed using the combination of application_id, status, and timestamp:
const processed = new Set();
app.post('/webhooks/thrive', (req, res) => {
const { application_id, status, timestamp } = req.body;
const key = `${application_id}:${status}:${timestamp}`;
if (processed.has(key)) {
// Already handled this webhook
return res.status(200).json({ received: true });
}
processed.add(key);
// Process the webhook...
res.status(200).json({ received: true });
});For production systems, store processed webhook keys in a database with an expiration time (e.g., 24 hours).
Testing Your Integration
Local Development
Use a tool like ngrok to expose your local development server:
ngrok http 3000This gives you a public HTTPS URL that forwards to your local machine. Share this URL with your Thrive representative for testing.
Sample Test Payloads
Use these sample payloads to test your webhook handler:
Application Approved:
curl -X POST https://your-endpoint.com/webhooks/thrive \
-H "Content-Type: application/json" \
-d '{
"timestamp": "2025-01-15T10:30:00.000Z",
"status": "Approved",
"application_id": "test-app-123",
"data": {
"approved_offer": {
"term": "60",
"interest_rate": "8.99",
"approved_amount": "25000.00",
"merchant_fee_percentage": "7.00"
}
}
}'Documents Signed:
curl -X POST https://your-endpoint.com/webhooks/thrive \
-H "Content-Type: application/json" \
-d '{
"timestamp": "2025-01-15T10:30:00.000Z",
"status": "DOCUMENT_SIGNED",
"application_id": "test-app-123"
}'Funding Settled:
curl -X POST https://your-endpoint.com/webhooks/thrive \
-H "Content-Type: application/json" \
-d '{
"timestamp": "2025-01-15T10:30:00.000Z",
"status": "FUNDING_SETTLED",
"application_id": "test-app-123"
}'Quick Reference
All Event Types
| Event | When It's Sent |
|---|---|
application.status.update | Application status changes (Approved, Declined, etc.) |
application.amount.update | Approved loan amount is modified |
application.offer.update | Loan terms change after hard pull |
document.sent | Documents sent to borrower for signing |
document.signed | Borrower completes document signing |
disbursement.funding.status-changed | Funding requested or processing |
disbursement.funding.settled | Funds successfully transferred |
task.created | New task added to application |
task.updated | Task status changes |
All Status Values
| Category | Possible Values |
|---|---|
| Document | DOCUMENT_SENT, DOCUMENT_SIGNED |
| Funding | FUNDING_REQUESTED, FUNDING_PROCESSING, FUNDING_SETTLED |
Managing Webhook Subscriptions
You can create, update, and manage webhook subscriptions programmatically using our API. This gives you full control over your webhook configuration without needing to contact support.
Authentication
All webhook subscription endpoints require the standard Thrive API authentication headers:
| Header | Description |
|---|---|
x-thrive-client-id | Your API client ID |
x-thrive-client-secret | Your API client secret |
x-thrive-merchant-uid | Your merchant unique identifier |
Available Endpoints
| Method | Endpoint | Description |
|---|---|---|
GET | /public/v1/webhook-subscriptions | List all your webhook subscriptions |
GET | /public/v1/webhook-subscriptions/event-types | List available event types |
GET | /public/v1/webhook-subscriptions/events | View webhook delivery history |
GET | /public/v1/webhook-subscriptions/{id} | Get a specific subscription |
POST | /public/v1/webhook-subscriptions | Create a new subscription |
PUT | /public/v1/webhook-subscriptions/{id} | Update an existing subscription |
DELETE | /public/v1/webhook-subscriptions/{id} | Delete a subscription |
Creating a Subscription
curl -X POST https://api.thrive.com/public/v1/webhook-subscriptions \
-H "Content-Type: application/json" \
-H "x-thrive-client-id: your-client-id" \
-H "x-thrive-client-secret: your-client-secret" \
-H "x-thrive-merchant-uid: your-merchant-uid" \
-d '{
"name": "Production Webhook",
"description": "Receives funding status updates",
"url": "https://api.example.com/webhooks/thrive",
"secret": "whsec_your_secret_here",
"subscriptions": [
"disbursement.funding.status-changed",
"disbursement.funding.settled",
"application.status.update"
],
"enabled": true,
"auth_type": "hmac-sha256"
}'Subscription Fields
| Field | Required | Description |
|---|---|---|
name | Yes | Human-readable name (max 255 characters) |
description | No | Optional description (max 1000 characters) |
url | Yes | HTTPS URL to receive webhook notifications |
secret | No | Secret for HMAC signing or Bearer token auth |
subscriptions | Yes | Array of event types to subscribe to |
enabled | Yes | Whether the subscription is active |
auth_type | No | Authentication method: none, hmac-sha256, or bearer (default: none) |
Viewing Delivery History
Track your webhook deliveries to debug issues and monitor delivery success:
curl -X GET "https://api.thrive.com/public/v1/webhook-subscriptions/events?limit=50&status=failed" \
-H "x-thrive-client-id: your-client-id" \
-H "x-thrive-client-secret: your-client-secret" \
-H "x-thrive-merchant-uid: your-merchant-uid"Query Parameters:
| Parameter | Description |
|---|---|
limit | Maximum events to return (1-100, default: 50) |
start_date | Filter events after this date (ISO 8601) |
end_date | Filter events before this date (ISO 8601) |
event_type | Filter by specific event type |
status | Filter by success or failed |
The response includes the full payload that was sent, response time, HTTP status, retry count, and any error messages from your endpoint.
Need Help?
Contact your Thrive representative to:
- Get assistance with webhook configuration
- Troubleshoot delivery issues
- Request test webhooks
- Discuss custom integration requirements
We're here to help you integrate successfully.
Updated about 7 hours ago
