openapi: 3.1.0
info:
  title: Webhooks & Events API — Headless AI SDR (Reply.io)
  version: "3.0"
  description: |
    Manage outbound webhook subscriptions and inspect delivery history.
    These endpoints are the management surface; event deliveries themselves are
    OUTBOUND — Reply POSTs a JSON payload to the subscription's URL when the event
    fires. Summary specification for AI agents; the authoritative, complete reference is
    https://docs.reply.io/api-reference/webhooks/list-webhook-subscriptions, the event
    catalog at https://docs.reply.io/webhook-events, and the full platform OpenAPI at
    https://docs.reply.io/api-reference/bundled.yaml.
  contact:
    name: Reply.io
    url: https://reply.io
servers:
  - url: https://api.reply.io/v3
security:
  - bearerAuth: []
tags:
  - name: Webhooks
paths:
  /webhooks:
    get:
      tags: [Webhooks]
      operationId: listWebhooks
      summary: List webhook subscriptions
      description: Requires the `webhooks:read` scope.
      responses:
        "200":
          description: List of webhook subscriptions.
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: "#/components/schemas/Webhook"
        "429":
          $ref: "#/components/responses/RateLimited"
    post:
      tags: [Webhooks]
      operationId: createWebhook
      summary: Create a webhook subscription
      description: |
        Requires the `webhooks:write` scope. Binds one event type to one receiver URL.
        `scope` defaults to `personal`; `organization` is reserved and currently rejected.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [eventType, url]
              properties:
                eventType:
                  type: string
                  description: |
                    Event type this subscription fires on. Must be one of the values
                    returned by GET /webhooks/events (e.g. email_replied).
                url:
                  type: string
                  format: uri
                  maxLength: 1024
                  description: Absolute http/https URL that receives the webhook payload.
                scope:
                  type: string
                  enum: [personal, team, organization]
                enabled:
                  type: boolean
                  default: true
                payloadConfig:
                  $ref: "#/components/schemas/WebhookPayloadConfig"
      responses:
        "201":
          description: Webhook subscription created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Webhook"
        "403":
          $ref: "#/components/responses/Forbidden"
  /webhooks/events:
    get:
      tags: [Webhooks]
      operationId: getWebhookEvents
      summary: List supported event types
      description: |
        Requires the `webhooks:read` scope. Returns every event type name a subscription
        can fire on — use any of them as the `eventType` field when creating or updating
        a subscription.
      responses:
        "200":
          description: Supported event types.
          content:
            application/json:
              schema:
                type: object
                properties:
                  events:
                    type: array
                    items:
                      type: string
                    description: Supported event type names (e.g. email_replied, email_bounced).
  /webhooks/{id}:
    get:
      tags: [Webhooks]
      operationId: getWebhook
      summary: Get a webhook subscription
      description: Requires the `webhooks:read` scope.
      parameters:
        - $ref: "#/components/parameters/webhookId"
      responses:
        "200":
          description: The webhook subscription.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Webhook"
    put:
      tags: [Webhooks]
      operationId: updateWebhook
      summary: Update a webhook subscription
      description: |
        Requires the `webhooks:write` scope. Full update — the `enabled` state cannot be
        changed through PUT; use the dedicated enable/disable endpoints.
      parameters:
        - $ref: "#/components/parameters/webhookId"
      responses:
        "200":
          description: Updated webhook subscription.
    delete:
      tags: [Webhooks]
      operationId: deleteWebhook
      summary: Delete a webhook subscription
      description: Requires the `webhooks:write` scope.
      parameters:
        - $ref: "#/components/parameters/webhookId"
      responses:
        "204":
          description: Deleted.
  /webhooks/{id}/enable:
    post:
      tags: [Webhooks]
      operationId: enableWebhook
      summary: Enable a webhook subscription
      description: Requires the `webhooks:operate` scope.
      parameters:
        - $ref: "#/components/parameters/webhookId"
      responses:
        "200":
          description: Subscription enabled (firing).
  /webhooks/{id}/disable:
    post:
      tags: [Webhooks]
      operationId: disableWebhook
      summary: Disable a webhook subscription
      description: |
        Requires the `webhooks:operate` scope. Stops deliveries without deleting the
        subscription's configuration.
      parameters:
        - $ref: "#/components/parameters/webhookId"
      responses:
        "200":
          description: Subscription disabled.
  /webhooks/{id}/test:
    post:
      tags: [Webhooks]
      operationId: sendTestPayload
      summary: Send a test payload
      description: |
        Requires the `webhooks:operate` scope. Sends a test payload to the subscription's
        URL so the receiver can be verified before real events flow.
      parameters:
        - $ref: "#/components/parameters/webhookId"
      responses:
        "200":
          description: Test payload sent to the subscription's URL.
  /webhooks/{id}/logs:
    get:
      tags: [Webhooks]
      operationId: getWebhookDeliveryLogs
      summary: Get webhook delivery logs
      description: |
        Requires the `webhooks:read` scope. Paginated FAILURE log for a single
        subscription — only failed delivery attempts are recorded; successful deliveries
        are not listed. Each entry captures the triggering event id, the HTTP status
        (null when the request could not be completed), and the UTC timestamp of the
        attempt.
      parameters:
        - $ref: "#/components/parameters/webhookId"
      responses:
        "200":
          description: Paginated failure log of delivery attempts.
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: |
        Reply.io API key sent as a Bearer token. Create one in the Reply.io app under
        Settings → API Key. See https://docs.reply.io/api-reference/authentication.
  parameters:
    webhookId:
      name: id
      in: path
      required: true
      schema:
        type: integer
      description: Webhook subscription identifier.
  schemas:
    Webhook:
      type: object
      properties:
        id:
          type: integer
          readOnly: true
        eventType:
          type: string
          description: Event type this subscription fires on (e.g. email_replied).
        url:
          type: string
          format: uri
          description: Absolute http/https URL that receives the webhook payload.
        scope:
          type: string
          enum: [personal, team, organization]
          description: |
            personal fires only for the owner's activity; team fires for any member of
            the owner's team; organization is reserved for future use.
        enabled:
          type: boolean
          description: |
            If false, the subscription does not fire. Toggle via the enable/disable
            endpoints — the state cannot be changed through PUT.
        createdAt:
          type: string
          format: date-time
        payloadConfig:
          $ref: "#/components/schemas/WebhookPayloadConfig"
    WebhookPayloadConfig:
      type: object
      description: Optional flags that enrich the delivered payload.
      properties:
        includeEmailUrl:
          type: boolean
        includeEmailText:
          type: boolean
        includeProspectCustomFields:
          type: boolean
    Problem:
      type: object
      description: RFC 7807 problem document (application/problem+json).
      properties:
        type: { type: string }
        title: { type: string }
        status: { type: integer }
        detail: { type: string }
  responses:
    Forbidden:
      description: The API key is missing a required scope.
      content:
        application/problem+json:
          schema:
            $ref: "#/components/schemas/Problem"
    RateLimited:
      description: |
        Rate limit exceeded (100 requests/minute, 3,000/hour per user). Honor the
        Retry-After header.
      content:
        application/problem+json:
          schema:
            $ref: "#/components/schemas/Problem"
