Webhooks
How Preczn's event notifications work, and the full catalog of subscribable events.
Webhooks let Preczn notify your system the moment something happens — a transaction is approved, a merchant record changes, a boarding form is completed — instead of you polling our API to find out.
You give us an HTTPS endpoint and a list of events. When one of those events occurs, we send a signed POST request to your endpoint with a JSON body describing what happened.
New to webhooks?Start with Subscribing to Webhooks to create your first subscription, then Receiving and Verifying Webhooks to build the endpoint that handles them.
How delivery works
flowchart TD
A["Something happens in Preczn<br/>(transaction, merchant, loan, or form change)"] --> B{"Any subscriptions match?"}
B -->|"Matches on platform + mode + event type"| C["Build the notification<br/>id, webhookId, eventType, data"]
B -->|No match| Z["Nothing sent"]
C --> D["Sign the body with the<br/>subscription's signing secret"]
D --> E["POST to your endpoint URL"]
E --> F{"2xx response<br/>within 5 seconds?"}
F -->|Yes| G["Success — failure counter reset to 0"]
F -->|No| H["Retry up to 3 times<br/>network errors and 5xx only"]
H --> I{"Still failing?"}
I -->|Yes| J["Failure counter incremented"]
I -->|No| G
J --> K{"25 consecutive failures?"}
K -->|Yes| L["Subscription disabled<br/>+ email to its creator"]
K -->|No| M["Subscription stays active"]
G --> N["Attempt recorded — kept 15 days"]
J --> N
Three rules govern whether a given event reaches a given subscription. All three must be true:
| Rule | Meaning |
|---|---|
| Platform match | The subscription belongs to the same platform as the record that changed. |
| Mode match | A Test-mode subscription only receives Test-mode events; a Live-mode subscription only receives Live-mode events. There is no crossover. |
| Event match | The event type is in the subscription's events list. |
If more than one of your subscriptions matches an event, each one receives its own independent delivery.
Live vs Test modeWebhook subscriptions are scoped to a single mode and cannot span both. If you want the same notifications in both modes, create one subscription in each. See Live vs Test Mode.
Event catalog
Preczn currently supports 14 subscribable events across four domains. These are the exact string values to use in the events array when creating a subscription.
Transactions
| Event | Fires when |
|---|---|
transaction.approved | A transaction is approved by the processor. |
transaction.declined | A transaction is declined by the processor. |
transaction.pending | A transaction is accepted but not yet settled or finalized. |
transaction.errored | A transaction fails due to an error rather than a decline. |
→ Transaction Webhook Payloads
Merchants
| Event | Fires when |
|---|---|
merchant.created | A merchant record is created. |
merchant.updated | A merchant record is modified. |
merchant.deleted | A merchant record is deleted. |
Loans
| Event | Fires when |
|---|---|
loan.created | A loan account is first recorded against a merchant. |
loan.updated | An existing loan account's details or status change. |
Boarding forms
| Event | Fires when |
|---|---|
form.created | A boarding form is created. |
form.started | A merchant completes a section of the form for the first time. |
form.updated | Any change is saved to the form. |
form.completed | The form is submitted and its completion is recorded. |
form.expired | An unfinished form passes its expiration time. |
→ Boarding Form Webhook Payloads
What every notification looks like
Every webhook body shares the same four top-level fields, regardless of event type. Only data changes shape.
{
"id": "what_6k022ss0jj8vp9g85xv1z357m7",
"webhookId": "wh_5jg1dx62za981aqkanv3cd99zh",
"eventType": "transaction.approved",
"data": {}
}See Receiving and Verifying Webhooks for the full field reference, the request headers we send, and how to verify the signature.
Reliability at a glance
| Behavior | Value |
|---|---|
| Request timeout | 5 seconds |
| Retries per notification | Up to 3, with exponential backoff |
| What gets retried | Network and connection errors, and 5xx responses |
| What does not get retried | Any 4xx response |
| Counts as success | Any 2xx response |
| Auto-disable threshold | 25 consecutive failed notifications |
| Delivery history retention | 15 days |
Delivery, Retries, and Failures covers each of these in depth, including what happens when a subscription is disabled and how to bring it back.
Managing subscriptions
You can create and manage subscriptions two ways, and they operate on the same underlying subscriptions — a subscription created in the dashboard is visible and editable over the API, and vice versa.
| Dashboard | API | |
|---|---|---|
| Create, edit, delete subscriptions | Yes | Yes |
| Choose subscribed events | Yes | Yes |
| Set a custom authorization header | Yes | Yes |
| View the signing secret | Yes, any time | Only in the create response |
| Browse delivery history | Yes | No |
| Resend a past notification | Transaction deliveries only | No |
See Subscribing to Webhooks for both paths.
FAQ
Should I use webhooks or poll the API?
Use webhooks. They are the recommended way to track state in Preczn, and polling is not a substitute for them.
Polling means asking repeatedly whether anything changed, so nearly every request returns the same answer as the last one. That costs you latency — you learn about a change only at your next poll — and the request volume grows with your portfolio, because the work scales with the number of records you have to re-read rather than the number of things that actually happened. Some signals are impractical to reach this way at all: detecting form.started or form.expired by polling would mean re-reading every open boarding form on a schedule just to spot the few that moved.
Where polling genuinely helps is reconciliation, not discovery. Reading the API to confirm your stored state matches ours is a sound backstop, and it is exactly what you need after a gap — see recovering from a disabled subscription. Let webhooks tell you what changed; use the API to fetch detail and to verify.
Will one event ever reach the same endpoint twice?
Yes, it can — by two different routes, which matter because they behave differently.
A retry after a timeout may arrive even though your server actually processed the first attempt. It is byte-identical, including the top-level id, so deduplicating on id catches it.
A resend triggered from the dashboard deliberately re-sends a past event, but it is issued a new id while carrying the original eventType and data. Deduplicating on id will not catch that one.
Handle both by making the effect of processing a notification idempotent, not just by filtering identifiers — see Receiving and Verifying Webhooks.
Are webhooks delivered in order?
No. Do not assume ordering between notifications, even for the same record. If you need to know whether a notification reflects the latest state, compare the timestamps inside data (such as modifiedOn) against what you have already stored, and ignore anything older.
Can a Test-mode subscription receive Live events?
No. Mode is matched exactly on every delivery, and a mismatch means nothing is sent. This is deliberate — it prevents test activity from reaching production systems. Subscription IDs make the mode visible: Test subscriptions are prefixed wh_test_, Live subscriptions wh_.
Can I subscribe to every event by leaving the list empty?
No. events is required and each value is validated against the catalog above. To receive everything, list every event explicitly. This is intentional: new event types are never added to existing subscriptions silently, so a future release cannot start sending your endpoint traffic it was not built to handle.
Do webhooks contain cardholder data?
No. Transaction notifications include only the card brand, BIN, and last four digits — never a full card number or CVV. Boarding form notifications carry identifiers, status values, and timestamps only, never the contents of the form or its supporting documents.
Is there an IP range I can allowlist?
Contact your Preczn support team for current egress details. For authenticating that a request genuinely came from Preczn, signature verification is the supported mechanism and is strictly better than IP filtering — see Receiving and Verifying Webhooks.
Updated 4 days ago
