> ## Documentation Index
> Fetch the complete documentation index at: https://docs.authsignal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# challenge.log_created

> A record of a challenge-related event such as an OTP being sent or verified. Sent in batches for SIEM/data lake forwarding.

Records granular challenge lifecycle events such as OTPs being sent, verified, expired, or rate-limited. Pair with [`action.log_created`](/advanced-usage/webhooks/action-log-created) for a full audit trail.

These webhooks are asynchronous and delivered in batches of up to 500 events, after your tenant's challenge token duration (typically 15 minutes). Delivery is at-least-once, so de-duplicate using the envelope `id`.

Configure the webhook URL for log events in [tenant settings](https://portal.authsignal.com/organisations/tenants/settings).

## Payload

<ParamField path="tenantId" type="string" required>
  The ID of the tenant that the event occurred within.
</ParamField>

<ParamField path="userId" type="string" required>
  The ID of the user that the action was triggered by.
</ParamField>

<ParamField path="actionCode" type="string" required>
  The action being evaluated (e.g. `login`, `withdrawal`).
</ParamField>

<ParamField path="idempotencyKey" type="string" required>
  Unique per action instance.
</ParamField>

<ParamField path="createdAt" type="string" required>
  When this challenge event occurred.
</ParamField>

<ParamField path="type" type="string" required>
  The event type. See [Challenge event types](#challenge-event-types) below for the full list.
</ParamField>

<ParamField path="verificationMethod" type="string">
  The verification method involved (e.g. `EMAIL_OTP`, `SMS`, `PASSKEY`).
</ParamField>

<ParamField path="email" type="string">
  Email address involved in the event (for email-channel events).
</ParamField>

<ParamField path="phoneNumber" type="string">
  Phone number involved in the event (for SMS/WhatsApp-channel events).
</ParamField>

<ParamField path="errorDescription" type="string">
  Human-readable error summary for `*_FAILED` events.
</ParamField>

<ParamField path="statusCode" type="string">
  Upstream HTTP status code for downstream-delivery failure events.
</ParamField>

<ParamField path="data" type="object">
  Additional structured fields. Omitted if empty.
</ParamField>

## Challenge event types

A non-exhaustive list of the most commonly seen event types.

**Email OTP**: `EMAIL_OTP_SENT`, `EMAIL_OTP_CODE_VALID`, `EMAIL_OTP_INVALID_OR_EXPIRED`, `EMAIL_OTP_MAX_ATTEMPTS_EXCEEDED`, `EMAIL_OTP_RATE_LIMIT_EXCEEDED`, `EMAIL_OTP_SEND_DOWNSTREAM_FAILED`

**Email magic link**: `EMAIL_MAGIC_LINK_SENT`, `EMAIL_MAGIC_LINK_INVALID_OR_EXPIRED`, `EMAIL_MAGIC_LINK_RATE_LIMIT_EXCEEDED`, `EMAIL_MAGIC_LINK_SEND_DOWNSTREAM_FAILED`

**SMS**: `SMS_SENT`, `SMS_DELIVERED`, `SMS_NOT_DELIVERED`, `SMS_CODE_VALID`, `SMS_CODE_INVALID_OR_EXPIRED`, `SMS_MAX_ATTEMPTS_EXCEEDED`, `SMS_RATE_LIMIT_EXCEEDED`, `SMS_SEND_DOWNSTREAM_FAILED`

**WhatsApp**: `WHATSAPP_SENT`, `WHATSAPP_CODE_VALID`, `WHATSAPP_CODE_INVALID_OR_EXPIRED`, `WHATSAPP_MAX_ATTEMPTS_EXCEEDED`, `WHATSAPP_RATE_LIMIT_EXCEEDED`, `WHATSAPP_SEND_DOWNSTREAM_FAILED`

**TOTP / authenticator app**: `TOTP_CODE_VALID`, `TOTP_CODE_INVALID_OR_EXPIRED`, `TOTP_MAX_ATTEMPTS_EXCEEDED`

**Push**: `PUSH_SENT`

<ResponseExample>
  ```json challenge.log_created theme={null}
  {
    "version": 1,
    "id": "ffffffff-ffff-ffff-ffff-ffffffffffff",
    "source": "https://authsignal.com",
    "time": "2026-04-22T01:10:20.939Z",
    "tenantId": "dddddddd-dddd-dddd-dddd-dddddddddddd",
    "type": "challenge.log_created",
    "record": {
      "tenantId": "dddddddd-dddd-dddd-dddd-dddddddddddd",
      "userId": "user_abc",
      "actionCode": "login",
      "idempotencyKey": "bb51e6b9-a7f8-4f03-8044-2940ae574236",
      "createdAt": "2026-04-22T01:10:20.939Z",
      "type": "EMAIL_OTP_SENT",
      "verificationMethod": "EMAIL_OTP",
      "email": "alice@example.com"
    }
  }
  ```
</ResponseExample>
