> ## 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.

# Create a subscription

> Creates a webhook endpoint that receives a signed POST for every event its filters match, and returns it with its `hmac_secret`. Save the secret: only this response shows it, and you need it to verify signatures. The endpoint is active at once and receives events from the ledger after `activation_checkpoint`.

- **Free plan:** one Testnet endpoint; deliveries cost no credits and are capped at 1,000 per organization per UTC day (later matches become free_quota_exhausted coverage gaps). Mainnet needs a paid plan.
- **Paid plans:** 10 (Starter), 50 (Growth), 250 (Scale) or 1,000 (Enterprise) endpoints per network. Testnet deliveries are free; each delivered Mainnet event costs 1 credit.
- **Retries:** resend the same Idempotency-Key and body to get the existing endpoint (200, without the secret); the same key with another body returns 409.
- **Payloads:** token_transfer, contract_event, balance.changed and webhook.test bodies and the signed headers are in the `delivery` callback of this operation and on [Receive webhooks](/webhooks/receive).



## OpenAPI

````yaml /api-reference/webhooks.json post /v1/subscriptions
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:
    post:
      tags:
        - Subscriptions
      summary: Create a subscription
      description: >-
        Creates a webhook endpoint that receives a signed POST for every event
        its filters match, and returns it with its `hmac_secret`. Save the
        secret: only this response shows it, and you need it to verify
        signatures. The endpoint is active at once and receives events from the
        ledger after `activation_checkpoint`.


        - **Free plan:** one Testnet endpoint; deliveries cost no credits and
        are capped at 1,000 per organization per UTC day (later matches become
        free_quota_exhausted coverage gaps). Mainnet needs a paid plan.

        - **Paid plans:** 10 (Starter), 50 (Growth), 250 (Scale) or 1,000
        (Enterprise) endpoints per network. Testnet deliveries are free; each
        delivered Mainnet event costs 1 credit.

        - **Retries:** resend the same Idempotency-Key and body to get the
        existing endpoint (200, without the secret); the same key with another
        body returns 409.

        - **Payloads:** token_transfer, contract_event, balance.changed and
        webhook.test bodies and the signed headers are in the `delivery`
        callback of this operation and on [Receive webhooks](/webhooks/receive).
      operationId: createSubscription
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          description: >-
            Required, 1 to 128 characters. Resending the same key with the same
            body returns the existing endpoint (200, without hmac_secret)
            instead of creating a second one; the same key with a different body
            returns 409.
          schema:
            type: string
            minLength: 1
            maxLength: 128
            example: retry-0001-2026-10-22
            x-default: retry-0001-2026-10-22
          example: retry-0001-2026-10-22
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SubscriptionInput'
            example:
              name: payments
              target_url: https://example.com/webhooks
              account: GAIH3ULLFQ4DGSECF2AR555KZ4KNDGEKN4AFI4SU2M7B43MGK3QJZNSR
              event_types:
                - transfer
      responses:
        '201':
          description: >-
            Created and active (effective_state active). hmac_secret is shown
            only in this response. A retry with the same Idempotency-Key and
            body answers 200 with the same endpoint, without hmac_secret.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Subscription'
              example:
                id: 00000000-0000-4000-8000-000000000000
                name: payments
                target_url: https://example.com/webhooks
                account: GAIH3ULLFQ4DGSECF2AR555KZ4KNDGEKN4AFI4SU2M7B43MGK3QJZNSR
                event_types:
                  - transfer
                active: true
                created_at: '2026-10-22T09:15:04Z'
                admission_protocol: 2
                version: 1
                desired_state: active
                effective_state: active
                slot_state: sponsored
                sponsored: true
                metered: false
                signing_version: 1
                generation: testnet-2025-12-18-v2
                activation_checkpoint: 5331500
                effective_checkpoint: 5331500
                last_scanned_ledger: 5331500
                hmac_secret: whsec_0000…
          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
            ETag:
              description: Quoted subscription version.
              schema:
                type: string
                example: '"1"'
            Location:
              schema:
                type: string
        '202':
          description: >-
            Prepaid accounts only: created, effective_state activating. Tests
            answer 409 until GET shows effective_state active.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Subscription'
              example:
                id: 00000000-0000-4000-8000-000000000000
                name: payments
                target_url: https://example.com/webhooks
                account: GAIH3ULLFQ4DGSECF2AR555KZ4KNDGEKN4AFI4SU2M7B43MGK3QJZNSR
                event_types:
                  - transfer
                active: false
                created_at: '2026-10-22T09:15:04Z'
                admission_protocol: 2
                version: 1
                desired_state: active
                effective_state: activating
                slot_state: held
                sponsored: false
                metered: false
                signing_version: 1
                generation: testnet-2025-12-18-v2
                activation_checkpoint: 5331500
                effective_checkpoint: 5331500
                last_scanned_ledger: 5331500
                hmac_secret: whsec_0000…
          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
            ETag:
              description: Quoted subscription version.
              schema:
                type: string
                example: '"1"'
            Location:
              schema:
                type: string
        '400':
          $ref: '#/components/responses/HTTP400_3'
        '401':
          $ref: '#/components/responses/HTTP401'
        '403':
          $ref: '#/components/responses/HTTP403_2'
        '405':
          $ref: '#/components/responses/HTTP405_3'
        '409':
          $ref: '#/components/responses/HTTP409_2'
        '410':
          $ref: '#/components/responses/HTTP410'
        '413':
          $ref: '#/components/responses/HTTP413'
        '429':
          $ref: '#/components/responses/HTTP429'
        '503':
          $ref: '#/components/responses/HTTP503_2'
      callbacks:
        delivery:
          '{$request.body#/target_url}':
            post:
              summary: Event delivery
              description: >-
                Lumeus POSTs one event per request to your target_url. Verify
                X-Webhook-Signature over the raw body and the signed delivery
                context before you parse it ([verify](/webhooks/receive)), store
                the event under (network, id), then answer.


                - Answer 2xx within 10 seconds with a body of at most 4 KiB.
                Anything else, including a redirect, is retried: 8 attempts,
                waiting 2 s and doubling up to 128 s.

                - Each endpoint has exactly one delivery in flight; later events
                wait in ledger order.

                - token_transfer and contract_event bodies use the Activity
                event model (without paging fields); on Mainnet network is
                pubnet.
              parameters:
                - name: X-Webhook-Signature
                  in: header
                  required: true
                  description: >-
                    Signature of the raw body: `t=<unix seconds>,v1=<hex
                    HMAC-SHA256>` with your whsec_ secret over `<t>.<body>`.
                    Reject timestamps more than 300 seconds off.
                  schema:
                    type: string
                - name: X-Webhook-Timestamp
                  in: header
                  required: true
                  description: Unix seconds when this attempt was signed.
                  schema:
                    type: string
                - name: X-Webhook-Id
                  in: header
                  required: true
                  description: Delivery ID; negative for test deliveries.
                  schema:
                    type: string
                - name: X-Webhook-Event-Id
                  in: header
                  required: true
                  description: The event id, the same as in the body.
                  schema:
                    type: string
                - name: X-Webhook-Delivery-Context
                  in: header
                  required: true
                  description: >-
                    Signed delivery context, base64url JSON: delivery and
                    subscription IDs, event id, lane, network, generation and
                    the SHA-256 of the body.
                  schema:
                    type: string
                - name: X-Webhook-Context-Signature
                  in: header
                  required: true
                  description: '`t=<unix seconds>,v1=<hex>` over the decoded context bytes.'
                  schema:
                    type: string
                - name: X-Webhook-Lane
                  in: header
                  required: true
                  description: live, replay or test (also inside the signed context).
                  schema:
                    type: string
                - name: X-Webhook-Subscription-Id
                  in: header
                  required: true
                  description: The subscription UUID.
                  schema:
                    type: string
                - name: X-Webhook-Key-Version
                  in: header
                  required: true
                  description: Version of the signing key behind X-Webhook-Signature.
                  schema:
                    type: string
                - name: X-Webhook-Test
                  in: header
                  required: false
                  description: true on test deliveries.
                  schema:
                    type: string
                - name: X-Webhook-Replay-Id
                  in: header
                  required: false
                  description: Replay job ID, on replayed deliveries.
                  schema:
                    type: string
                - name: X-Webhook-Next-Signature
                  in: header
                  required: false
                  description: >-
                    During a key rotation only: the body signature made with the
                    new key (also X-Webhook-Next-Context-Signature and
                    X-Webhook-Next-Key-Version).
                  schema:
                    type: string
              requestBody:
                required: true
                content:
                  application/json:
                    schema:
                      oneOf:
                        - $ref: '#/components/schemas/Event'
                        - $ref: '#/components/schemas/BalanceChangedEvent'
                        - $ref: '#/components/schemas/TestEvent'
                    examples:
                      token_transfer:
                        summary: token_transfer (transfer)
                        value:
                          id: testnet:5294900:20
                          kind: token_transfer
                          type: transfer
                          network: testnet
                          ledger: 5294900
                          closed_at: '2026-10-20T12:08:07Z'
                          tx_hash: >-
                            25a493371952f0f99a6ff2dabcdbb783db6062ec7e7a5933c962b836fea08a0b
                          tx_index: 6
                          operation_index: 1
                          asset: native
                          contract_address: >-
                            CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC
                          from: >-
                            GAIH3ULLFQ4DGSECF2AR555KZ4KNDGEKN4AFI4SU2M7B43MGK3QJZNSR
                          to: >-
                            GAIGKM2WWDVEB4OCV3Q4YICODYWTWFZ5CDOWG7I7Y5HJW7VVFQ7BSUCL
                          amount: '10000.0000000'
                          amount_raw: '100000000000'
                      contract_event:
                        summary: contract_event (approve)
                        value:
                          id: testnet:2650391:ce:9:0:0
                          kind: contract_event
                          type: approve
                          network: testnet
                          ledger: 2650391
                          closed_at: '2026-05-20T07:17:29Z'
                          tx_hash: >-
                            8c7f3bc80381cf504285ee4fc17a4ab20fb94c8f8f6ed3688124e3e82ec021c0
                          tx_index: 9
                          operation_index: 1
                          contract_address: >-
                            CCUX7JEJBAUCTFWXY5LQ4FOVIXF2ZWBTPXXZQN5CTGMJ7A2LUHYU22MY
                          topics:
                            - approve
                            - >-
                              CAT6HNJZ6ODHXRA77FKDVPAG3RX4B6I362SU4K4DDCRN6J7TDY75OZSI
                            - >-
                              GAIH3ULLFQ4DGSECF2AR555KZ4KNDGEKN4AFI4SU2M7B43MGK3QJZNSR
                          data:
                            - '50000000'
                            - 2667669
                          topics_xdr:
                            - AAAADwAAAAdhcHByb3ZlAA==
                            - >-
                              AAAAEgAAAAEn47U584Z7xB/5VDq8BtxvwPkb9qVOK4MYot8n8x4/1w==
                            - >-
                              AAAAEgAAAAAAAAAAEH3Rayw4M0iCLoEe96rPFNGYim8AVHJU0z4ebYZW4Jw=
                          data_xdr: >-
                            AAAAEAAAAAEAAAACAAAACgAAAAAAAAAAAAAAAAL68IAAAAADACi0lQ==
                      balance.changed:
                        summary: balance.changed
                        value:
                          id: >-
                            testnet:5294900:b:GAIGKM2WWDVEB4OCV3Q4YICODYWTWFZ5CDOWG7I7Y5HJW7VVFQ7BSUCL:native
                          kind: balance
                          type: balance.changed
                          network: testnet
                          ledger: 5294900
                          closed_at: '2026-10-20T12:08:07Z'
                          holder: >-
                            GAIGKM2WWDVEB4OCV3Q4YICODYWTWFZ5CDOWG7I7Y5HJW7VVFQ7BSUCL
                          asset: native
                          contract_address: >-
                            CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC
                          balance: '10000.0000000'
                          balance_raw: '100000000000'
                          previous_balance_raw: '0'
                          decimals: 7
                          source: ledger_entry
                          archived: false
                          deleted: false
                      webhook.test:
                        summary: webhook.test
                        value:
                          id: test_5
                          kind: test
                          type: webhook.test
                          test: true
                          network: testnet
                          generation: testnet-2025-12-18-v2
                          subscription_id: 00000000-0000-4000-8000-000000000000
                          created_at: '2026-10-22T10:00:00Z'
              responses:
                '200':
                  description: 'Delivered: any 2xx answer within 10 seconds counts.'
              method: post
              type: path
            path: '{$request.body#/target_url}'
      x-codeSamples:
        - lang: bash
          label: cURL
          source: >-
            curl --fail-with-body -sS -X POST
            'https://webhooks-testnet.lumeus.dev/v1/subscriptions' \
              -H "Authorization: Bearer $LUMEUS_WEBHOOK_KEY" \
              -H 'Idempotency-Key: retry-0001-2026-10-22' \
              -H 'Content-Type: application/json' \
              -d '{"name":"payments","target_url":"https://example.com/webhooks","account":"GAIH3ULLFQ4DGSECF2AR555KZ4KNDGEKN4AFI4SU2M7B43MGK3QJZNSR","event_types":["transfer"]}'
        - lang: javascript
          label: JavaScript
          source: >-
            // Node 18+ (ES module)

            const res = await
            fetch('https://webhooks-testnet.lumeus.dev/v1/subscriptions', {
              method: 'POST',
              headers: {
                Authorization: `Bearer ${process.env.LUMEUS_WEBHOOK_KEY}`,
                'Idempotency-Key': 'retry-0001-2026-10-22',
                'Content-Type': 'application/json',
              },
              body: JSON.stringify({
                "name": "payments",
                "target_url": "https://example.com/webhooks",
                "account": "GAIH3ULLFQ4DGSECF2AR555KZ4KNDGEKN4AFI4SU2M7B43MGK3QJZNSR",
                "event_types": [
                  "transfer"
                ]
              }),
            });

            console.log(res.status, JSON.stringify(await res.json(), null, 2));
        - lang: python
          label: Python
          source: |-
            import json
            import os

            import requests

            res = requests.post(
                "https://webhooks-testnet.lumeus.dev/v1/subscriptions",
                headers={"Authorization": f"Bearer {os.environ['LUMEUS_WEBHOOK_KEY']}", "Idempotency-Key": "retry-0001-2026-10-22"},
                json={
                    "name": "payments",
                    "target_url": "https://example.com/webhooks",
                    "account": "GAIH3ULLFQ4DGSECF2AR555KZ4KNDGEKN4AFI4SU2M7B43MGK3QJZNSR",
                    "event_types": [
                        "transfer"
                    ]
                },
                timeout=30,
            )
            print(res.status_code, json.dumps(res.json(), indent=2))
components:
  schemas:
    SubscriptionInput:
      type: object
      properties:
        name:
          type: string
          description: Label for the endpoint, at most 256 bytes.
          maxLength: 256
        target_url:
          type: string
          description: >-
            Public HTTPS URL. DNS and dial-time SSRF validation reject private
            targets.
          format: uri
          maxLength: 2048
        account:
          type: string
          description: Checksum-valid G/M/C/B/L StrKey.
        asset:
          type: string
          description: >-
            native or CODE:ISSUER. Balance events also accept a C… token
            contract (a SAC selects its classic asset) or `pool:<64 hex>`.
        contract_addr:
          type: string
          description: Checksum-valid C StrKey.
        event_types:
          type: array
          items:
            type: string
            minLength: 1
            maxLength: 128
          maxItems: 64
          uniqueItems: true
          description: >-
            Empty means every decoded event type. Token-transfer types:
            transfer, mint, burn, clawback, fee. Balance events are opt-in: list
            balance.changed, or balance.changed.fees to include fee-only XLM
            changes. Any other value selects contract events by their first
            topic symbol and must be a Soroban symbol (1-32 characters of A-Z,
            a-z, 0-9 and _); anything else is a 400. A symbol that looks like a
            misspelled token-transfer type (for example transfers) is accepted
            with a warnings entry in the response.
      required:
        - target_url
      additionalProperties: false
    Subscription:
      type: object
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
          description: Endpoint label.
        target_url:
          type: string
          description: HTTPS URL that receives the signed POSTs.
        hmac_secret:
          type: string
          description: >-
            Returned only by the first successful creation; retries do not
            reveal it.
        account:
          type: string
          description: Account filter, when set.
        asset:
          type: string
          description: Asset filter, when set.
        contract_addr:
          type: string
          description: Contract filter, when set.
        event_types:
          type: array
          items:
            type: string
          description: Event type filter; absent or empty means every decoded event type.
        active:
          type: boolean
          description: True while the endpoint receives events.
        created_at:
          type: string
          format: date-time
        admission_protocol:
          type: integer
          description: 'Delivery protocol version (2: deliveries carry a signed context).'
        version:
          type: integer
          description: >-
            Endpoint version, also in the ETag header. Every change increments
            it.
        desired_state:
          type: string
          description: 'What you asked for: active, paused or deleted.'
        effective_state:
          type: string
          description: >-
            What applies now: active, activating, paused_by_user,
            paused_by_funding (for example the free daily cap was reached) or
            deleted.
        slot_state:
          type: string
          description: >-
            metered for paid-plan endpoints, sponsored for the free Testnet
            endpoint, held for prepaid funded endpoints.
        sponsored:
          type: boolean
          description: >-
            True for the one free Testnet endpoint of a Free organization:
            deliveries are not charged credits but are capped per UTC day, and
            replays are not available.
        metered:
          type: boolean
          description: >-
            True for a paid-plan endpoint: every delivered Mainnet event costs
            the catalog webhook credit weight (1 credit) from the organization's
            monthly balance, with overage billed on paid plans. Testnet
            deliveries, and failed, cancelled and expired deliveries, cost
            nothing. Replays are not yet available for paid endpoints.
        signing_version:
          type: integer
          description: Version of the current signing secret; rotation increments it.
        generation:
          type: string
          description: Event index generation the endpoint reads.
        activation_checkpoint:
          type: integer
          description: >-
            The endpoint receives events from the ledger after this one. Read
            earlier history from the Activity API.
        effective_checkpoint:
          type: integer
          description: Last ledger the endpoint's state applies to.
        last_scanned_ledger:
          type: integer
          description: Last ledger scanned for matching events.
        last_fully_admitted_ledger:
          type: integer
          description: Last ledger whose matching events were all queued for delivery.
        free_quota:
          type: object
          properties:
            day:
              type: string
              description: UTC date (YYYY-MM-DD).
            daily_cap:
              type: integer
            admitted:
              type: integer
              description: >-
                Admitted today; deliveries cancelled before any attempt are
                given back.
            delivered:
              type: integer
          required:
            - day
            - daily_cap
            - admitted
            - delivered
          description: >-
            Free Testnet endpoints only, on `GET /v1/subscriptions/{id}`: the
            organization's admitted and delivered deliveries today (UTC) against
            its daily cap.
        paid:
          type: object
          properties:
            plan:
              type: string
            endpoint_limit:
              type: integer
              description: Paid endpoints allowed per network on this plan.
            endpoints_used:
              type: integer
              description: Active paid endpoints of the organization on this network.
            credits_per_delivery:
              type: integer
          required:
            - plan
            - endpoint_limit
            - endpoints_used
            - credits_per_delivery
          description: Paid endpoints only, on `GET /v1/subscriptions/{id}`.
        warnings:
          type: array
          items:
            type: string
          description: >-
            Create and update responses only: non-fatal filter warnings, such as
            a probable event type typo.
      required:
        - id
        - target_url
        - active
        - created_at
        - admission_protocol
        - version
        - desired_state
        - effective_state
        - slot_state
        - sponsored
        - metered
        - signing_version
    Event:
      type: object
      properties:
        id:
          type: string
          description: >-
            Deterministic event identity: `{network}:{ledger}:{n}` for
            token_transfer, `{network}:{ledger}:ce:{tx}:{op}:{event}` for
            contract_event. Activity and Webhooks give the same on-chain event
            the same id (same decoder release), so deduplicate on (network, id);
            after a Testnet reset ledger numbers repeat, so start a new store.
        kind:
          type: string
          enum:
            - token_transfer
            - contract_event
        type:
          type: string
          description: >-
            transfer, mint, burn, clawback, fee, or a custom contract event
            name.
        network:
          type: string
          description: 'Canonical payload vocabulary: pubnet is Mainnet.'
          enum:
            - pubnet
            - testnet
        ledger:
          type: integer
          minimum: 3
        closed_at:
          type: string
          format: date-time
        tx_hash:
          type: string
          pattern: ^[0-9a-fA-F]{64}$
        tx_index:
          type: integer
          description: One-based position within the ledger.
        operation_index:
          type: integer
          description: One-based operation index; absent for transaction-level fee events.
        asset:
          type: string
          description: native or CODE:ISSUER. May be absent for custom contract tokens.
        contract_address:
          type: string
        from:
          type: string
        to:
          type: string
        issuer:
          type: string
        to_muxed_id:
          type: string
          description: Unsigned integer string, never a JavaScript number.
        to_muxed_address:
          type: string
        to_muxed_text:
          type: string
        to_muxed_hash:
          type: string
        memo_type:
          type: string
        memo:
          type: string
        memo_xdr:
          type: string
        amount:
          type: string
          description: Decimal string; seven decimal places for Classic/SAC assets.
        amount_raw:
          type: string
          description: Exact signed integer string.
        topics:
          type: array
          items: {}
        data: {}
        topics_xdr:
          type: array
          items:
            type: string
            description: Base64 ScVal XDR.
        data_xdr:
          type: string
          description: Base64 ScVal XDR; authoritative typed representation.
        paging_token:
          type: string
          description: Activity collections only; opaque keyset cursor.
      required:
        - id
        - kind
        - type
        - network
        - ledger
        - closed_at
        - tx_hash
        - tx_index
    BalanceChangedEvent:
      type: object
      properties:
        id:
          type: string
          description: >-
            `{network}:{ledger}:b:{holder}:{asset}`. Deduplicate on (network,
            id).
        kind:
          type: string
          enum:
            - balance
        type:
          type: string
          enum:
            - balance.changed
        network:
          type: string
          description: pubnet is Mainnet.
          enum:
            - pubnet
            - testnet
        ledger:
          type: integer
        closed_at:
          type: string
          format: date-time
        holder:
          type: string
          description: Account or contract that holds the balance.
        asset:
          type: string
          description: >-
            native, CODE:ISSUER, a C… contract token, or `pool:<hex>` for a
            liquidity pool share. Never a SAC address.
        contract_address:
          type: string
          description: >-
            The SAC for native and classic assets, the token contract for
            contract tokens; absent for pool shares.
        balance:
          type: string
          description: >-
            New balance after the ledger as a decimal string. Absent when
            decimals is unknown.
        balance_raw:
          type: string
          description: New balance as an exact integer string.
        previous_balance_raw:
          type: string
          description: Balance before the ledger (0 when it did not exist).
        decimals:
          type: integer
          description: >-
            7 for native, classic, SAC and pool shares; the token's decimals for
            contract tokens. Absent when unknown.
        source:
          type: string
          enum:
            - ledger_entry
            - token_storage
        archived:
          type: boolean
          description: >-
            The contract balance entry was evicted to the archive; its value is
            unchanged.
        deleted:
          type: boolean
          description: The trustline or balance entry was removed; balance is 0.
      required:
        - id
        - kind
        - type
        - network
        - ledger
        - closed_at
        - holder
        - asset
        - balance_raw
        - previous_balance_raw
        - source
        - archived
        - deleted
      description: >-
        balance.changed: one event per holder, asset and ledger, carrying the
        value after the ledger. Opt in with event_types balance.changed (or
        balance.changed.fees to include fee-only XLM changes).
    TestEvent:
      type: object
      properties:
        id:
          type: string
          description: '`test_{n}`.'
        kind:
          type: string
          enum:
            - test
        type:
          type: string
          enum:
            - webhook.test
        test:
          type: boolean
          description: Always true.
        network:
          type: string
          description: testnet or mainnet (the signed-context vocabulary).
        generation:
          type: string
          description: The subscription's webhook chain generation.
        subscription_id:
          type: string
          format: uuid
        created_at:
          type: string
          format: date-time
      required:
        - id
        - kind
        - type
        - test
        - network
        - generation
        - subscription_id
        - created_at
      description: >-
        webhook.test: sent by `POST /v1/subscriptions/{id}/tests`, once and
        without retries, with X-Webhook-Test: true and lane test. Keep it out of
        your data.
    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_3:
      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'
          examples:
            Target is not HTTPS:
              summary: Target is not HTTPS
              value:
                code: invalid_request
                error: target_url must use https
                request_id: req_6f1c2a9b0e4d4c7a8b3f5e21
            Unknown field:
              summary: Unknown field
              value:
                code: invalid_request
                error: 'invalid JSON body: unknown field "network"'
                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_2:
      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'
          examples:
            Paid plan endpoint limit:
              summary: Paid plan endpoint limit
              value:
                code: forbidden
                error: >-
                  plan "starter" allows 10 webhook endpoints on this network;
                  delete one or upgrade
                request_id: req_6f1c2a9b0e4d4c7a8b3f5e21
            Second Free endpoint:
              summary: Second Free endpoint
              value:
                code: forbidden
                error: >-
                  the Free plan includes one Testnet webhook endpoint; delete it
                  or upgrade to a paid plan for more
                request_id: req_6f1c2a9b0e4d4c7a8b3f5e21
            Free plan on Mainnet:
              summary: Free plan on Mainnet
              value:
                code: forbidden
                error: >-
                  free webhooks are available on Testnet only; upgrade to a paid
                  plan to use Mainnet 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}$
    HTTP405_3:
      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 PUT is not allowed on /v1/subscriptions; allowed: GET,
              HEAD, 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_2:
      description: The request conflicts with the current state (code conflict).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: conflict
            error: request identity or subscription generation conflicts
            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}$
    HTTP410:
      description: >-
        The endpoint created with this Idempotency-Key has since been deleted
        (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}$
    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}$
    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_2:
      description: >-
        code unavailable. Usually temporary (for example `webhook control is
        temporarily unavailable`): wait Retry-After seconds and retry. When the
        message says this kind of endpoint is not enabled on the network (`paid
        webhooks are not enabled on this network yet`, `free Testnet webhooks
        are not enabled`, or `webhook admission is not initialized on this
        network yet`; Retry-After 300), retrying does not help until Lumeus
        changes the network configuration: stop after one or two attempts and
        contact support, or create the endpoint on the other network.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            Temporarily unavailable:
              summary: Temporarily unavailable (retry after Retry-After)
              value:
                code: unavailable
                error: webhook control is temporarily unavailable
                request_id: req_6f1c2a9b0e4d4c7a8b3f5e21
            Paid webhooks off on this network:
              summary: >-
                Paid webhooks are not enabled on this network (Retry-After 300;
                do not retry in a loop)
              value:
                code: unavailable
                error: paid webhooks are not enabled on this network yet
                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.