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

# Register a webhook endpoint

> Register an endpoint and get its signing secret, once.



## OpenAPI

````yaml /openapi.yaml post /v1/webhooks
openapi: 3.1.0
info:
  title: Nylon API
  version: 1.0.0
  description: |
    One API for publishing to twelve social networks.

    You address a post to connected profile ids; Nylon knows which network each
    one belongs to, what that network accepts, and how to get the media there.
    Character limits, media specs, upload protocols and threading rules are
    normalised before the request reaches a platform, and every failure comes
    back in one error taxonomy.

    ## Conventions

    - Request and response fields are `snake_case`.
    - Successful responses wrap the payload in `data`. List responses add
      `meta.pagination`.
    - Failures return `{ "error": { "code", "message", "details?" } }`.
      Branch on `code`; `message` is written for humans and may change.
    - Times are ISO 8601 with a `Z` offset.
    - Successful responses carry `RateLimit-Limit`, `RateLimit-Remaining` and
      `RateLimit-Reset`. A `429` carries those plus `Retry-After`.
servers:
  - url: https://api.nylon.dev
    description: Production
security:
  - bearerAuth: []
tags:
  - name: Posts
    description: Create, schedule, inspect, edit and retry posts.
  - name: Profiles
    description: Social profiles connected to the authenticated Nylon account.
  - name: Connections
    description: Start a connection and see which networks are available.
  - name: Networks
    description: What each network accepts, as data.
  - name: Validation
    description: Dry-run a post without publishing it.
  - name: Webhooks
    description: Endpoints Nylon calls when a post finishes or a profile stops working.
paths:
  /v1/webhooks:
    post:
      tags:
        - Webhooks
      summary: Register a webhook endpoint
      description: |
        Registers an endpoint and returns its signing secret.

        The secret is in this response and in no other one. Store it before you
        move on; if you lose it, rotate rather than asking for it back — an
        endpoint that hands out signing secrets would turn a leaked API key
        into forged events.

        `url` must be `https`. Omit `events` to receive every event.
      operationId: createWebhook
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateWebhookRequest'
            examples:
              everything:
                summary: Every event
                value:
                  url: https://example.com/nylon/webhooks
                  description: Production receiver
              failuresOnly:
                summary: Only the bad news
                value:
                  url: https://example.com/nylon/webhooks
                  events:
                    - post.failed
                    - post.partially_published
                    - profile.needs_attention
                    - profile.disconnected
      responses:
        '201':
          description: The endpoint, including its signing secret.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookWithSecretResponse'
        '400':
          $ref: '#/components/responses/InvalidRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '409':
          description: The endpoint limit for this account is already reached.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
components:
  schemas:
    CreateWebhookRequest:
      type: object
      required:
        - url
      properties:
        url:
          type: string
          format: uri
          description: An `https` URL. Private and link-local addresses are refused.
        description:
          type:
            - string
            - 'null'
          maxLength: 200
        events:
          type:
            - array
            - 'null'
          description: Events to subscribe to. Omit for every event.
          items:
            $ref: '#/components/schemas/WebhookEvent'
    WebhookWithSecretResponse:
      type: object
      required:
        - data
      properties:
        data:
          $ref: '#/components/schemas/WebhookWithSecret'
    ErrorResponse:
      type: object
      required:
        - error
      properties:
        error:
          $ref: '#/components/schemas/Error'
    WebhookEvent:
      type: string
      enum:
        - post.published
        - post.partially_published
        - post.failed
        - profile.connected
        - profile.disconnected
        - profile.needs_attention
    WebhookWithSecret:
      allOf:
        - $ref: '#/components/schemas/Webhook'
        - type: object
          required:
            - secret
          properties:
            secret:
              type: string
              description: |
                The signing secret, returned by creation and rotation only.
                Store it now — it is not readable afterwards.
              example: whsec_9tK2mQ7pR4wX1bN6vC3zL8yF
    Error:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: string
          description: The stable identifier to branch on.
          enum:
            - invalid_request
            - unauthorized
            - payment_required
            - forbidden
            - not_found
            - conflict
            - rate_limited
            - unsupported
            - publish_failed
            - internal_error
          example: unauthorized
        message:
          type: string
          description: Written for humans. Do not match on it.
          example: A valid Nylon API key is required.
        details:
          type: array
          description: Present when the failure has a per-field or per-network breakdown.
          items:
            $ref: '#/components/schemas/ErrorDetail'
    Webhook:
      type: object
      required:
        - id
        - url
        - events
        - status
        - secret_last_four
        - consecutive_failures
        - created_at
        - updated_at
      properties:
        id:
          type: string
          example: cly7w1a2b0001x8b3k9m2p0zz
        url:
          type: string
          format: uri
          example: https://example.com/nylon/webhooks
        description:
          type:
            - string
            - 'null'
          example: Production receiver
        events:
          type: array
          description: Subscribed events. An empty array means every event.
          items:
            $ref: '#/components/schemas/WebhookEvent'
        status:
          type: string
          enum:
            - active
            - disabled
          description: Nylon disables an endpoint after 20 consecutive failed deliveries.
        disabled_reason:
          type:
            - string
            - 'null'
        secret_last_four:
          type: string
          description: >-
            The last four characters of the signing secret, to tell two secrets
            apart.
          example: 8f2a
        consecutive_failures:
          type: integer
          description: >-
            Failed deliveries since the last success. Any success resets it to
            zero.
          example: 0
        last_succeeded_at:
          type:
            - string
            - 'null'
          format: date-time
        last_failed_at:
          type:
            - string
            - 'null'
          format: date-time
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    ErrorDetail:
      type: object
      required:
        - message
      properties:
        field:
          type: string
          description: The request field the problem is about.
          example: profile_ids
        network:
          type: string
          description: The network the problem is about.
          example: instagram
        code:
          type: string
          description: |
            Machine-readable identifier for this problem. On a per-network
            detail this is a publishing code: `invalid_request`,
            `unsupported`, `media_error`, `reauthentication_required`,
            `rejected_by_network`, `network_error`, `timeout`,
            `profile_unavailable` or `internal_error`.
          example: invalid_request
        message:
          type: string
          example: >-
            Instagram requires at least 1 media item — text-only posts are not
            supported.
  responses:
    InvalidRequest:
      description: The request body or query is not valid.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            badField:
              value:
                error:
                  code: invalid_request
                  message: The request body is not valid.
                  details:
                    - field: profile_ids
                      message: Address the post to at least one profile.
    Unauthorized:
      description: The bearer API key is missing, malformed or revoked.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            missingKey:
              value:
                error:
                  code: unauthorized
                  message: A valid Nylon API key is required.
    RateLimited:
      description: |
        Too many requests for this API key. Reads allow 120 requests a minute;
        publishing endpoints allow 30, because each one costs real upstream
        calls. The limit is per key, not per IP.
      headers:
        Retry-After:
          $ref: '#/components/headers/RetryAfter'
        RateLimit-Limit:
          $ref: '#/components/headers/RateLimitLimit'
        RateLimit-Remaining:
          $ref: '#/components/headers/RateLimitRemaining'
        RateLimit-Reset:
          $ref: '#/components/headers/RateLimitReset'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            throttled:
              value:
                error:
                  code: rate_limited
                  message: Too many requests. Retry after the window resets.
    InternalError:
      description: Nylon encountered an unexpected error.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
  headers:
    RetryAfter:
      description: Seconds to wait before retrying.
      schema:
        type: integer
        example: 47
    RateLimitLimit:
      description: Requests allowed in the current window.
      schema:
        type: integer
        example: 120
    RateLimitRemaining:
      description: Requests left in the current window.
      schema:
        type: integer
        example: 119
    RateLimitReset:
      description: Seconds until the window resets.
      schema:
        type: integer
        example: 47
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: Nylon API key
      description: An API key beginning with `nylon_live_`.

````