Skip to main content

Intake Events

Triple emits events during and at the end of an intake session, via two channels:

  • window.postMessage from the intake iframe to the parent page. Use these for in-app UX (progress indicators, success redirects).
  • Webhooks to your backend. Use these for durable business logic (creating the dispute record, triggering downstream workflows).

Both channels emit the same logical events, but you'll typically want webhooks for anything that must not be lost if the browser closes.

Beta

Event names and payload fields below are under active development and may change before general availability.

postMessage events

All messages from the intake iframe have this shape:

{
type: string, // e.g. "triple.intake.completed"
intake_session_id: string,
...payload
}

Always verify event.origin === 'https://intake.triple.app' before trusting a message.

triple.intake.opened

Fired once when the cardholder loads the flow.

{
"type": "triple.intake.opened",
"intake_session_id": "is_a1b2c3",
"mode": "form"
}

triple.intake.step_changed

Fired each time the cardholder moves to a new step (page in the form, message in the chatbot). Useful for analytics.

{
"type": "triple.intake.step_changed",
"intake_session_id": "is_a1b2c3",
"step_id": "cardholder_statement",
"step_index": 2,
"step_total": 5
}

triple.intake.completed

Fired when the cardholder finishes the flow and an evaluation has been created. This is the event most integrations care about.

{
"type": "triple.intake.completed",
"intake_session_id": "is_a1b2c3",
"evaluation_id": "eval_7d9e1f"
}

triple.intake.abandoned

Fired if the cardholder closes the iframe or stays idle past the session's inactivity threshold. You may offer to resume via a fresh session.

{
"type": "triple.intake.abandoned",
"intake_session_id": "is_a1b2c3",
"reason": "timeout"
}

triple.intake.error

Fired if something goes wrong inside the flow — an upload failure, an unrecoverable validation mismatch, etc.

{
"type": "triple.intake.error",
"intake_session_id": "is_a1b2c3",
"code": "evidence_upload_failed",
"message": "The cardholder's upload could not be stored."
}

Webhook events

The same events (minus the noisy UX ones) are delivered to your webhook endpoint. See Webhooks for configuration and signature verification.

EventWhen
intake.session.completedCardholder finished; evaluation is queued/available
intake.session.abandonedSession timed out or was closed without completion

Example payload for intake.session.completed:

{
"event": "intake.session.completed",
"data": {
"intake_session_id": "is_a1b2c3",
"evaluation_id": "eval_7d9e1f",
"cardholder": {
"external_id": "cust_9f3a2"
},
"occurred_at": "2026-04-23T16:24:11Z"
}
}

Deciding which channel to use

  • Need to close a modal / redirect the cardholder? Use postMessage.
  • Need to write to a database / notify an ops team? Use webhooks.
  • Want both? Do both. They are independent — delivery of one doesn't affect the other.