Skip to main content
The decision on a transaction is produced on chmod’s side, after the person has finished the flow on their phone. It reaches your backend in two complementary ways, and it helps to be clear about what each one is for.

The notification

When you open a transaction you can give chmod a URL on your backend. As the transaction moves through its lifecycle — and most importantly when the decision exists — chmod calls that URL. The call is signed. chmod publishes a public key, and every notification carries a timestamp and a signature computed with the matching private key over that timestamp and the transaction id. Your backend checks the signature before doing anything else, and rejects calls whose timestamp is more than a few minutes old — a valid signature never expires on its own, so without the time check a captured call could be replayed later. Expect the same notification to arrive more than once now and then, and occasionally out of order. That is the nature of delivery over the internet, and your handler should treat a repeat as a no-op rather than applying it twice.
The notification tells you that something happened. It is not the place to read the verdict from. Treat it as a doorbell, not as a letter.

The fetch

Whenever your backend wants the truth about a transaction, it asks chmod for it by id. The answer is the full transaction: where it is in its lifecycle, when each step happened, and — once analysis has finished — the decision with every finding behind it and everything that was extracted from the document and the selfie. This is what you act on. Because your backend requested it over its own authenticated connection, it cannot have been forged or replayed by anyone else, whatever arrived at your webhook. The fetch is also your safety net. A reconciliation job that periodically asks about transactions that never reached a final state will catch anything a lost notification would otherwise have left hanging.

Putting the two together

1

The notification arrives

Verify the signature and the timestamp. Acknowledge immediately; do the work out of band so a slow database never makes chmod think the delivery failed.
2

Fetch the transaction

Read the decision and the findings from the fetched transaction, never from the notification body.
3

Act

Approve, reject, or escalate. Update the person. Record what you need.

What to keep

The full result contains document images, personal details and device signals — personal data under every privacy regime you operate in. Keep the decision, the finding codes, the transaction id and the time it was reached; that is enough for an audit trail, analytics and support conversations. Fetch the full result again by id on the rare occasions you need it, rather than storing it.

What the person sees

By the time the decision exists, the person has already closed the flow and is looking at your app, which told them their document was being reviewed. Now you tell them the outcome — in your own words. The findings carry messages written for your operators. They say precisely which check failed, which is more than a genuine user needs and exactly what a fraudster wants. Map each finding to copy of your own: actionable guidance for the recoverable ones (“try again in better light”), a neutral message for the suspicious ones (“we couldn’t verify your identity; our team will be in touch”). See Decisions and issues for the buckets.

The reference

The notification’s headers, the verification steps with code, and the full structure of a fetched transaction are in the API Reference:

Webhooks

The request, the signature, and how to verify it.

Get transaction

Fetch a transaction by id.

Reading a result

Every field the transaction returns.