Skip to content

Webhooks: one decision, three places

The app gets the decision first, so the customer sees the right next step at once. The same decision then reaches your FRM, case manager or SIEM as an event, with the same reasons, and the decision log keeps it. Your FRM stays in charge; DeepID feeds it.

Names and fields are illustrative and agreed in the sandbox before any contract.

On this page

One decision, three places

One coached payment, as it reached each place. The times are the story’s: a 41-minute call, a payee added 3 minutes before the payment.

  1. 12:12
    A video call begins.

    A man in uniform tells Ananya a crime is linked to her identity and that she must stay on camera.

    Her phone
  2. 12:48
    She opens the app. login.attempt returns allow.

    Her own phone, the bound SIM, no code sent. The session the SDK reads from here carries the call that is already 36 minutes old.

    Her app and DeepID
  3. 12:50
    She shares her screen and adds the payee. payee.add returns cool_off.

    An account 2 days old, linked to 14 others. The app tells her she can send up to ₹10,000 to it for 12 hours.

    Her app and DeepID
  4. 12:53:34
    She starts a payment of ₹96,000. payment.initiate returns hold.

    The app shows the message and sends nothing to the rail: “Payment paused. Your money hasn’t left your account. We’ll call you on +91 •••• 3210.”

    Her app
  5. 12:53:34
    decision.created reaches your FRM.

    The same decision id, the same four reasons (ACTIVE_CALL, SCREEN_SHARED, DICTATION_PAUSES, PAYEE_MULE_LINKED) and the queue scam-callback. Your case manager opens the case under the id.

    Your FRM and case manager
  6. 12:53:34
    The decision log keeps it.

    The reasons, the message as shown, the policy (retail, version 14) and the time, for the analyst and the audit.

    The decision log
  7. After
    Your team calls Ananya on +91 •••• 3210, her registered number.

    The money never left. The decision, its reasons and the call-back are one record, under one id.

    Your call-back team

The event

The event carries the decision, not a summary of it. Your FRM sees the same reasons and the same queue the app saw, under the same id.

To your FRM

POST /hooks/deepid

POST /hooks/deepid HTTP/1.1
Content-Type: application/json

{
  "type": "decision.created",
  "data": {
    "decision_id": "dec_7q2_118",
    "event": "payment.initiate",
    "session": "ses_8f2c91ab",
    "customer": "cus_4821",
    "action": "hold",
    "reasons": [
      "ACTIVE_CALL",
      "SCREEN_SHARED",
      "DICTATION_PAUSES",
      "PAYEE_MULE_LINKED"
    ],
    "message": {
      "key": "payment_paused_callback",
      "shown": true
    },
    "queue": "scam-callback",
    "policy": { "id": "retail", "version": 14 },
    "created_at": "2026-10-22T12:53:34Z"
  }
}
Each field of the event and what it carries
FieldCarries
typedecision.created, for every decision. Other event types are agreed in the sandbox.
data.decision_idThe decision’s id, the same one the app received. The key for everything downstream.
data.eventThe moment the app called at.
data.sessionThe app session the decision was read against.
data.customerYour customer id, as the app passed it. Never a name.
data.actionThe action the app was told to take.
data.reasonsThe reason codes, risk first.
data.messageWhich customer message was shown, by key, and that it was shown.
data.queueThe queue a person should work, or null.
data.policyThe policy and version that made the decision.
data.created_atWhen the decision was made, in UTC.

Where it goes

  • Your FRM

    Keeps its own rules, queues and case management. DeepID adds the signals it never receives today: the call, the shared screen, the dictation pauses, the payee’s links. Nothing is replaced.

  • Your case manager

    Opens a case when the decision names a queue, such as a call back, under the decision id, so the call-back team reads the same reasons the customer’s message was written from.

  • Your SIEM

    Receives the device and session signals for the security team: emulators, tampered devices, remote access and screen sharing, beside your other events.

  • The decision log

    Keeps every decision with its reasons, the message shown and the policy version, for audit.

Handling events

Act on the event in your backend rather than on what the app reports. Treat data.decision_id as the key: a repeated delivery is stored once and opens no second case. The handler below does both.

Your backend

hooks.ts

// Act on what DeepID sent, not on what the app
// reports. The decision id is the key: a repeated
// delivery is stored once and opens no second case.
app.post("/hooks/deepid", async (req, res) => {
  const { type, data } = req.body
  if (type !== "decision.created") {
    return res.sendStatus(200)
  }

  const fresh = await decisions.put(
    data.decision_id,
    data,
  )
  if (fresh && data.queue) {
    await cases.open(data.queue, data)
  }

  res.sendStatus(200)
})

When a service needs the decision before the event arrives, it can ask for it by id, server to server.

Your backend

Request

GET /v1/decisions/dec_7q2_118
Authorization: Bearer <server-key>

How events are delivered, signed and retried, and the endpoints and headers your gateway will see, are agreed in the sandbox with your platform team.

The decision log

The decision log is the audit record: every decision, its reasons, the message as the customer read it and the policy version that applied. A complaint, a regulator’s question or an internal review starts from one id and reads one record. How long the log and the signed face-check records are kept is settled in writing with your security team before a pilot, as the security page sets out.

Wire one moment in the sandbox, before any contract.

Sign-up or login end to end, with the decision back in the app and as an event, so your engineers see the shape of it before anyone signs anything.