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

# Send a test event to a webhook endpoint

> Send a signed webhook.test event now and return the result inline.

Send a signed `webhook.test` event now and return the result inline.

Use this to verify signature verification end to end before relying on real
events. The attempt is recorded in the endpoint's delivery log but is
purely diagnostic: it never counts toward the failure streak, never
auto-disables the endpoint and is never retried. A receiver that rejects
the event still returns 200 here with `ok: false` and the status code it
responded with, because the CALL succeeded even though the DELIVERY did
not; a disabled endpoint is still testable.

## Authorization

This route requires the `write` scope.

A missing or invalid credential returns 401 [`authentication_error`](/errors/authentication_error). A valid credential without the scope returns 403 [`permission_denied`](/errors/permission_denied), and the problem body names the exact scope required.

## Headers

These are request conventions the contract does not declare as parameters, so they do not appear in the schema tables below.

| Header            | Applies        | What it does                                                                                        |
| ----------------- | -------------- | --------------------------------------------------------------------------------------------------- |
| `X-Exo-API-Key`   | Required       | Your Exo API key, `exo_<env>_<token>`. `Authorization: Bearer exo_...` is accepted as an alternate. |
| `X-Exo-Subject`   | Not applicable | This route is not subject-scoped.                                                                   |
| `Idempotency-Key` | Not honoured   | This route does not replay: a diagnostic send is meant to happen every time you ask for it.         |
| `X-Request-Id`    | Response       | Returned on every response, including `204`s. Quote it in a support request.                        |

## Success responses

| Status | Meaning             |
| ------ | ------------------- |
| `200`  | Successful Response |

## Errors

| Status | Code                                                   | When                                                           |
| ------ | ------------------------------------------------------ | -------------------------------------------------------------- |
| `400`  | [`invalid_request`](/errors/invalid_request)           | Malformed request, for example an invalid cursor.              |
| `401`  | [`authentication_error`](/errors/authentication_error) | Missing or invalid credentials.                                |
| `403`  | [`permission_denied`](/errors/permission_denied)       | Missing scope, or an unprovisioned subject selector.           |
| `404`  | [`not_found`](/errors/not_found)                       | The resource does not exist, or is not visible to this caller. |
| `409`  | [`conflict`](/errors/conflict)                         | A conflict with the current state of the resource.             |
| `422`  | [`validation_error`](/errors/validation_error)         | The request was understood but failed field validation.        |
| `429`  | [`rate_limit_exceeded`](/errors/rate_limit_exceeded)   | Rate limit exceeded. Retry after the Retry-After interval.     |
| `503`  | [`service_degraded`](/errors/service_degraded)         | A dependency is temporarily unavailable. Safe to retry.        |

Every error is an RFC 9457 `application/problem+json` body carrying a stable `code`, a `requestId`, and a `suggestedAction` where Exo has one. See [Errors](/platform/errors).

## Notes

* **A test never counts against the endpoint.** It is recorded in the delivery log but never contributes to the failure streak, never auto-disables and is never retried.
* **A receiver that rejects the event still returns 200 here**, with `ok: false` and the status it responded with, because the call succeeded even though the delivery did not.


## OpenAPI

````yaml openapi.json POST /v1/webhooks/{webhook_id}/test
openapi: 3.1.0
info:
  contact:
    name: Exo
    url: https://get-exo.com/
  description: >-
    The Exo public developer API: ingest content, retrieve identity-conditioned
    context, and read the knowledge graph. Authenticate every request with an
    Exo API key, either as the X-Exo-API-Key header or as Authorization: Bearer
    exo_... . Errors follow RFC 9457 problem+json with a stable snake_case code
    on every body.
  title: Exo API
  version: 1.0.0
servers:
  - url: https://api.get-exo.com
security:
  - ApiKeyHeader: []
  - BearerAuth: []
tags:
  - name: retrieve
    x-group: Retrieval
  - name: search
    x-group: Search
  - name: ingest
    x-group: Ingestion
  - name: jobs
    x-group: Jobs
  - name: subjects
    x-group: Subjects
  - name: recall
    x-group: Recall
  - name: graph
    x-group: Graph
  - name: insights
    x-group: Contradictions and proposals
  - name: condition
    x-group: Condition
  - name: brain
    x-group: Brain
  - name: sessions
    x-group: Coding sessions
  - name: connectors
    x-group: Connectors
  - name: events
    x-group: Events and webhooks
  - name: meta
    x-group: Identity
  - name: keys
    x-group: Keys and sandbox
  - name: usage
    x-group: Usage
  - name: settings
    x-group: Settings
  - name: exports
    x-group: Exports
  - name: team
    x-group: Team
  - name: admin
    x-group: Account and purge
paths:
  /v1/webhooks/{webhook_id}/test:
    post:
      tags:
        - events
      summary: Send a test event to a webhook endpoint
      description: >-
        Send a signed ``webhook.test`` event now and return the result inline.


        Use this to verify signature verification end to end before relying on
        real

        events. The attempt is recorded in the endpoint's delivery log but is

        purely diagnostic: it never counts toward the failure streak, never

        auto-disables the endpoint and is never retried. A receiver that rejects

        the event still returns 200 here with ``ok: false`` and the status code
        it

        responded with, because the CALL succeeded even though the DELIVERY did

        not; a disabled endpoint is still testable.
      operationId: testWebhook
      parameters:
        - description: The webhook endpoint id returned at registration.
          in: path
          name: webhook_id
          required: true
          schema:
            description: The webhook endpoint id returned at registration.
            format: uuid
            title: Webhook Id
            type: string
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookTestResult'
          description: Successful Response
        '400':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
          description: Malformed request, for example an invalid cursor.
        '401':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
          description: Missing or invalid credentials
        '403':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
          description: Missing scope or unprovisioned subject
        '404':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
          description: No such webhook endpoint in this organization
        '409':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
          description: Conflict, for example a duplicate in-flight idempotent request.
        '422':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
          description: Validation Error
        '429':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
          description: Rate limit exceeded
        '503':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
          description: A dependency is unavailable
components:
  schemas:
    WebhookTestResult:
      description: 'POST /v1/webhooks/{id}/test: the delivery outcome, inline.'
      properties:
        attempt:
          title: Attempt
          type: integer
        attemptedAt:
          anyOf:
            - format: date-time
              type: string
            - type: 'null'
          title: Attemptedat
        deliveryId:
          title: Deliveryid
          type: string
        durationMs:
          anyOf:
            - type: integer
            - type: 'null'
          title: Durationms
        error:
          anyOf:
            - type: string
            - type: 'null'
          title: Error
        eventType:
          title: Eventtype
          type: string
        ok:
          title: Ok
          type: boolean
        responseSnippet:
          anyOf:
            - type: string
            - type: 'null'
          title: Responsesnippet
        statusCode:
          anyOf:
            - type: integer
            - type: 'null'
          title: Statuscode
        webhookId:
          title: Webhookid
          type: string
      required:
        - deliveryId
        - eventType
        - attempt
        - ok
        - webhookId
      title: WebhookTestResult
      type: object
    Problem:
      description: |-
        RFC 9457 problem+json envelope (spec D9), documented in OpenAPI.

        Invariant: ``code`` equals the tail of the ``type`` URI
        (``https://docs.get-exo.com/errors/<code>``).
      properties:
        code:
          title: Code
          type: string
        detail:
          title: Detail
          type: string
        documentationUrl:
          anyOf:
            - type: string
            - type: 'null'
          title: Documentationurl
        errors:
          anyOf:
            - items:
                $ref: '#/components/schemas/FieldViolation'
              type: array
            - type: 'null'
          title: Errors
        requestId:
          default: ''
          title: Requestid
          type: string
        status:
          title: Status
          type: integer
        suggestedAction:
          anyOf:
            - type: string
            - type: 'null'
          title: Suggestedaction
        title:
          title: Title
          type: string
        type:
          title: Type
          type: string
      required:
        - type
        - title
        - status
        - detail
        - code
      title: Problem
      type: object
    FieldViolation:
      description: A single field-level violation inside a Problem ``errors[]`` list.
      properties:
        code:
          title: Code
          type: string
        field:
          title: Field
          type: string
        message:
          title: Message
          type: string
        pointer:
          title: Pointer
          type: string
      required:
        - pointer
        - field
        - code
        - message
      title: FieldViolation
      type: object
  securitySchemes:
    ApiKeyHeader:
      description: An Exo API key (exo_...) sent as the X-Exo-API-Key header.
      in: header
      name: X-Exo-API-Key
      type: apiKey
    BearerAuth:
      description: The same Exo API key (exo_...) sent as an Authorization bearer token.
      scheme: bearer
      type: http

````