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

# Send a test event

> Sends one signed synthetic webhook.test event to an active or paused endpoint and returns the outcome. The body has test: true and the signed context has lane test. Tests never enter delivery history, billing or replay. Limited to 12 tests per organization per hour. Deleting the endpoint deletes its test history.



## OpenAPI

````yaml /api-reference/webhooks.json post /v1/subscriptions/{id}/tests
openapi: 3.0.3
info:
  title: Lumeus Webhooks API
  version: '2026-09-15'
  description: >-
    Lumeus Webhooks API on Stellar. Sign up at https://app.lumeus.dev: Free,
    Starter, Growth and Scale plans are self-serve, Enterprise by agreement.


    - **Pricing.** Testnet webhook deliveries cost no credits. A Free
    organization gets one Testnet endpoint with up to 1,000 deliveries a day. On
    paid plans each delivered Mainnet event costs 1 credit from the monthly
    balance. Calls to this management API are not charged. Plans, limits and
    credit weights: `GET https://api.lumeus.dev/v1/plans`.

    - **Authentication.** Send `Authorization: Bearer whk_…`, a webhook key from
    the dashboard. Webhook keys belong to one network, so pick the server that
    matches the key. `lum_` API keys are not accepted here (401).

    - **Headers.** Every response carries X-Request-Id; authenticated responses
    carry RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset; 429 and 503
    carry Retry-After.

    - **Errors.** JSON with a machine-readable code (see
    [errors](/guides/errors)). A path with an empty, `.` or `..` segment answers
    400 invalid_request, a trailing slash answers 404 not_found, and a method
    the path does not accept answers 405 with an Allow header.

    - **CORS.** Browser calls (CORS) are allowed from https://docs.lumeus.dev
    (the Try it playground of this reference) and https://app.lumeus.dev only,
    without cookies; responses expose ETag, Link, Location, Retry-After,
    X-Request-Id, X-Lumeus-Operation-Id, X-Lumeus-Idempotency and
    RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset (errors included).
    Other websites cannot read responses made with a server key: use a
    publishable key with your own allowed origins ([browser
    keys](/guides/browser-keys)).
  license:
    name: Lumeus API contract
servers:
  - url: https://webhooks-testnet.lumeus.dev
    description: Testnet (default)
  - url: https://webhooks.lumeus.dev
    description: Mainnet
security:
  - Bearer: []
tags:
  - name: Webhook keys
    description: >-
      Create, list and revoke the `whk_` keys that manage webhook endpoints on
      one network.
  - name: Subscriptions
    description: >-
      Create, list, read, change, pause and delete webhook endpoints
      (subscriptions) and their event filters.
  - name: Deliveries
    description: >-
      What was delivered to an endpoint: recent deliveries, coverage gaps and
      signed test events.
  - name: Signing keys
    description: >-
      Rotate an endpoint's whsec_ signing secret with a 24-hour overlap, or end
      the overlap early.
  - name: Replay
    description: >-
      Redeliver past events or replay a ledger range to an endpoint, priced by a
      quote first. Free and paid plan endpoints get 403 today.
  - name: Health
    description: Liveness and readiness probes for monitoring. No authentication.
paths:
  /v1/subscriptions/{id}/tests:
    post:
      tags:
        - Deliveries
      summary: Send a test event
      description: >-
        Sends one signed synthetic webhook.test event to an active or paused
        endpoint and returns the outcome. The body has test: true and the signed
        context has lane test. Tests never enter delivery history, billing or
        replay. Limited to 12 tests per organization per hour. Deleting the
        endpoint deletes its test history.
      operationId: sendTestEvent
      parameters:
        - name: id
          in: path
          required: true
          description: >-
            Endpoint (subscription) ID from `POST /v1/subscriptions` or `GET
            /v1/subscriptions`. The example ID is a placeholder and answers 404:
            use your own.
          schema:
            type: string
            format: uuid
            example: 00000000-0000-4000-8000-000000000000
            x-default: 00000000-0000-4000-8000-000000000000
          example: 00000000-0000-4000-8000-000000000000
        - name: If-Match
          in: header
          required: true
          description: >-
            The ETag from `GET /v1/subscriptions/{id}`, for example `"1"` (the
            weak form `W/"1"` that some proxies produce is accepted too). A
            stale version returns 412; a missing header returns 428.
          schema:
            type: string
            pattern: ^(W/)?"[1-9][0-9]*"$
            example: '"1"'
            x-default: '"1"'
          example: '"1"'
        - name: Idempotency-Key
          in: header
          required: true
          description: >-
            Required, 1 to 128 characters. Resending the same key within seven
            days returns the first test instead of sending another.
          schema:
            type: string
            minLength: 1
            maxLength: 128
            example: test-0001
            x-default: test-0001
          example: test-0001
      responses:
        '200':
          description: The test was sent; status says how the receiver answered.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TestDelivery'
              example:
                id: 1
                subscription_id: 00000000-0000-4000-8000-000000000000
                event_id: test_1
                status: delivered
                response_code: 200
                created_at: '2026-10-22T09:15:04Z'
                completed_at: '2026-10-22T09:15:05Z'
          headers:
            X-Request-Id:
              description: >-
                Identifier of this request: req_ followed by 24 hex characters.
                Error bodies repeat it as request_id. Quote it when contacting
                support.
              schema:
                type: string
                pattern: ^req_[0-9a-f]{24}$
            RateLimit-Limit:
              description: >-
                Requests per minute of the bucket that answered: the plan rate,
                the dashboard session floor of 120, or a publishable key's
                per-IP rate.
              schema:
                type: integer
            RateLimit-Remaining:
              description: Whole requests left in the bucket after this one.
              schema:
                type: integer
            RateLimit-Reset:
              description: Seconds until the bucket is full again.
              schema:
                type: integer
        '202':
          description: A test with this Idempotency-Key is still in progress.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TestDelivery'
              example:
                id: 1
                subscription_id: 00000000-0000-4000-8000-000000000000
                event_id: test_1
                status: started
                created_at: '2026-10-22T09:15:04Z'
          headers:
            X-Request-Id:
              description: >-
                Identifier of this request: req_ followed by 24 hex characters.
                Error bodies repeat it as request_id. Quote it when contacting
                support.
              schema:
                type: string
                pattern: ^req_[0-9a-f]{24}$
            RateLimit-Limit:
              description: >-
                Requests per minute of the bucket that answered: the plan rate,
                the dashboard session floor of 120, or a publishable key's
                per-IP rate.
              schema:
                type: integer
            RateLimit-Remaining:
              description: Whole requests left in the bucket after this one.
              schema:
                type: integer
            RateLimit-Reset:
              description: Seconds until the bucket is full again.
              schema:
                type: integer
        '400':
          $ref: '#/components/responses/HTTP400_7'
        '401':
          $ref: '#/components/responses/HTTP401'
        '403':
          $ref: '#/components/responses/HTTP403'
        '404':
          $ref: '#/components/responses/HTTP404_2'
        '405':
          $ref: '#/components/responses/HTTP405_7'
        '409':
          $ref: '#/components/responses/HTTP409_3'
        '410':
          $ref: '#/components/responses/HTTP410_2'
        '412':
          $ref: '#/components/responses/HTTP412'
        '413':
          $ref: '#/components/responses/HTTP413'
        '428':
          $ref: '#/components/responses/HTTP428'
        '429':
          $ref: '#/components/responses/HTTP429'
        '503':
          $ref: '#/components/responses/HTTP503_3'
      x-codeSamples:
        - lang: bash
          label: cURL
          source: >-
            # Use a subscription id from POST or GET /v1/subscriptions; the
            placeholder answers 404.

            curl --fail-with-body -sS -X POST
            'https://webhooks-testnet.lumeus.dev/v1/subscriptions/00000000-0000-4000-8000-000000000000/tests'
            \
              -H "Authorization: Bearer $LUMEUS_WEBHOOK_KEY" \
              -H 'If-Match: "1"' \
              -H 'Idempotency-Key: test-0001'
        - lang: javascript
          label: JavaScript
          source: >-
            // Node 18+ (ES module)

            // Use a subscription id from POST or GET /v1/subscriptions; the
            placeholder answers 404.

            const res = await
            fetch('https://webhooks-testnet.lumeus.dev/v1/subscriptions/00000000-0000-4000-8000-000000000000/tests',
            {
              method: 'POST',
              headers: {
                Authorization: `Bearer ${process.env.LUMEUS_WEBHOOK_KEY}`,
                'If-Match': '"1"',
                'Idempotency-Key': 'test-0001',
              },
            });

            console.log(res.status, JSON.stringify(await res.json(), null, 2));
        - lang: python
          label: Python
          source: >-
            # Use a subscription id from POST or GET /v1/subscriptions; the
            placeholder answers 404.

            import json

            import os


            import requests


            res = requests.post(
                "https://webhooks-testnet.lumeus.dev/v1/subscriptions/00000000-0000-4000-8000-000000000000/tests",
                headers={"Authorization": f"Bearer {os.environ['LUMEUS_WEBHOOK_KEY']}", "If-Match": "\"1\"", "Idempotency-Key": "test-0001"},
                timeout=30,
            )

            print(res.status_code, json.dumps(res.json(), indent=2))
components:
  schemas:
    TestDelivery:
      type: object
      properties:
        id:
          type: integer
          format: int64
        subscription_id:
          type: string
          format: uuid
        event_id:
          type: string
        status:
          type: string
          enum:
            - started
            - delivered
            - rejected
            - uncertain
        response_code:
          type: integer
        last_error:
          type: string
        created_at:
          type: string
          format: date-time
        completed_at:
          type: string
          format: date-time
      required:
        - id
        - subscription_id
        - event_id
        - status
        - created_at
    Error:
      type: object
      properties:
        error:
          type: string
          description: Human-readable message. It may change; branch on code.
        code:
          type: string
          description: >-
            Machine-readable error code. Branch on code, not on the error text,
            which may change. RPC carries the same codes as the string
            error.data of a JSON-RPC error. invalid_request: 400: invalid input,
            including a malformed Idempotency-Key or an unknown or repeated
            query parameter (Webhooks also uses it for an oversized request
            body, 413). Fix the request; do not retry unchanged. unauthorized:
            401: missing, revoked, invalid or wrong-network credential.
            payment_required: 402 (Mainnet): monthly credit quota exhausted on a
            hard-capped plan. forbidden: 403: the key or account policy does not
            allow this action. not_found: 404 (Webhooks also 410): the resource
            does not exist in this organization and network.
            topic_search_disabled: 404: contract-event topic search is not
            enabled on this network. method_not_allowed: 405: the route does not
            accept this method. conflict: 409: conflicting request identity,
            idempotency key, funding or recovery state. generation_changed: 409:
            the index generation or network changed since the snapshot was
            taken; restart the walk without generation and snapshot_ledger.
            history_unavailable: 409 (Assets): as_of_ledger is not answered from
            the balance history; start a snapshot job (POST /snapshots) or retry
            later. precondition_failed: 412 (Webhooks): the subscription version
            changed; fetch the current ETag. response_too_large: 413: the result
            exceeds the response budget; lower limit or narrow the request.
            precondition_required: 428 (Webhooks): If-Match with the
            subscription ETag is required. rate_limited: 429: a rate,
            concurrency or credit-cap limit was reached, or (Activity, Assets
            and RPC on Testnet) the daily Testnet request cap (message `daily
            Testnet request cap of 10000 reached; resets at 00:00 UTC`,
            Retry-After until 00:00 UTC). Wait Retry-After seconds (a refused
            request consumes nothing). A Retry-After greater than 60 means the
            daily Testnet cap: wait until 00:00 UTC or switch to Mainnet. RPC
            carries it as the string error.data. internal_error: 500 or another
            unexpected 5xx; quote request_id when contacting support.
            not_implemented: 501: the feature is not enabled on this host. busy:
            503: reads are saturated (the queue wait expired or the database
            refused another query or ran short of memory). Retry the same
            request after Retry-After (2) seconds. query_timeout: 503: the read
            ran out of time. Do not retry unchanged right away: narrow the
            ledger range (since_ledger/until_ledger) or lower limit; Retry-After
            is 30. index_not_ready: 503: the index or snapshot is not ready yet
            or is rebuilding; retry after Retry-After seconds. topic_coverage:
            503: the effective range is outside the contract-event topic index
            coverage (the message states it); pass a range inside it or retry
            after Retry-After (60) seconds. unavailable: 503: another temporary
            failure (billing, rate limiter, queue); retry after Retry-After
            seconds.
          enum:
            - invalid_request
            - unauthorized
            - payment_required
            - forbidden
            - not_found
            - topic_search_disabled
            - method_not_allowed
            - conflict
            - generation_changed
            - history_unavailable
            - precondition_failed
            - response_too_large
            - precondition_required
            - rate_limited
            - internal_error
            - not_implemented
            - busy
            - query_timeout
            - index_not_ready
            - topic_coverage
            - unavailable
        request_id:
          type: string
          description: >-
            Identifier of this request, the same value as the X-Request-Id
            header. Quote it when contacting support.
      required:
        - error
  responses:
    HTTP400_7:
      description: >-
        Invalid input (code invalid_request). The message names the problem. Fix
        the request; do not retry it unchanged.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: invalid_request
            error: Idempotency-Key is required (1–128 characters)
            request_id: req_6f1c2a9b0e4d4c7a8b3f5e21
      headers:
        X-Request-Id:
          description: >-
            Identifier of this request: req_ followed by 24 hex characters.
            Error bodies repeat it as request_id. Quote it when contacting
            support.
          schema:
            type: string
            pattern: ^req_[0-9a-f]{24}$
    HTTP401:
      description: >-
        Missing, invalid, revoked or expired key, or a key for the other network
        (code unauthorized). Keys work only on the network they were created
        for.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            No key:
              summary: No key
              value:
                code: unauthorized
                error: missing credentials
                request_id: req_6f1c2a9b0e4d4c7a8b3f5e21
            Invalid key:
              summary: Unknown, revoked or expired whk_ key
              value:
                code: unauthorized
                error: invalid or revoked API key
                request_id: req_6f1c2a9b0e4d4c7a8b3f5e21
      headers:
        X-Request-Id:
          description: >-
            Identifier of this request: req_ followed by 24 hex characters.
            Error bodies repeat it as request_id. Quote it when contacting
            support.
          schema:
            type: string
            pattern: ^req_[0-9a-f]{24}$
    HTTP403:
      description: >-
        This key or account cannot call this route (code forbidden): for example
        a read-only key on a workspace route, or a publishable key on a route or
        from an origin it does not allow.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: forbidden
            error: confirm your email address to manage webhooks
            request_id: req_6f1c2a9b0e4d4c7a8b3f5e21
      headers:
        X-Request-Id:
          description: >-
            Identifier of this request: req_ followed by 24 hex characters.
            Error bodies repeat it as request_id. Quote it when contacting
            support.
          schema:
            type: string
            pattern: ^req_[0-9a-f]{24}$
    HTTP404_2:
      description: Not found in this organization and network (code not_found).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: not_found
            error: subscription not found
            request_id: req_6f1c2a9b0e4d4c7a8b3f5e21
      headers:
        X-Request-Id:
          description: >-
            Identifier of this request: req_ followed by 24 hex characters.
            Error bodies repeat it as request_id. Quote it when contacting
            support.
          schema:
            type: string
            pattern: ^req_[0-9a-f]{24}$
    HTTP405_7:
      description: >-
        This path does not accept the HTTP method you sent (code
        method_not_allowed). The Allow header lists the methods it accepts.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: method_not_allowed
            error: >-
              method GET is not allowed on
              /v1/subscriptions/00000000-0000-4000-8000-000000000000/tests;
              allowed: POST
            request_id: req_6f1c2a9b0e4d4c7a8b3f5e21
      headers:
        X-Request-Id:
          description: >-
            Identifier of this request: req_ followed by 24 hex characters.
            Error bodies repeat it as request_id. Quote it when contacting
            support.
          schema:
            type: string
            pattern: ^req_[0-9a-f]{24}$
    HTTP409_3:
      description: >-
        code conflict: the endpoint is not active or paused, or the
        Idempotency-Key was used with another version. While the endpoint is
        activating the answer carries Retry-After 5 and the message `endpoint is
        still activating; retry in 5 seconds, or once GET /v1/subscriptions/{id}
        shows effective_state active`.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: conflict
            error: >-
              endpoint is still activating; retry in 5 seconds, or once GET
              /v1/subscriptions/{id} shows effective_state active
            request_id: req_6f1c2a9b0e4d4c7a8b3f5e21
      headers:
        X-Request-Id:
          description: >-
            Identifier of this request: req_ followed by 24 hex characters.
            Error bodies repeat it as request_id. Quote it when contacting
            support.
          schema:
            type: string
            pattern: ^req_[0-9a-f]{24}$
        Retry-After:
          description: Seconds to wait while the endpoint is activating (5).
          schema:
            type: integer
    HTTP410_2:
      description: >-
        The resource was deleted, or the retained payload or result expired
        (code not_found).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: not_found
            error: subscription is deleted
            request_id: req_6f1c2a9b0e4d4c7a8b3f5e21
      headers:
        X-Request-Id:
          description: >-
            Identifier of this request: req_ followed by 24 hex characters.
            Error bodies repeat it as request_id. Quote it when contacting
            support.
          schema:
            type: string
            pattern: ^req_[0-9a-f]{24}$
    HTTP412:
      description: >-
        The subscription version changed (code precondition_failed). Fetch the
        current ETag and retry.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: precondition_failed
            error: subscription version changed; fetch its current ETag
            request_id: req_6f1c2a9b0e4d4c7a8b3f5e21
      headers:
        X-Request-Id:
          description: >-
            Identifier of this request: req_ followed by 24 hex characters.
            Error bodies repeat it as request_id. Quote it when contacting
            support.
          schema:
            type: string
            pattern: ^req_[0-9a-f]{24}$
    HTTP413:
      description: Request body too large (code invalid_request).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: invalid_request
            error: request body is too large
            request_id: req_6f1c2a9b0e4d4c7a8b3f5e21
      headers:
        X-Request-Id:
          description: >-
            Identifier of this request: req_ followed by 24 hex characters.
            Error bodies repeat it as request_id. Quote it when contacting
            support.
          schema:
            type: string
            pattern: ^req_[0-9a-f]{24}$
    HTTP428:
      description: If-Match is required (code precondition_required).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: precondition_required
            error: If-Match with the subscription ETag is required
            request_id: req_6f1c2a9b0e4d4c7a8b3f5e21
      headers:
        X-Request-Id:
          description: >-
            Identifier of this request: req_ followed by 24 hex characters.
            Error bodies repeat it as request_id. Quote it when contacting
            support.
          schema:
            type: string
            pattern: ^req_[0-9a-f]{24}$
    HTTP429:
      description: >-
        The Webhooks management rate limit was reached (code rate_limited). Wait
        Retry-After seconds. The daily Testnet request cap of Activity, Assets
        and RPC does not apply to the Webhooks API.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: rate_limited
            error: webhook management rate limit exceeded
            request_id: req_6f1c2a9b0e4d4c7a8b3f5e21
      headers:
        X-Request-Id:
          description: >-
            Identifier of this request: req_ followed by 24 hex characters.
            Error bodies repeat it as request_id. Quote it when contacting
            support.
          schema:
            type: string
            pattern: ^req_[0-9a-f]{24}$
        RateLimit-Limit:
          description: >-
            Requests per minute of the bucket that answered: the plan rate, the
            dashboard session floor of 120, or a publishable key's per-IP rate.
          schema:
            type: integer
        RateLimit-Remaining:
          description: Whole requests left in the bucket after this one.
          schema:
            type: integer
        RateLimit-Reset:
          description: Seconds until the bucket is full again.
          schema:
            type: integer
        Retry-After:
          description: Seconds to wait before retrying.
          schema:
            type: integer
    HTTP503_3:
      description: >-
        Temporarily unavailable (code unavailable), for example the management
        limiter or the database. Wait Retry-After seconds and retry.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: unavailable
            error: webhook control is temporarily unavailable
            request_id: req_6f1c2a9b0e4d4c7a8b3f5e21
      headers:
        X-Request-Id:
          description: >-
            Identifier of this request: req_ followed by 24 hex characters.
            Error bodies repeat it as request_id. Quote it when contacting
            support.
          schema:
            type: string
            pattern: ^req_[0-9a-f]{24}$
        Retry-After:
          description: Seconds to wait before retrying.
          schema:
            type: integer
  securitySchemes:
    Bearer:
      type: http
      scheme: bearer
      description: >-
        Send `Authorization: Bearer whk_…`, a webhook key from the dashboard.
        Webhook keys belong to one network, so pick the server that matches the
        key. `lum_` API keys are not accepted here (401).

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.