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

# Create a webhook subscription

> Subscribes a URL to one or more event types. This response is the only
time the subscription `secret` is returned: store it to verify the
signatures.

- **URL**: HTTPS only; no private or local address; no credentials in
  the URL. A refused URL returns `400 invalid_request` with
  `details.parameter: url` and the cause in `details.reason`.
- **Events**: at least one; duplicates are accepted and ignored.
- **Limit**: 20 active subscriptions per workspace. Beyond that, the
  API returns `400 invalid_request` with `details.max`.
- **Ownership**: the subscription belongs to the workspace; workspace
  admins can see and delete it in Settings → API. Revoking the key
  that creates it deletes the subscription as well, unless the admin
  unticks that option in Settings → API. The key is also revoked, with
  its subscriptions, when the admin who created it leaves the
  workspace, loses the admin role or deletes their account.

**Delivery** (the `delivery` callback below): each event is sent as a
`POST` to the subscribed URL, with a `WebhookDelivery` JSON body,
`Content-Type: application/json` and `User-Agent: Agentova-Webhooks/1.0`.

- **Signature**: `X-Agentova-Signature: t=<unix timestamp>,v1=<hex>`,
  where `v1` is the HMAC-SHA256 of the string `{t}.{raw body}`, keyed
  with the complete `secret` (the whole `whsec_…` string). Compare in
  constant time and reject a `t` more than 5 minutes away from your
  clock (recommended tolerance).
- **Success**: a 2xx status received within 10 seconds (deadline for
  the whole response). The response body is ignored. Redirects are not
  followed: a 3xx is a failure, like a timeout or a network error.
- **Retries**: 8 attempts in total, spread over about 27 hours 35
  minutes. The first attempt is immediate; after each failure, the
  next one comes 5 seconds, 5 minutes, 30 minutes, 2 hours, 5 hours,
  10 hours and finally 10 hours later. On `429` or `503` with a
  `Retry-After` header, the next attempt waits at least that long
  (12 hours at most). No attempt is scheduled more than 36 hours
  after the event was created: the delivery is abandoned instead.
- **`410 Gone`**: the subscription is deleted immediately, without
  notification. Answer `410` to unsubscribe.
- **Disabling**: a delivery is abandoned after its 8th failed attempt,
  or earlier at the 36-hour limit. The
  subscription is then disabled (`disabled_at`) if it has at least 3
  abandoned deliveries in a row and has been failing without
  interruption for at least 72 hours, or at once if its URL no longer
  passes the address checks; workspace admins are notified. A
  disabled subscription cannot be re-enabled: delete it and create a
  new one (Zapier: turn the Zap off and on again; n8n: deactivate and
  reactivate the workflow). It is deleted automatically 30 days later.
- **At least once, in no guaranteed order**: deduplicate on the event
  `id` (`evt_…`), which is the same on every attempt and for every
  subscription (keep seen ids for at least 48 hours); order events
  with the timestamp of the resource in `data`, not with their arrival
  order.




## OpenAPI

````yaml /openapi/openapi-v1.yaml post /webhooks
openapi: 3.0.3
info:
  title: Agentova Public API
  version: 1.0.0
  termsOfService: https://agentova.ai/legal/terms-of-use
  license:
    name: Proprietary — Agentova terms of use
    url: https://agentova.ai/legal/terms-of-use
  contact:
    name: Agentova support
    email: contact@agentova.ai
    url: https://docs.agentova.ai
  description: >
    The Agentova Public API lets your own code, Zapier or n8n work with an

    Agentova workspace: read its automations, runs and leads, pause and resume

    its automations, and receive events through signed webhooks.



    ## Base URL and authentication


    All endpoints are served over HTTPS under `https://core-api.agentova.ai/v1`.

    Every request carries an API key, created in the Agentova app

    (Settings → API), in the `Authorization` header:

    `Authorization: Bearer agk_live_…`


    - A key belongs to one workspace and gives access to the whole workspace.
      The key identifies the workspace: no workspace identifier is ever sent.
    - Every key starts with `agk_live_`. There are no test keys and no separate
      test environment: to experiment safely, use a dedicated workspace.
    - A revoked key is refused immediately, on every endpoint.

    - The API is meant to be called from a server. It sends no CORS headers,
      so a web page cannot call it from a browser, and an `OPTIONS` request
      receives an error in the format described under Errors.


    ## Stability


    This is version 1.0.0 of the v1 API, and v1 is stable: no breaking change

    will be made under `/v1`. Additive changes can still happen: new optional

    fields, new event types, new enum values. Your client must ignore the

    fields, event types and enum values it does not know.



    ## Coverage


    - **Automations**: the messaging automations of the workspace on Meta
      networks (`facebook`, `instagram`, `instagram_page`), WhatsApp
      (`whatsapp`) and e-mail (`gmail`, `microsoft_outlook`, `imap`), with the
      types `social_comments`, `social_story`, `social_messages`, `lead_ads`
      and `email_messages`, plus the CRM sources (`crm_source`). They can all
      be read, and paused or resumed with `PATCH`.
    - **Leads**: from the sources `widget`, `lead_ads`, `telephony`, `social`
      and `crm`.
    - **Runs**: see the `Run` schema for the automations that produce runs.

    - **Webhook events**: `lead.created`, `run.completed` and
      `automation.status_changed`.


    ## Conventions


    - **Identifiers** are opaque strings prefixed by their type: `aut_`
      (automation), `agt_` (agent), `run_` (run), `lea_` (lead), `whk_`
      (webhook subscription), `evt_` (event). Store them and send them back
      unchanged; never validate or parse them (length, alphabet). They are not
      UUIDs.
    - **Dates** are ISO 8601, in UTC, with the `Z` suffix.

    - **Unknown query parameters** are ignored, never rejected, so that a
      client written for a later version keeps working.
    - **Request bodies** are JSON, sent with `Content-Type: application/json`,
      and limited to 16 KB. Another content type is refused with HTTP `415`,
      a larger body with HTTP `413`, both with the code `invalid_request`.
    - **Caching**: every response carries `Cache-Control: no-store`, because
      responses contain personal data.


    ## Pagination


    Lists are paginated with an opaque cursor. `limit` takes a value from 1 to

    100 (25 by default); a value out of range is refused with `400`, not

    corrected. A page looks like

    `{ "data": [...], "has_more": true, "next_cursor": "..." }`: to get the

    next page, send `next_cursor` back as `cursor`. A missing or empty

    `cursor`, or the literal word `null`, means the first page.

    `GET /webhooks` is not paginated.



    ## Rate limits


    - Each API key can make about 100 requests per minute. Requests are
      counted per server instance, so this limit is approximate.
    - Responses carry `X-RateLimit-Limit`, `X-RateLimit-Remaining` and
      `X-RateLimit-Reset` (seconds until the window resets, not a timestamp),
      `401` and `403` responses included.
    - Above the limit, the API answers `429 rate_limited` with a `Retry-After`
      header, in seconds.
    - More than 30 authentication failures per minute from the same IP address
      also lead to `429`. This never applies to requests made with a valid
      key.


    ## Errors


    Every 4xx and 5xx response has the same body:

    `{ "error": { "code": "...", "message": "...", "details": {} } }`.


    - `code` is stable and comes from a closed list (`ErrorCode`): branch on
      it.
    - `message` is in English, meant to be shown to a person, and can change
      at any time.
    - `details` is always an object: empty, or giving context such as the
      faulty `parameter` and a `reason`.

    | HTTP status | `code` | Meaning |

    |---|---|---|

    | 400 | `invalid_request` | Invalid query parameter or body
    (`details.parameter`) |

    | 413, 415 | `invalid_request` | Body larger than 16 KB, or unsupported
    content type (`details.reason`) |

    | 401 | `invalid_api_key` | Missing, malformed, unknown or revoked key |

    | 403 | `workspace_access_denied` | The workspace's subscription does not
    allow API access |

    | 404 | `automation_not_found` | No such automation in this workspace |

    | 404 | `webhook_not_found` | No such webhook subscription in this workspace
    |

    | 404 | `route_not_found` | Unknown path or method under `/v1` (never `405`)
    |

    | 422 | `automation_not_controllable` | `PATCH` on an automation in `draft`
    or `error` (`details.status`), or resuming an e-mail automation whose
    mailbox another active agent already uses (`details.reason: account_in_use`)
    |

    | 429 | `rate_limited` | Rate limit exceeded: wait `Retry-After` seconds |

    | 500 | `internal_error` | Unexpected error (generic message) |

    | 503 | `service_unavailable` | The API is temporarily switched off by
    Agentova: retry later |



    ## Webhooks


    Create a subscription with `POST /webhooks`. Agentova then sends every

    event of the subscribed types as a `POST` request to your URL; the body is

    described by the `delivery` callback of `POST /webhooks`.


    - **Request**: a `POST` with `Content-Type: application/json` and
      `User-Agent: Agentova-Webhooks/1.0`.
    - **Signature**: each delivery carries
      `X-Agentova-Signature: t=<unix timestamp>,v1=<hex digest>`. The digest
      is the HMAC-SHA256 of the string `{t}.{raw request body}`, keyed with the
      complete subscription `secret`, `whsec_` prefix included. Compare digests
      in constant time, and reject a delivery whose `t` is more than 5 minutes
      away from your clock (recommended tolerance). The official Zapier app
      accepts 1 hour, because Zapier can process hooks late and the hook URL
      is itself a secret.
    - **Success** is a 2xx status received within 10 seconds (a deadline for
      the whole response). The response body is ignored. Redirects are not
      followed: a 3xx is a failure.
    - **Retries**: 8 attempts spread over about 27 hours 35 minutes. The first
      attempt is immediate; after each failure, the next one comes 5 seconds,
      5 minutes, 30 minutes, 2 hours, 5 hours, 10 hours and finally 10 hours
      later. When your endpoint answers `429` or `503` with a `Retry-After`
      header, the next attempt waits at least that long, up to 12 hours. No
      attempt is ever scheduled more than 36 hours after the event was
      created: when the next one would be, the delivery is abandoned.
    - **`410 Gone`** deletes the subscription immediately, without any
      notification: answer `410` to unsubscribe (this is how Zapier reports a
      deleted Zap).
    - **Disabling**: a delivery is abandoned after its 8th failed attempt, or
      earlier when it reaches the 36-hour limit. The
      subscription is then disabled if it has at least 3 abandoned deliveries
      in a row and has been failing without interruption for at least 72
      hours. It is also disabled at once, without any delivery, if its URL no
      longer passes the address checks (an IP address that became forbidden).
      Workspace admins are notified in the app and by push
      notification. A disabled subscription receives nothing and cannot be
      re-enabled: delete it and create a new one (Zapier: turn the Zap off and
      on again; n8n: deactivate and reactivate the workflow). Disabled
      subscriptions are deleted automatically 30 days after being disabled.
    - **At least once, in no guaranteed order**: the same event can be
      delivered more than once, and events can arrive out of order.
      Deduplicate on the event `id` (`evt_…`): it is the same on every attempt
      and for every subscription that receives the event; keep the ids you
      have seen for at least 48 hours: retries are always scheduled within 36
      hours of the event's creation. To order events,
      use the timestamp of the resource in `data` (`updated_at` of an
      automation, `created_at` of a lead, `occurred_at` of a run), not the
      arrival order.
    - **Ownership**: subscriptions belong to the workspace; workspace admins
      see and delete them in Settings → API. Revoking the key that created a
      subscription deletes the subscription as well, unless the admin unticks
      that option in Settings → API. A key is also revoked, with its
      subscriptions, when the admin who created it leaves the workspace,
      loses the admin role or deletes their account.
    - **Retention**: the webhook delivery log is kept for 30 days, and runs
      for 90 days.
    - **While the API is switched off** (`503 service_unavailable`), no
      delivery is created for the events that happen in the meantime, and the
      deliveries already in progress are suspended: they resume when the API
      is back. Catch up on the missed events with the list endpoints.


    ## Support


    Documentation: https://docs.agentova.ai. Contact: contact@agentova.ai.
servers:
  - url: https://core-api.agentova.ai/v1
    description: Production, the only environment (there is no separate test environment)
security:
  - bearerAuth: []
paths:
  /webhooks:
    post:
      summary: Create a webhook subscription
      description: >
        Subscribes a URL to one or more event types. This response is the only

        time the subscription `secret` is returned: store it to verify the

        signatures.


        - **URL**: HTTPS only; no private or local address; no credentials in
          the URL. A refused URL returns `400 invalid_request` with
          `details.parameter: url` and the cause in `details.reason`.
        - **Events**: at least one; duplicates are accepted and ignored.

        - **Limit**: 20 active subscriptions per workspace. Beyond that, the
          API returns `400 invalid_request` with `details.max`.
        - **Ownership**: the subscription belongs to the workspace; workspace
          admins can see and delete it in Settings → API. Revoking the key
          that creates it deletes the subscription as well, unless the admin
          unticks that option in Settings → API. The key is also revoked, with
          its subscriptions, when the admin who created it leaves the
          workspace, loses the admin role or deletes their account.

        **Delivery** (the `delivery` callback below): each event is sent as a

        `POST` to the subscribed URL, with a `WebhookDelivery` JSON body,

        `Content-Type: application/json` and `User-Agent:
        Agentova-Webhooks/1.0`.


        - **Signature**: `X-Agentova-Signature: t=<unix timestamp>,v1=<hex>`,
          where `v1` is the HMAC-SHA256 of the string `{t}.{raw body}`, keyed
          with the complete `secret` (the whole `whsec_…` string). Compare in
          constant time and reject a `t` more than 5 minutes away from your
          clock (recommended tolerance).
        - **Success**: a 2xx status received within 10 seconds (deadline for
          the whole response). The response body is ignored. Redirects are not
          followed: a 3xx is a failure, like a timeout or a network error.
        - **Retries**: 8 attempts in total, spread over about 27 hours 35
          minutes. The first attempt is immediate; after each failure, the
          next one comes 5 seconds, 5 minutes, 30 minutes, 2 hours, 5 hours,
          10 hours and finally 10 hours later. On `429` or `503` with a
          `Retry-After` header, the next attempt waits at least that long
          (12 hours at most). No attempt is scheduled more than 36 hours
          after the event was created: the delivery is abandoned instead.
        - **`410 Gone`**: the subscription is deleted immediately, without
          notification. Answer `410` to unsubscribe.
        - **Disabling**: a delivery is abandoned after its 8th failed attempt,
          or earlier at the 36-hour limit. The
          subscription is then disabled (`disabled_at`) if it has at least 3
          abandoned deliveries in a row and has been failing without
          interruption for at least 72 hours, or at once if its URL no longer
          passes the address checks; workspace admins are notified. A
          disabled subscription cannot be re-enabled: delete it and create a
          new one (Zapier: turn the Zap off and on again; n8n: deactivate and
          reactivate the workflow). It is deleted automatically 30 days later.
        - **At least once, in no guaranteed order**: deduplicate on the event
          `id` (`evt_…`), which is the same on every attempt and for every
          subscription (keep seen ids for at least 48 hours); order events
          with the timestamp of the resource in `data`, not with their arrival
          order.
      operationId: createWebhook
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - url
                - events
              properties:
                url:
                  type: string
                  format: uri
                  description: >
                    URL that receives the deliveries. HTTPS is required; no
                    private or local address; no credentials in the URL.
                events:
                  type: array
                  minItems: 1
                  description: Event types to receive (at least one).
                  items:
                    $ref: '#/components/schemas/WebhookEvent'
            example:
              url: https://hooks.zapier.com/hooks/standard/xxxxx/
              events:
                - lead.created
      responses:
        '201':
          description: >
            Subscription created. The `secret` is returned only in this
            response.
          headers:
            Cache-Control:
              $ref: '#/components/headers/Cache-Control'
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Webhook'
                  - type: object
                    required:
                      - secret
                    properties:
                      secret:
                        type: string
                        description: >
                          Signing secret (`whsec_…`), shown only once. The
                          complete string, prefix included, is the HMAC key used
                          to sign the deliveries.
              example:
                id: whk_01HZX6X7Y8Z9A0B1C2D3E4F5G6
                url: https://hooks.zapier.com/hooks/standard/xxxxx/
                events:
                  - lead.created
                created_at: '2026-08-20T09:25:00Z'
                disabled_at: null
                secret: whsec_5f8a3c1e9b2d4f6a8c0e2b4d6f8a0c2e
        '400':
          description: >
            Invalid body: `details.parameter` names the field (`url`, `events`,
            `body`); for `url`, `details.reason` says why (`https_required`,
            `credentials_in_url`, `local_address`, `private_address`,
            `unresolvable_host`, `invalid_url`, `url_too_long`); when the limit
            of active subscriptions is reached, `details.max` gives it.
          headers:
            Cache-Control:
              $ref: '#/components/headers/Cache-Control'
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '413':
          $ref: '#/components/responses/PayloadTooLarge'
        '415':
          $ref: '#/components/responses/UnsupportedMediaType'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
      callbacks:
        delivery:
          '{$request.body#/url}':
            post:
              summary: Event delivery to the subscribed URL
              description: >
                Sent by Agentova for each event of the subscribed types. Answer
                with a 2xx status within 10 seconds. A timeout, a network error
                or any other status is a failure, retried on the schedule
                described in `POST /webhooks`.
              security: []
              requestBody:
                required: true
                content:
                  application/json:
                    schema:
                      $ref: '#/components/schemas/WebhookDelivery'
              parameters:
                - name: X-Agentova-Signature
                  in: header
                  required: true
                  description: >
                    `t=<unix timestamp>,v1=<hex digest>`, where the digest is
                    the HMAC-SHA256 of `{t}.{raw request body}`, keyed with the
                    complete subscription secret (`whsec_` prefix included).
                    Recommended tolerance on `t`: 5 minutes.
                  schema:
                    type: string
                  example: >-
                    t=1724145600,v1=5f8a3c1e9b2d4f6a8c0e2b4d6f8a0c2e5f8a3c1e9b2d4f6a8c0e2b4d6f8a0c2e
                - name: User-Agent
                  in: header
                  required: true
                  description: Always `Agentova-Webhooks/1.0`.
                  schema:
                    type: string
                    enum:
                      - Agentova-Webhooks/1.0
              responses:
                '410':
                  description: >
                    Unsubscribe: the subscription is deleted immediately,
                    without notification, and nothing is retried.
                2XX:
                  description: Delivery acknowledged (the response body is ignored)
                4XX:
                  description: >
                    Failure: retried on the schedule (8 attempts over about 27
                    hours 35 minutes), then abandoned. On `429`, a `Retry-After`
                    header is respected, up to 12 hours.
                5XX:
                  description: >
                    Failure: retried on the schedule (8 attempts over about 27
                    hours 35 minutes), then abandoned. On `503`, a `Retry-After`
                    header is respected, up to 12 hours.
              method: post
              type: path
            path: '{$request.body#/url}'
components:
  schemas:
    WebhookEvent:
      type: string
      description: |
        - `lead.created`: a lead was created (`data` is a `Lead`).
        - `run.completed`: an automation completed a run (`data` is a `Run`).
        - `automation.status_changed`: the status of an automation changed
          (`data` is an `Automation`).
      enum:
        - run.completed
        - lead.created
        - automation.status_changed
    Webhook:
      type: object
      description: >
        A webhook subscription. It belongs to the workspace. Revoking the API
        key that created it deletes it as well, unless the admin unticks that
        option in Settings → API.
      required:
        - id
        - url
        - events
        - created_at
        - disabled_at
      properties:
        id:
          type: string
          description: Opaque identifier prefixed with `whk_`.
        url:
          type: string
          format: uri
          description: URL that receives the deliveries.
        events:
          type: array
          description: Event types sent to this URL.
          items:
            $ref: '#/components/schemas/WebhookEvent'
        created_at:
          type: string
          format: date-time
          description: When the subscription was created.
        disabled_at:
          type: string
          format: date-time
          nullable: true
          description: >
            Set when Agentova disabled the subscription, typically after
            prolonged delivery failures (see `POST /webhooks`); `null`
            otherwise. A disabled subscription receives nothing and cannot be
            re-enabled: delete it and create a new one. It is deleted
            automatically 30 days after this date.
    ErrorResponse:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
            - details
          properties:
            code:
              $ref: '#/components/schemas/ErrorCode'
            message:
              type: string
              description: >
                In English, meant to be displayed; it can change without notice
                (branch on `code`).
            details:
              type: object
              description: >
                Empty (`{}`) or context: `parameter`, `allowed`, `max`,
                `reason`, `status`, `retry_after_seconds`…
    WebhookDelivery:
      description: >
        Body sent to the subscribed URL. `type` (a `WebhookEvent` value)
        determines the shape of `data`: a `Lead` for `lead.created`, a `Run` for
        `run.completed`, an `Automation` for `automation.status_changed`.
      oneOf:
        - $ref: '#/components/schemas/LeadCreatedDelivery'
        - $ref: '#/components/schemas/RunCompletedDelivery'
        - $ref: '#/components/schemas/AutomationStatusChangedDelivery'
      discriminator:
        propertyName: type
        mapping:
          lead.created: '#/components/schemas/LeadCreatedDelivery'
          run.completed: '#/components/schemas/RunCompletedDelivery'
          automation.status_changed: '#/components/schemas/AutomationStatusChangedDelivery'
      example:
        id: evt_01HZX7B2C3D4E5F6G7H8J9K0L1
        type: lead.created
        created_at: '2026-08-20T09:20:01Z'
        data:
          id: lea_01HZX5M2N3P4Q5R6S7T8V9W0X1
          source: lead_ads
          agent_id: agt_01HZX3Q8K5N7P2R4S6T8V0W2Y5
          name: Jane Doe
          email: jane.doe@example.com
          phone: '+33612345678'
          custom_fields: {}
          created_at: '2026-08-20T09:20:00Z'
    ErrorCode:
      type: string
      description: >
        Stable error codes. `invalid_request` (400; also 413 when the body is
        larger than 16 KB and 415 for an unsupported content type: the HTTP
        status is kept and the cause is in `details.reason`) · `invalid_api_key`
        (401) · `workspace_access_denied` (403) · `automation_not_found` (404) ·
        `webhook_not_found` (404) · `route_not_found` (404: unknown path or
        method) · `automation_not_controllable` (422: automation in `draft` or
        `error`, see `details.status`) · `rate_limited` (429) · `internal_error`
        (500, generic message) · `service_unavailable` (503: the API is
        temporarily switched off by Agentova; retry later).
      enum:
        - invalid_request
        - invalid_api_key
        - workspace_access_denied
        - automation_not_found
        - webhook_not_found
        - route_not_found
        - automation_not_controllable
        - rate_limited
        - internal_error
        - service_unavailable
    LeadCreatedDelivery:
      description: >
        Sent only when a lead is created, never when an existing lead is updated
        (for example by a form submitted again). `data` is the lead, with the
        same shape as in `GET /leads`.
      allOf:
        - $ref: '#/components/schemas/WebhookDeliveryBase'
        - type: object
          required:
            - type
            - data
          properties:
            type:
              type: string
              enum:
                - lead.created
            data:
              $ref: '#/components/schemas/Lead'
    RunCompletedDelivery:
      description: >
        Sent when a run is recorded. `data` is the run, with the same shape as
        in `GET /runs`.
      allOf:
        - $ref: '#/components/schemas/WebhookDeliveryBase'
        - type: object
          required:
            - type
            - data
          properties:
            type:
              type: string
              enum:
                - run.completed
            data:
              $ref: '#/components/schemas/Run'
    AutomationStatusChangedDelivery:
      description: >
        Sent only when the status of an automation really changes, whether the
        change comes from the Agentova app or from the API (your own `PATCH`
        calls included), and also when a CRM source is activated. Nothing is
        sent when a request leaves the status unchanged. `data` is the
        automation after the change. When a failure removes an automation from
        the API (revoked token, mailbox authentication refused, reconnection
        impossible), a last event is sent with `status: error`, after which the
        automation is no longer listed. When the account is reconnected, an
        event with `status: active` is sent for each automation that comes back.
        Deleting an automation sends no event.
      allOf:
        - $ref: '#/components/schemas/WebhookDeliveryBase'
        - type: object
          required:
            - type
            - data
          properties:
            type:
              type: string
              enum:
                - automation.status_changed
            data:
              $ref: '#/components/schemas/Automation'
    WebhookDeliveryBase:
      type: object
      required:
        - id
        - created_at
      properties:
        id:
          type: string
          description: >
            Opaque identifier prefixed with `evt_`, unique per event: use it to
            deduplicate. It is the same on every delivery attempt and for every
            subscription that receives the event.
        created_at:
          type: string
          format: date-time
          description: When the event was generated.
    Lead:
      type: object
      description: A contact captured by one of the workspace's agents.
      required:
        - id
        - source
        - agent_id
        - name
        - email
        - phone
        - custom_fields
        - created_at
      properties:
        id:
          type: string
          description: Opaque identifier prefixed with `lea_`.
        source:
          $ref: '#/components/schemas/LeadSource'
        agent_id:
          type: string
          description: >
            Opaque identifier, prefixed with `agt_`, of the agent that captured
            the lead (telephony agents included).
        name:
          type: string
          nullable: true
          description: Name as captured, or `null`.
        email:
          type: string
          nullable: true
          description: E-mail address as captured, or `null`.
        phone:
          type: string
          nullable: true
          description: >
            Phone number exactly as entered or captured, or `null`. It is not
            normalized: its format varies from one source to another.
        custom_fields:
          type: object
          description: >
            Additional data captured with the lead (for example the answers to a
            Lead Ads form), as key-value pairs. Keys that start with `_` are
            internal to Agentova and are never returned.
        created_at:
          type: string
          format: date-time
          description: When the lead was created in Agentova.
    Run:
      type: object
      description: |
        One execution of an automation: what triggered it and what it did.

        Runs are produced by the messaging automations (comments, stories,
        private messages, e-mails), by the Lead Ads automations, and by the CRM
        automations that have an agent: one run per person of a Customer.io
        segment handled, and one run per action received from a CRM workflow
        (for example HubSpot, Close or Typeform). The website widget produces
        no runs. Runs are kept for 90 days.
      required:
        - id
        - automation_id
        - status
        - trigger_type
        - occurred_at
        - actions
        - lead_id
      properties:
        id:
          type: string
          description: Opaque identifier prefixed with `run_`.
        automation_id:
          type: string
          description: Opaque identifier prefixed with `aut_`.
        status:
          type: string
          description: >
            `success`: no action failed (a run without any action is also
            `success`). `failed`: every action failed. `partial`: some actions
            failed, for example an e-mail reply that could not be sent
            automatically and was saved as a draft instead.
          enum:
            - success
            - partial
            - failed
        trigger_type:
          type: string
          description: |
            What started the run:

            - `comment`: a comment on Facebook or Instagram.
            - `story_reply`: a reply to a story.
            - `message`: a private message on Facebook, Instagram or WhatsApp.
            - `email`: an e-mail received by an `email_messages` automation.
            - `lead_ads`: a Lead Ads form submission.
            - `crm_event`: an event from a CRM source.
          enum:
            - comment
            - story_reply
            - message
            - lead_ads
            - crm_event
            - email
        occurred_at:
          type: string
          format: date-time
          description: When the run happened.
        actions:
          type: array
          description: >
            What the automation did. `type` is an open string, today one of
            `reply_message`, `reply_comment`, `send_dm`, `story_reply`,
            `send_reply`, `save_draft`, `generate_reply`, `send_message` and
            `add_to_crm`. The list is empty for a Lead Ads run when the
            automation has no action configured (the run is then `success`).
          items:
            type: object
            required:
              - type
              - status
            properties:
              type:
                type: string
                description: Kind of action (open string; new values can appear).
              status:
                type: string
                description: Outcome of the action.
                enum:
                  - success
                  - failed
        lead_id:
          type: string
          nullable: true
          description: >-
            Opaque identifier, prefixed with `lea_`, of the lead involved, or
            `null`.
    Automation:
      type: object
      description: An automation of the workspace, carried out by one agent.
      required:
        - id
        - name
        - type
        - provider
        - agent_id
        - agent_name
        - status
        - updated_at
      properties:
        id:
          type: string
          description: >-
            Opaque identifier prefixed with `aut_`. Stable for a given
            automation.
        name:
          type: string
          description: >
            Display label in English: what the automation does, then the agent's
            name (for example `Comment replies — Support Agent`, or `HubSpot
            contacts — Support Agent` for a CRM source). For display only: it
            can change, and two automations can share one.
        type:
          $ref: '#/components/schemas/AutomationType'
        provider:
          type: string
          description: >
            The connected service, as a raw value. Messaging automations:
            `facebook`, `instagram`, `instagram_page`, `whatsapp`, `gmail`,
            `microsoft_outlook`, `imap`. CRM sources carry the name of the CRM
            (for example `hubspot`). Treat it as an open string: new values can
            appear.
        agent_id:
          type: string
          description: Opaque identifier of the agent, prefixed with `agt_`.
        agent_name:
          type: string
          description: Name of the agent.
        status:
          $ref: '#/components/schemas/AutomationStatus'
        updated_at:
          type: string
          format: date-time
          description: >
            Date of the last change to the automation. Use it to order
            `automation.status_changed` events.
    LeadSource:
      type: string
      description: |
        - `widget`: the chat widget of a website, or a lead entered manually in
          the Agentova app.
        - `lead_ads`: a Meta Lead Ads form.
        - `telephony`: a phone call handled by an Agentova telephony agent.
        - `social`: an Instagram or Facebook prospect who commented a post and
          then sent their contact details (email or phone) in a private
          message to the comment automation of an Agentova agent.
        - `crm`: an incoming contact of a connected CRM (HubSpot, Monday,
          Customer.io…) for which an automation of an Agentova agent ran.
      enum:
        - widget
        - social
        - telephony
        - lead_ads
        - crm
    AutomationType:
      type: string
      description: >
        `social_comments`, `social_story` and `lead_ads` cover the Meta networks
        (Facebook, Instagram). `social_messages` replies to private messages on
        the Meta networks and on WhatsApp (the `provider` field tells them
        apart). `email_messages` replies to the e-mails of a Gmail, Outlook or
        IMAP mailbox. `crm_source` is an automation triggered by a CRM.
      enum:
        - social_comments
        - social_story
        - social_messages
        - lead_ads
        - email_messages
        - crm_source
    AutomationStatus:
      type: string
      description: |
        - `active`: running.
        - `paused`: paused from the Agentova app or through `PATCH`.
        - `draft`: never activated; it has to be activated from the Agentova
          app.
        - `error`: stopped by a failure that has to be fixed from the Agentova
          app (for example a lost e-mail connection, a channel that could not
          be reconnected on resume, or a subscription to the provider that
          could not be renewed).

        `PATCH` only acts on `active` and `paused` automations.

        An automation that is deleted or deactivated in the Agentova app, or
        whose connected account is disconnected, is no longer returned by the
        API (`404 automation_not_found`). When a failure is what removes it
        (revoked token, mailbox authentication refused, reconnection
        impossible), a last `automation.status_changed` event is sent first,
        with `status: error`. When the account is reconnected, an
        `automation.status_changed` event with `status: active` is sent for
        each automation that comes back. A deliberate deletion sends no event.
      enum:
        - active
        - paused
        - draft
        - error
  headers:
    Cache-Control:
      description: Always `no-store` (personal data, no intermediate cache)
      schema:
        type: string
        enum:
          - no-store
    X-RateLimit-Limit:
      description: >
        Number of requests allowed per window (per key; per IP address when the
        429 comes from repeated authentication failures)
      schema:
        type: integer
    X-RateLimit-Remaining:
      description: Requests left in the current window
      schema:
        type: integer
    X-RateLimit-Reset:
      description: Seconds left before the window resets (NOT a timestamp)
      schema:
        type: integer
  responses:
    Unauthorized:
      description: >-
        Missing, malformed, unknown or revoked key (deliberately
        indistinguishable)
      headers:
        Cache-Control:
          $ref: '#/components/headers/Cache-Control'
        X-RateLimit-Limit:
          $ref: '#/components/headers/X-RateLimit-Limit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/X-RateLimit-Remaining'
        X-RateLimit-Reset:
          $ref: '#/components/headers/X-RateLimit-Reset'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: invalid_api_key
              message: Invalid or revoked key — create one in Settings → API
              details: {}
    Forbidden:
      description: >
        Valid key, but the workspace does not have access to the service (or no
        longer has it): its subscription is blocked (unpaid, paused, or initial
        payment never completed). A workspace without a subscription is on the
        free plan and is not affected. This is not a per-key permission: v1 has
        no per-key permissions.
      headers:
        Cache-Control:
          $ref: '#/components/headers/Cache-Control'
        X-RateLimit-Limit:
          $ref: '#/components/headers/X-RateLimit-Limit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/X-RateLimit-Remaining'
        X-RateLimit-Reset:
          $ref: '#/components/headers/X-RateLimit-Reset'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: workspace_access_denied
              message: This workspace's subscription does not allow access to the API
              details: {}
    PayloadTooLarge:
      description: >
        Request body larger than 16 KB. The code is `invalid_request`; the HTTP
        status stays `413` and `details.reason` gives the cause.
      headers:
        Cache-Control:
          $ref: '#/components/headers/Cache-Control'
        X-RateLimit-Limit:
          $ref: '#/components/headers/X-RateLimit-Limit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/X-RateLimit-Remaining'
        X-RateLimit-Reset:
          $ref: '#/components/headers/X-RateLimit-Reset'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: invalid_request
              message: Invalid request
              details:
                reason: Request body is too large
    UnsupportedMediaType:
      description: >
        Request body not sent as JSON (`Content-Type` other than
        `application/json`). The code is `invalid_request`; the HTTP status
        stays `415` and `details.reason` gives the cause.
      headers:
        Cache-Control:
          $ref: '#/components/headers/Cache-Control'
        X-RateLimit-Limit:
          $ref: '#/components/headers/X-RateLimit-Limit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/X-RateLimit-Remaining'
        X-RateLimit-Reset:
          $ref: '#/components/headers/X-RateLimit-Reset'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: invalid_request
              message: Invalid request
              details:
                reason: Unsupported Media Type
    RateLimited:
      description: >
        Rate limit exceeded: too many requests with this key, or too many
        authentication failures from this IP address
      headers:
        Cache-Control:
          $ref: '#/components/headers/Cache-Control'
        Retry-After:
          description: Seconds to wait before retrying
          schema:
            type: integer
        X-RateLimit-Limit:
          $ref: '#/components/headers/X-RateLimit-Limit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/X-RateLimit-Remaining'
        X-RateLimit-Reset:
          $ref: '#/components/headers/X-RateLimit-Reset'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: rate_limited
              message: Rate limit exceeded — retry in a few seconds
              details:
                retry_after_seconds: 42
    ServiceUnavailable:
      description: >
        The API is temporarily switched off by Agentova (`service_unavailable`):
        retry later. This response may come without the `X-RateLimit-*` headers.
        While the API is switched off, no webhook delivery is created for the
        events that happen in the meantime.
      headers:
        Cache-Control:
          $ref: '#/components/headers/Cache-Control'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: service_unavailable
              message: The API is temporarily unavailable — retry later
              details: {}
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: agk_live_<32 characters>
      description: >
        API key created in the Agentova app (Settings → API), sent as
        `Authorization: Bearer agk_live_…`. One key = one workspace: the key
        determines the workspace, and no workspace identifier ever travels in
        requests. The `Bearer` scheme is case-insensitive. A revoked key is
        refused immediately.

````

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