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

# Create a webhook endpoint

> Registers an HTTPS URL to receive the listed event types. The response includes the signing secret; store it to verify deliveries, because an idempotent replay of this request returns the endpoint without it. Up to 16 endpoints per organization.



## OpenAPI

````yaml /openapi.json post /v1/webhooks/endpoints
openapi: 3.1.0
info:
  title: Endstate API
  version: 0.1.0
  description: Endstate developer API for chip verification and ownership workflows.
servers:
  - url: https://api2.endstate.io
    description: Production
  - url: https://api-staging.endstate.io
    description: Staging
security: []
paths:
  /v1/webhooks/endpoints:
    post:
      tags:
        - Webhooks
      summary: Create a webhook endpoint
      description: >-
        Registers an HTTPS URL to receive the listed event types. The response
        includes the signing secret; store it to verify deliveries, because an
        idempotent replay of this request returns the endpoint without it. Up to
        16 endpoints per organization.
      operationId: createWebhookEndpoint
      parameters:
        - schema:
            type: string
            minLength: 1
            maxLength: 255
            description: >-
              Unique key that makes this request safe to retry. Replaying the
              key with the same body returns the original response with
              `Idempotent-Replayed: true`; replaying it with a different body
              returns 409 `idempotency.key_conflict`.
            example: a1b2c3d4-0000-4000-8000-000000000000
          required: false
          name: Idempotency-Key
          in: header
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateWebhookEndpointRequest'
            example:
              url: https://hooks.example.com/endstate
              event_types:
                - example.updated
              description: Production listener
      responses:
        '201':
          description: The created endpoint with its signing secret.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookEndpointWithSecret'
              example:
                id: 8e1a7f50-90ab-4cde-8012-3456789abcde
                url: https://hooks.example.com/endstate
                event_types:
                  - example.updated
                description: Production listener
                status: enabled
                disabled_reason: null
                fail_since: null
                api_version: '2026-09-01'
                created_at: '2026-09-22T12:00:00.000Z'
                updated_at: '2026-09-22T12:00:00.000Z'
                secret: whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw
        '400':
          description: >-
            The request was malformed or failed validation.


            | Error code | When |

            | --- | --- |

            | `validation.failed` | The request failed schema validation. See
            `error.details` for per-field issues. |

            | `webhook_endpoint.url_refused` | The endpoint URL must use https
            and point at a public host. |

            | `webhook_event_type.unknown` | One of the event types is not a
            supported webhook event. |
          x-error-codes:
            - validation.failed
            - webhook_endpoint.url_refused
            - webhook_event_type.unknown
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                validation.failed:
                  summary: >-
                    The request failed schema validation. See `error.details`
                    for per-field issues.
                  value:
                    error:
                      code: validation.failed
                      message: >-
                        The request failed schema validation. See
                        `error.details` for per-field issues.
                      request_id: req_8e1a7f50-90ab-4cde-f012-3456789abcde
                      doc_url: https://docs.endstate.io/errors/validation-failed
                webhook_endpoint.url_refused:
                  summary: The endpoint URL must use https and point at a public host.
                  value:
                    error:
                      code: webhook_endpoint.url_refused
                      message: >-
                        The endpoint URL must use https and point at a public
                        host.
                      request_id: req_8e1a7f50-90ab-4cde-f012-3456789abcde
                      doc_url: >-
                        https://docs.endstate.io/errors/webhook-endpoint-url-refused
                webhook_event_type.unknown:
                  summary: One of the event types is not a supported webhook event.
                  value:
                    error:
                      code: webhook_event_type.unknown
                      message: One of the event types is not a supported webhook event.
                      request_id: req_8e1a7f50-90ab-4cde-f012-3456789abcde
                      doc_url: >-
                        https://docs.endstate.io/errors/webhook-event-type-unknown
        '401':
          description: |-
            Authentication failed.

            | Error code | When |
            | --- | --- |
            | `auth.unauthorized` | Credential is missing or malformed. |
          x-error-codes:
            - auth.unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                auth.unauthorized:
                  summary: Credential is missing or malformed.
                  value:
                    error:
                      code: auth.unauthorized
                      message: Credential is missing or malformed.
                      request_id: req_8e1a7f50-90ab-4cde-f012-3456789abcde
                      doc_url: https://docs.endstate.io/errors/auth-unauthorized
        '403':
          description: >-
            Authenticated, but not permitted.


            | Error code | When |

            | --- | --- |

            | `auth.forbidden` | Credential is valid but does not have access to
            the requested resource or action. |
          x-error-codes:
            - auth.forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                auth.forbidden:
                  summary: >-
                    Credential is valid but does not have access to the
                    requested resource or action.
                  value:
                    error:
                      code: auth.forbidden
                      message: >-
                        Credential is valid but does not have access to the
                        requested resource or action.
                      request_id: req_8e1a7f50-90ab-4cde-f012-3456789abcde
                      doc_url: https://docs.endstate.io/errors/auth-forbidden
        '409':
          description: >-
            The request conflicts with the resource's current state.


            | Error code | When |

            | --- | --- |

            | `idempotency.in_progress` | A request with this `Idempotency-Key`
            is already in progress. |

            | `idempotency.key_conflict` | The `Idempotency-Key` was previously
            used with a different request body. |

            | `webhook_endpoint.limit_reached` | Your organization already has
            the maximum of 16 webhook endpoints. |
          x-error-codes:
            - idempotency.in_progress
            - idempotency.key_conflict
            - webhook_endpoint.limit_reached
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                idempotency.in_progress:
                  summary: >-
                    A request with this `Idempotency-Key` is already in
                    progress.
                  value:
                    error:
                      code: idempotency.in_progress
                      message: >-
                        A request with this `Idempotency-Key` is already in
                        progress.
                      request_id: req_8e1a7f50-90ab-4cde-f012-3456789abcde
                      doc_url: https://docs.endstate.io/errors/idempotency-in-progress
                idempotency.key_conflict:
                  summary: >-
                    The `Idempotency-Key` was previously used with a different
                    request body.
                  value:
                    error:
                      code: idempotency.key_conflict
                      message: >-
                        The `Idempotency-Key` was previously used with a
                        different request body.
                      request_id: req_8e1a7f50-90ab-4cde-f012-3456789abcde
                      doc_url: https://docs.endstate.io/errors/idempotency-key-conflict
                webhook_endpoint.limit_reached:
                  summary: >-
                    Your organization already has the maximum of 16 webhook
                    endpoints.
                  value:
                    error:
                      code: webhook_endpoint.limit_reached
                      message: >-
                        Your organization already has the maximum of 16 webhook
                        endpoints.
                      request_id: req_8e1a7f50-90ab-4cde-f012-3456789abcde
                      doc_url: >-
                        https://docs.endstate.io/errors/webhook-endpoint-limit-reached
        '500':
          description: >-
            Something went wrong on our end.


            | Error code | When |

            | --- | --- |

            | `internal.error` | An unexpected server error occurred. Retry with
            exponential backoff and include `request_id` in any support request.
            |
          x-error-codes:
            - internal.error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                internal.error:
                  summary: >-
                    An unexpected server error occurred. Retry with exponential
                    backoff and include `request_id` in any support request.
                  value:
                    error:
                      code: internal.error
                      message: >-
                        An unexpected server error occurred. Retry with
                        exponential backoff and include `request_id` in any
                        support request.
                      request_id: req_8e1a7f50-90ab-4cde-f012-3456789abcde
                      doc_url: https://docs.endstate.io/errors/internal-error
        '503':
          description: >-
            The service cannot do this right now. See the error code.


            | Error code | When |

            | --- | --- |

            | `webhook_endpoint.signing_unavailable` | Webhook signing is not
            configured in this environment, so endpoints cannot be created or
            their secrets rotated. |
          x-error-codes:
            - webhook_endpoint.signing_unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                webhook_endpoint.signing_unavailable:
                  summary: >-
                    Webhook signing is not configured in this environment, so
                    endpoints cannot be created or their secrets rotated.
                  value:
                    error:
                      code: webhook_endpoint.signing_unavailable
                      message: >-
                        Webhook signing is not configured in this environment,
                        so endpoints cannot be created or their secrets rotated.
                      request_id: req_8e1a7f50-90ab-4cde-f012-3456789abcde
                      doc_url: >-
                        https://docs.endstate.io/errors/webhook-endpoint-signing-unavailable
      security:
        - ApiKeyBearer: []
components:
  schemas:
    CreateWebhookEndpointRequest:
      type: object
      properties:
        url:
          type: string
          maxLength: 2048
          format: uri
          description: HTTPS URL on a public host.
          example: https://hooks.example.com/endstate
        event_types:
          type: array
          items:
            type: string
            minLength: 1
          minItems: 1
          maxItems: 64
          example:
            - example.updated
        description:
          type: string
          maxLength: 512
        api_version:
          type: string
          pattern: ^\d{4}-\d{2}-\d{2}$
          description: >-
            Dated payload version; must be the current version or an older one
            the platform still renders.
          example: '2026-09-01'
      required:
        - url
        - event_types
    WebhookEndpointWithSecret:
      allOf:
        - $ref: '#/components/schemas/WebhookEndpoint'
        - type: object
          properties:
            secret:
              type: string
              description: >-
                Signing secret for this endpoint. Present on the first response
                only: an idempotent replay of the same request
                (`Idempotent-Replayed: true`) omits it. An admin API key can
                read it again through the secret endpoint; every read is
                recorded.
              example: whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw
    ErrorResponse:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              anyOf:
                - $ref: '#/components/schemas/ErrorCode'
                - type: string
              description: >-
                Stable, namespaced error code. The `ErrorCode` catalogue lists
                every code defined today; handle an unrecognized value as a
                generic failure rather than throwing, since codes are added over
                time.
              example: chip.not_found
            message:
              type: string
              description: >-
                Human-readable description, for logs and debugging. Wording may
                change without notice - never parse or match against it.
              example: Chip not found
            request_id:
              type: string
              description: >-
                Identifier for this request, matching the `X-Request-Id`
                response header. Log it and include it in any support request.
              example: req_8e1a7f50-90ab-4cde-f012-3456789abcde
            doc_url:
              type: string
              description: Documentation page for this error code.
              example: https://docs.endstate.io/errors/chip-not-found
            details:
              $ref: '#/components/schemas/ValidationErrorDetails'
          required:
            - code
            - message
            - request_id
            - doc_url
      required:
        - error
      description: >-
        Every error response, regardless of endpoint or HTTP status, uses this
        envelope.
    WebhookEndpoint:
      type: object
      properties:
        id:
          type: string
          format: uuid
          example: 8e1a7f50-90ab-4cde-8012-3456789abcde
        url:
          type: string
          format: uri
          description: HTTPS URL that receives deliveries.
          example: https://hooks.example.com/endstate
        event_types:
          type: array
          items:
            type: string
          description: Event types this endpoint is subscribed to.
          example:
            - example.updated
        description:
          type:
            - string
            - 'null'
        status:
          type: string
          enum:
            - enabled
            - disabled
          description: >-
            `disabled` on the first failed delivery after `fail_since` is five
            days old, after a 410 response, or when deleted. Re-enable with
            PATCH.
          example: enabled
        disabled_reason:
          type:
            - string
            - 'null'
        fail_since:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            When the current run of failed deliveries began, or null while
            deliveries succeed. The next failed delivery after this is five days
            old disables the endpoint, so fix the receiver before then.
          example: null
        api_version:
          type: string
          description: Dated payload version this endpoint receives.
          example: '2026-09-01'
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
        - id
        - url
        - event_types
        - description
        - status
        - disabled_reason
        - fail_since
        - api_version
        - created_at
        - updated_at
    ErrorCode:
      type: string
      enum:
        - environment.conflict
        - environment.invalid_configuration
        - organization.changed
        - validation.failed
        - auth.unauthorized
        - auth.forbidden
        - session_token.invalid_or_expired
        - session_token.wrong_chip
        - wallet_session.invalid_or_expired
        - not_found.resource
        - rate_limit.exceeded
        - chip.not_found
        - chip.invalid_e_value
        - chip.already_scanned
        - quota.exceeded
        - chip.not_a_test_chip
        - unit.not_found
        - unit.already_exists
        - unit.not_minted
        - collection.not_found
        - collection.already_exists
        - collection.not_active
        - collection_backfill.blocked
        - organization.not_found
        - chip.already_paired
        - chip.key_unusable
        - chip.mac_required
        - chip.bulk_mixed_collections
        - chip.bulk_pending
        - unit.issuance_pending
        - claim.owner_unknown
        - claim.already_to_recipient
        - claim.in_progress
        - claim.not_found
        - chip_replacement.locked
        - chip_replacement.in_progress
        - chip_replacement.not_found
        - transfer.owner_unknown
        - transfer.already_to_recipient
        - transfer.in_progress
        - transfer.not_found
        - submission.not_executable
        - vault.not_found
        - vault.already_exists
        - vault.provisioning_failed
        - vault.not_permitted
        - vault.unavailable
        - vault.challenge_invalid
        - vault.address_in_use
        - vault.key_conflict
        - vault.signer_unauthorized
        - vault_connection.not_found
        - vault_connection.not_active
        - vault_connection.already_exists
        - vault_connection.conflict
        - idempotency.key_conflict
        - idempotency.in_progress
        - internal.error
        - webhook_endpoint.not_found
        - webhook_endpoint.deleted
        - webhook_endpoint.limit_reached
        - webhook_endpoint.url_refused
        - webhook_endpoint.signing_unavailable
        - webhook_event_type.unknown
        - webhook_event.not_found
        - webhook_endpoint.disabled
        - webhook_delivery.in_progress
        - webhook_endpoint.not_subscribed
      description: >-
        Stable, namespaced error code in `<resource>.<reason>` form. Branch on
        this rather than on `message` or the HTTP status. This is the catalogue
        as of this spec revision, not a closed set - see
        `ErrorResponse.error.code`.
      example: chip.not_found
    ValidationErrorDetails:
      type: object
      properties:
        formErrors:
          type: array
          items:
            type: string
          description: Issues that apply to the request as a whole rather than one field.
          example: []
        fieldErrors:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
          description: Validation issues keyed by the field that failed.
          example:
            name:
              - Required
      required:
        - formErrors
        - fieldErrors
      description: Per-field validation detail. Present only on `validation.failed`.
  securitySchemes:
    ApiKeyBearer:
      type: http
      scheme: bearer
      bearerFormat: end_sk
      description: >-
        Use `Authorization: Bearer end_sk_*` for partner API keys (e.g.
        `end_sk_AbCd_example_api_key`).

````

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