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

# Events

> Everything Truscan can notify you about, and the shape of each payload.

Subscribe to events when you [create an endpoint](/webhooks/overview). An
endpoint only receives the types it asked for. The live list is served from
`GET /api/webhooks/events`.

## Billing

<AccordionGroup>
  <Accordion title="credits.low" icon="triangle-exclamation">
    Your balance has fallen below **\$1.00**. Fires once on the request that
    crosses the threshold, not on every request after it, so topping up is the
    only thing that arms it again.

    ```json theme={null}
    { "balance": "$0.84", "threshold": "$1.00" }
    ```
  </Accordion>

  <Accordion title="credits.exhausted" icon="circle-xmark">
    A request was refused because the balance could not cover it. The request
    that triggered this also returned `402`.

    ```json theme={null}
    { "balance": "$0.00", "attempted_cost": "$0.007" }
    ```
  </Accordion>

  <Accordion title="payment.succeeded" icon="circle-check">
    A top-up settled and the credit has been applied.

    ```json theme={null}
    {
      "payment_id": "pay_3f8a2c...",
      "amount_cents": 2000,
      "credits": "$20.00"
    }
    ```
  </Accordion>

  <Accordion title="payment.failed" icon="circle-xmark">
    A top-up did not complete. No credit was applied.

    ```json theme={null}
    { "payment_id": "pay_3f8a2c...", "amount_cents": 2000 }
    ```
  </Accordion>
</AccordionGroup>

## API keys

<AccordionGroup>
  <Accordion title="key.created" icon="key">
    A new API key was issued. The secret is never included.

    ```json theme={null}
    { "key_id": "key_7b2e...", "name": "Production server", "last_four": "8f3a" }
    ```
  </Accordion>

  <Accordion title="key.revoked" icon="ban">
    A key was revoked and stopped working immediately.

    ```json theme={null}
    { "key_id": "key_7b2e..." }
    ```
  </Accordion>
</AccordionGroup>

<Tip>
  These two are useful as an audit trail. Forward them to your own logging and
  you have a record of every credential issued against the account.
</Tip>

## Search

<AccordionGroup>
  <Accordion title="search.completed" icon="magnifying-glass">
    A search finished.

    ```json theme={null}
    {
      "request_id": "srch_2a9f...",
      "query": "how does the TLS 1.3 handshake work",
      "tier": "instant",
      "results": 10,
      "cached": false
    }
    ```
  </Accordion>
</AccordionGroup>

<Warning>
  `search.completed` fires on **every** search, so a busy account will generate
  a high volume of deliveries. Searches are synchronous, which means the caller
  already has the results when the HTTP response returns. Subscribe to this
  only if something other than the caller needs to know.
</Warning>

## Envelope

Every payload has the same four fields regardless of type.

| Field        | Type   | Notes                                         |
| ------------ | ------ | --------------------------------------------- |
| `id`         | string | `evt_` prefixed. Unique per event.            |
| `type`       | string | One of the types above, or `ping` for a test. |
| `created_at` | string | RFC 3339, UTC.                                |
| `data`       | object | Shape depends on `type`.                      |

<Note>
  New event types and new fields inside `data` are added over time. Ignore
  what you do not recognise rather than failing on it.
</Note>

## Ordering and duplicates

Deliveries are not ordered. A retried event can arrive after a newer one, so
do not infer sequence from arrival time. Use `created_at` when order matters.

Each event is delivered to each endpoint once, and a retry reuses the same
`id`. Treat `id` as an idempotency key and ignore one you have already
processed.
