Skip to content

Webhooks

Webhooks provide real-time notifications when events occur in your workspace. Instead of polling the API for changes, Colleckt delivers HTTP POST requests to your configured endpoints when verification lifecycle events fire.

Overview

Webhooks are useful for:

  • Receiving notifications when a verification status changes
  • Updating your internal systems when a decision is made
  • Triggering downstream workflows (e.g., sending emails, updating databases)
  • Logging verification activity in your own systems

How Webhooks Work

Loading diagram...

Key Concepts

ConceptDescription
WebhookA registered endpoint URL that receives HTTP POST requests when events occur
EventA verification lifecycle event that triggers delivery. You subscribe one or more events to each webhook
Signing SecretA unique 64-character HMAC secret, auto-generated per webhook. Used to sign every payload so you can verify it came from Colleckt
DeliveryThe actual HTTP POST request sent to your webhook URL. Includes the event payload, signature header, and any custom headers you configured

Quickstart

Set up your first webhook in under 5 minutes.

1. Create a Webhook

Navigate to Webhooks in the workspace dashboard and click New Webhook.

FieldRequiredDescription
URLYesThe endpoint that will receive webhook payloads. Use HTTPS in production
EventsYesOne or more events to subscribe to. See Events
ActiveNoEnable or disable the webhook without deleting it (default: enabled)
SSL VerificationNoVerify the target server's SSL certificate (default: enabled).
Custom HeadersNoAdditional HTTP headers sent with every delivery
AuthenticationNoCredentials sent in the Authorization header. This is useful for API key-based authentication on your endpoint.

2. Save Your Signing Secret

After creation, the signing secret is displayed exactly once. Copy it immediately and store it in a secure location (secrets manager, environment variable, or vault).

WARNING

The signing secret is not exposed through the API or dashboard after creation. If lost, you must delete the webhook and create a new one.

3. Test Your Integration

  • Use the sandbox environment to test webhook delivery before going live
  • Check the Webhooks tab on the verification detail page to confirm delivery
  • Verify the HMAC signature on every received payload (see Verifying Signatures)

Events

Colleckt fires webhook events at key points in a verification's lifecycle.

Actively Dispatched Events

The following events trigger a webhook delivery to all active endpoints that subscribe to them:

EventCodeFires When
Verification Startedverification.startedA new verification is created and the end-user session begins
Verification Submittedverification.submittedThe end-user submits all required documents for processing
Verification Finishedverification.finishedA verification reaches a terminal status — approved or rejected
Verification Canceledverification.canceledA verification is canceled before completion

Verification Lifecycle

Loading diagram...

Webhooks fire at the four transition points above.

Double Check Status

When a verification enters a Double Check state (requires manual review), the verification.finished webhook is not sent. The webhook is only delivered when the verification reaches a terminal approved or rejected state.

Registered Events (Not Currently Dispatched)

The following event codes exist in the system and can be selected when configuring a webhook, but they are not currently dispatched as webhook deliveries:

EventCodeStatus
Document Uploadeddocument.uploadedRegistered, not dispatched
Document Canceleddocument.canceledRegistered, not dispatched
Decision Madedecision.madeRegistered, not dispatched
Decision Canceleddecision.canceledRegistered, not dispatched

If you select these events, no webhook will be sent when they occur. This may change in a future release.

Managing Webhooks

View Webhooks

The webhooks list shows all configured webhooks with their URL, active status, subscribed events, and header count.

Update Webhook

You can modify the URL, events, authentication, custom headers, SSL verification, and active status.

The signing secret cannot be changed. If you need a new secret, delete the webhook and create a new one.

Delete Webhook

Deleting a webhook removes it permanently. Any undelivered events for this webhook are discarded.

Webhooks Delivery

Delivery Format

Each webhook delivery is an HTTP POST request:

HeaderValue
Content-Typeapplication/json
SignatureHMAC-SHA256 hex digest of the raw request body
Custom headersAny headers you configured on the webhook
AuthorizationIf authentication is configured on the webhook

Payload

json
{
  "event": "verification.finished",
  "data": {
    "id": "ver_xxxxx",
    "url": "https://{workspace}.colleckt.io/spa/v3/.../process",
    "qr_code": "https://{workspace}.colleckt.io/qr/...",
    "flow": "usps-1583",
    "expected_data": { /* ... */ },
    "extracted_data": { /* ... */ },
    "vendor_reference": "REF-001",
    "vendor_state": "Wyoming",
    "documents": [ /* ... */ ],
    "comments": [ /* ... */ ],
    "status_label": "Approved",
    "created_at": "2026-06-14T02:14:13.000000Z",
    "updated_at": "2026-06-14T02:16:42.000000Z"
  }
}

See Webhook Payloads for complete field descriptions and examples for every event type.

Retry Logic

If your endpoint does not return a 2xx status code within 10 seconds, delivery is retried:

PropertyValue
Maximum attempts3
Timeout per attempt10 seconds
Backoff strategyExponential (delay increases between attempts)

Webhook Logs

Every delivery attempt is recorded in the webhooks tab, accessible from the verification detail page.

From the tab you can:

  • View details of the full request and response
  • Resend a failed webhook from the stored payload
  • Mark as solved to acknowledge investigation is complete

Manual Resends

Manual resends from the webhook logs are delivered without an HMAC signature and without SSL verification. The original signature cannot be recomputed from the stored log payload. Verify manual resends through endpoint authentication or sender IP validation.

Webhook Security

Signature Verification

Each webhook request includes a Signature header. You must verify this signature to confirm the request came from Colleckt and was not tampered with during transit.

text
Signature: {hex_encoded_hmac_sha256_signature}

The signature is the lowercase hexadecimal output of:

text
HMAC-SHA256(raw_request_body, signing_secret)

Getting the Raw Request Body

A common pitfall is parsing the JSON body and re-encoding it, which changes key order, whitespace, or encoding. Always use the raw, unparsed request body.

Verification Steps

  1. Get the raw request body as a string (do not parse and re-encode)
  2. Get the Signature header value (64-character lowercase hex string)
  3. Compute HMAC-SHA256 of the raw body using your webhook's signing secret
  4. Convert the HMAC output to hexadecimal (lowercase)
  5. Compare with the Signature header using a constant-time comparison

Code Examples

javascript
const crypto = require('crypto');

function verifyWebhookSignature(rawBody, signatureHeader, signingSecret) {
  const expected = crypto
    .createHmac('sha256', signingSecret)
    .update(rawBody)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signatureHeader, 'hex'),
    Buffer.from(expected, 'hex')
  );
}
php
function verifyWebhookSignature(string $rawBody, string $signatureHeader, string $signingSecret): bool {
    $expected = hash_hmac('sha256', $rawBody, $signingSecret);
    return hash_equals($expected, $signatureHeader);
}
python
import hmac
import hashlib

def verify_webhook_signature(raw_body: str, signature_header: str, signing_secret: str) -> bool:
    expected = hmac.new(
        signing_secret.encode('utf-8'),
        raw_body.encode('utf-8'),
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature_header)
go
import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
)

func VerifyWebhookSignature(rawBody, signatureHeader, signingSecret string) bool {
    h := hmac.New(sha256.New, []byte(signingSecret))
    h.Write([]byte(rawBody))
    expected := hex.EncodeToString(h.Sum(nil))
    return hmac.Equal([]byte(expected), []byte(signatureHeader))
}
ruby
require 'openssl'

def verify_webhook_signature(raw_body, signature_header, signing_secret)
  expected = OpenSSL::HMAC.hexdigest(
    'SHA256',
    signing_secret,
    raw_body
  )
  ActiveSupport::SecurityUtils.secure_compare(expected, signature_header)
end

Common Pitfalls

  • Use the raw body bytes, not the parsed JSON object. Re-serializing JSON changes whitespace, key order, and encoding — all of which break the signature. Capture the raw body before any JSON parsing.
  • Use constant-time comparison (hash_equals, hmac.compare_digest, timingSafeEqual). Never use == — naive comparison leaks bytes through timing side channels.
  • Treat the signing secret as a credential. Never put it in source code, never log it, never include it in error responses.
  • Validate before processing. If the signature does not match, return 401 Unauthorized and do not process the payload.

Test Vector

Verify your signature implementation using a known payload:

text
Secret:     abc123
Payload:    {"event":"verification.started","data":{"id":"ver_test"}}
Signature:  6f8603bad35dd38facbb351d53c5d666ed36a01b6da270d998f883f527932b33

Compute the HMAC-SHA256 hex digest of the payload string using your secret. The result must match the signature above. Changing any character in the payload or secret produces a completely different hash.

Express.js Full Example

javascript
const crypto = require('crypto');
const express = require('express');

const app = express();

app.use('/webhooks', express.raw({ type: 'application/json' }));

app.post('/webhooks', (req, res) => {
  const rawBody = req.body.toString();
  const signature = req.headers['signature'];
  const signingSecret = process.env.COLLECKT_WEBHOOK_SECRET;

  if (!verifyWebhookSignature(rawBody, signature, signingSecret)) {
    return res.status(401).send('Invalid signature');
  }

  const event = JSON.parse(rawBody);
  console.log('Received event:', event.event);

  res.status(200).send('OK');
});

SSL Verification

Each webhook has a verify_ssl flag (default: true). When enabled, Colleckt validates the target server's SSL certificate on every delivery.

SettingBehavior
true (default)Validates the SSL certificate. Rejects delivery if the certificate is invalid, self-signed, or expired
falseSkips SSL validation. Intended for testing with self-signed certificates only

Security Risk

Disabling SSL verification exposes your integration to man-in-the-middle attacks. Only disable for testing.

Best Practices

  • Respond quickly — Return a 2xx status within the 10-second timeout. Defer processing to a background job if needed
  • Handle duplicates — Delivery is at-least-once. You may receive the same event multiple times. Use idempotency keys or event deduplication
  • Verify signatures — Always verify the Signature header. This is the only way to confirm the request came from Colleckt
  • Process asynchronously — Don't perform long-running operations in your webhook handler. Enqueue work for later processing
  • Log all deliveries — Keep a record of webhook events for debugging and audit purposes
  • Use the sandbox — Test your webhook integration in the sandbox environment before going live
  • Store the signing secret securely — It is shown only once at creation. Use a secrets manager (AWS Secrets Manager, Vault, 1Password)
  • Monitor failed deliveries — Configure email subscriptions for failed webhooks and check logs regularly

Common Issues

IssueCauseSolution
Endpoint unreachableNetwork error, DNS failure, or firewallVerify the URL is accessible from the public internet
Invalid signatureWrong secret, re-encoded body, wrong encodingUse raw request body, HMAC hex output, and the correct signing secret
SSL verification failedInvalid, self-signed, or expired certificateUse a valid SSL certificate, or disable verification for testing only
TimeoutEndpoint takes longer than 10 secondsOptimize your endpoint or delegate work to a background job
4xx/5xx responseApplication error on your endpointCheck your endpoint logs for the error
Webhook not receivedInactive webhook, wrong URL, event not selectedVerify the webhook is active, the URL is correct, and events are subscribed
No verification.finished eventVerification is in Double Check statusAwait manual review. The finished event fires after a human approves or rejects

Built for virtual address providers requiring USPS 1583 compliance.