TryMellon
Navigation

Webhook event catalog

All webhook events emitted by tryMellon, with payload shapes and emission triggers.

Webhook event catalog

tryMellon delivers events to the webhook_url configured per application. All events share an envelope; only data varies.

Envelope

{
  "id": "evt_…",
  "type": "session.revoked",
  "created_at": "2026-04-15T15:00:00.000Z",
  "application_id": "uuid",
  "tenant_id": "uuid",
  "data": { "…event-specific…": "…" }
}

The full payload is signed — see Signature verification.

Event types

EventWhen emitted
application.secret_rotatedSuccessful rotation of the application’s client_secret (manual or scheduled).
session.revokedA session was administratively revoked (admin action, security trigger, or DELETE /v1/sessions/:id).
session.logoutThe user logged out from their session (SDK logout() or POST /v1/sessions/:id/logout).
user.lockedA user was hard-locked (10 failed auth attempts in 24h).
credential.revokedA passkey credential was revoked by the user or admin.
identifier.linkedAn email or wallet identifier is verified and linked to a user (F1).
identifier.unlinkedAn identifier is removed from a user (F1).
recovery.enrollment.issuedA B2B recovery enrollment ticket was issued (your backend called POST /v1/users/:external_user_id/recovery/enroll).
recovery.enrollment.completedThe user completed the recovery enrollment URL; all prior credentials were revoked atomically and a new passkey was registered.

Subscription: today every application receives the full catalog. Per-event opt-in toggles are on the F0 follow-up roadmap.

Payloads

application.secret_rotated

{
  "type": "application.secret_rotated",
  "data": {
    "rotated_by": "user_…",
    "previous_secret_expires_at": "2026-04-15T15:14:00.000Z"
  }
}

session.revoked

{
  "type": "session.revoked",
  "data": {
    "session_id": "sess_…",
    "tenant_id": "uuid",
    "application_id": "uuid",
    "user_id": "user_…",
    "external_user_id": "your-user-123",
    "revoked_by": "user_…",
    "revoked_at": "2026-04-15T15:00:00.000Z",
    "reason": "admin_revoked"
  }
}
FieldTypeNotes
session_idstringThe revoked session id.
tenant_id / application_idstringRedundant with envelope; kept inside data for parsers that only consume data.
user_id / external_user_idstring | nullnull when the session predates user binding (anonymous bootstrap).
revoked_bystring | nullMaintainer userId of the human that triggered the revocation (dashboard, IDE). null for raw S2S admin Basic Auth (DELETE /v1/sessions/:id) — the responsible application is the envelope application_id.
revoked_atstring (ISO 8601)Wall-clock revocation timestamp.
reasonstringDefault "admin_revoked". Callers can override via the request body to convey domain-specific causes ("compromise_response", "password_reset", …). Free-form string — keep your own integration enum disciplined.

session.logout

{
  "type": "session.logout",
  "data": {
    "session_id": "sess_…",
    "tenant_id": "uuid",
    "application_id": "uuid",
    "user_id": "user_…",
    "external_user_id": "your-user-123",
    "logged_out_at": "2026-04-15T15:00:00.000Z"
  }
}
FieldTypeNotes
user_id / external_user_idstring | nullnull for sessions that were not yet bound to a user when logout fired (rare).
logged_out_atstring (ISO 8601)Wall-clock logout timestamp.

user.locked

{
  "type": "user.locked",
  "data": {
    "tenant_id": "uuid",
    "application_id": "uuid",
    "user_id": "user_…",
    "external_user_id": "your-user-123",
    "locked_until": "2026-04-16T15:00:00.000Z",
    "locked_at": "2026-04-15T15:00:00.000Z",
    "lockout_level": "hard",
    "reason": "too_many_failed_attempts"
  }
}
FieldTypeNotes
locked_untilstring (ISO 8601)When the lockout ends. Compute “try again at” UI from this.
locked_atstring (ISO 8601)When the lockout started.
lockout_level"hard"Today only hard (24 h) is webhook-emitted. Soft 30-min lockouts are not surfaced to integrators because they self-heal.
reason"too_many_failed_attempts"Stable literal. Reserved for future expansion.

credential.revoked

{
  "type": "credential.revoked",
  "data": {
    "credential_id": "cred_…",
    "user_id": "user_…",
    "external_user_id": "your-user-123",
    "revoked_by": "user"
  }
}

Identity linking events (F1)

identifier.linked

Emitted when a user successfully links and verifies an email or wallet address.

FieldTypeDescription
user_idstringUser who linked the identifier
identifier_idstringLinked identifier ID
type"email" | "wallet" | "custom"Identifier type
valuestringThe identifier value (email address or wallet address)

identifier.unlinked

Emitted when an identifier is removed from a user.

FieldTypeDescription
user_idstringUser who unlinked the identifier
identifier_idstringUnlinked identifier ID
type"email" | "wallet" | "custom"Identifier type
valuestringThe identifier value

B2B recovery events (F0)

Fired by the B2B recovery enrollment flow (ADR-045). See B2B account recovery.

recovery.enrollment.issued

Emitted when your backend successfully issues a recovery enrollment ticket via POST /v1/users/:external_user_id/recovery/enroll. The enrollment_url is not included — it carries a live ticket and is log-leakable; integrators reconstruct it locally.

FieldTypeDescription
user_idstringTryMellon user ID receiving recovery
external_user_idstringYour external user ID
ticket_idstringSingle-use enrollment ticket ID
context_hashstringSHA-256 context hash bound to the ticket (64 hex)
expires_atstringISO 8601 — ticket TTL (15 min – 7 days, configurable)
issued_atstringISO 8601 — issuance timestamp

recovery.enrollment.completed

Emitted when the user opens the enrollment URL and finishes passkey registration. All previously registered credentials for the user are revoked atomically before this event fires; a new session token is issued immediately after.

FieldTypeDescription
user_idstringTryMellon user ID
ticket_idstringThe consumed enrollment ticket ID
credential_idstringID of the newly registered passkey
reason"b2b_enrollment"Fixed literal — disambiguates from self-service recovery paths
completed_atstringISO 8601 — completion timestamp

Delivery semantics

  • At-least-once. Network blips can produce duplicates. Use the envelope id as your idempotency key.
  • Retries. Failed deliveries (non-2xx) are retried with exponential backoff up to 24 hours.
  • Manual retry. POST /v1/webhooks/deliveries/:deliveryId/retry.
  • History. GET /v1/webhooks/deliveries?application_id=…&event_type=….