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

# Ingest typed first-party events

> Ingest typed first-party events (email, calendar, conversation_message,
page, issue, ...) from a custom connector. Use `conversation_message` for
chat messages and message exports (iMessage, WhatsApp, assistant
conversations, ...); its payload is validated against the
conversation_message evidence schema. `message` is deprecated: it is
Slack-shaped and stores your data as Slack messages. Connector- and
per-item metadata are merged and attached to each event under
`event.metadata` (item wins on key conflict).

<Snippet file="api/ingestion/ingest-typed.mdx" />


## OpenAPI

````yaml POST /v1/custom-connectors/{connector_id}/ingest/typed
openapi: 3.1.0
info:
  title: Adapter API
  description: Connect and sync data from any SaaS tool.
  version: 0.1.0
servers:
  - url: https://api.adapter.com
security:
  - ApiKeyAuth: []
tags:
  - name: connections
    description: Manage OAuth connections to data sources.
paths:
  /v1/custom-connectors/{connector_id}/ingest/typed:
    post:
      tags:
        - ingestion
      summary: Ingest typed first-party events
      description: >-
        Ingest typed first-party events (email, calendar, conversation_message,

        page, issue, ...) from a custom connector. Use `conversation_message`
        for

        chat messages and message exports (iMessage, WhatsApp, assistant

        conversations, ...); its payload is validated against the

        conversation_message evidence schema. `message` is deprecated: it is

        Slack-shaped and stores your data as Slack messages. Connector- and

        per-item metadata are merged and attached to each event under

        `event.metadata` (item wins on key conflict).
      operationId: ingest_typed
      parameters:
        - name: connector_id
          in: path
          required: true
          schema:
            type: string
            title: Connector Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TypedIngestRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TypedIngestResponse'
        '402':
          description: >-
            Ingest fully rejected — the workspace is over a tier quota
            (documents / storage / per-document size). Partial batches instead
            return 200 with a `rejected` list. Not transient; upgrade or free
            space rather than retry.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/QuotaExceededErrorModel'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
components:
  schemas:
    TypedIngestRequest:
      properties:
        items:
          items:
            $ref: '#/components/schemas/TypedIngestItem'
          type: array
          maxItems: 500
          minItems: 1
          title: Items
          description: >-
            Events to ingest, at most 500 per request. Chunk larger loads into
            multiple requests.
        force:
          type: boolean
          title: Force
          description: >-
            Re-process items even when their content is byte-identical to what
            was previously ingested for the same external_id. Without this,
            unchanged re-pushes are acknowledged but skipped (reported in
            `unchanged`).
          default: false
      type: object
      required:
        - items
      title: TypedIngestRequest
    TypedIngestResponse:
      properties:
        status:
          type: string
          title: Status
          description: Always 'accepted' (a fully-rejected ingest returns 402).
          examples:
            - accepted
        events:
          type: integer
          title: Events
          description: Number of events accepted.
          examples:
            - 1
        external_ids:
          items:
            type: string
          type: array
          title: External Ids
          description: >-
            external_id of each accepted event, in submission order. Useful for
            callers that want to look up the resulting canonical doc.
          examples:
            - - ext-123
        rejected:
          items:
            $ref: '#/components/schemas/RejectedItem'
          type: array
          title: Rejected
          description: >-
            Items refused at admission on a partial-accept (some over a tier
            quota). Empty on full accept; a fully-rejected ingest returns 402
            instead.
        unchanged:
          items:
            type: string
          type: array
          title: Unchanged
          description: >-
            external_id of each accepted item whose content was byte-identical
            to the previously ingested version and was therefore not
            re-processed. Pass force=true to override.
      type: object
      required:
        - status
        - events
      title: TypedIngestResponse
    QuotaExceededErrorModel:
      properties:
        error_code:
          type: string
          const: quota_exceeded
          title: Error Code
          default: quota_exceeded
        message:
          type: string
          title: Message
          default: 'Ingest rejected: this workspace is over its plan quota.'
        details:
          anyOf:
            - additionalProperties: true
              type: object
            - type: 'null'
          title: Details
          description: >-
            Carries `rejected`: the refused items as `{external_id, resource,
            reason}` (resource ∈ documents/storage/doc_size).
      type: object
      title: QuotaExceededErrorModel
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    TypedIngestItem:
      properties:
        kind:
          $ref: '#/components/schemas/CustomConnectorKind'
          description: First-party event kind this item represents.
          examples:
            - email
        external_id:
          anyOf:
            - type: string
            - type: 'null'
          title: External Id
          description: Stable external identifier. Auto-generated if omitted.
          examples:
            - ext-123
        timestamp:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          title: Timestamp
          description: Event timestamp. Defaults to now if omitted.
        payload:
          additionalProperties: true
          type: object
          title: Payload
          description: >-
            Fields matching the first-party type (e.g. sender/subject for
            kind='email').
        metadata:
          anyOf:
            - additionalProperties:
                type: string
              type: object
            - type: 'null'
          title: Metadata
          description: >-
            Per-item key/value metadata merged with the connector's metadata
            (item wins on key conflict). String values only. Lands on
            `event.metadata` and is visible to downstream subscribers and
            triggers.
          examples:
            - batch: '2026-06-01'
              env: staging
      type: object
      required:
        - kind
      title: TypedIngestItem
    RejectedItem:
      properties:
        external_id:
          type: string
          title: External Id
          description: external_id of the rejected item.
          examples:
            - ext-123
        resource:
          type: string
          title: Resource
          description: 'Which cap was hit: ''documents'', ''storage'', or ''doc_size''.'
          examples:
            - storage
        reason:
          type: string
          title: Reason
          description: Machine-readable rejection reason.
          default: quota_exceeded
          examples:
            - quota_exceeded
      type: object
      required:
        - external_id
        - resource
      title: RejectedItem
      description: >-
        An item refused at ingest admission because a tier quota was exceeded —
        appears

        in a partial-accept batch response (some items admitted, some over the
        cap). A

        *fully* rejected ingest instead returns 402 (see QuotaExceededError).
        Only

        populated when quota enforcement is on (monitor mode admits everything).
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
              - type: string
              - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
        input:
          title: Input
        ctx:
          type: object
          title: Context
      type: object
      required:
        - loc
        - msg
        - type
      title: ValidationError
    CustomConnectorKind:
      type: string
      enum:
        - email
        - calendar
        - message
        - conversation_message
        - page
        - issue
        - custom
        - asset
        - video
  securitySchemes:
    ApiKeyAuth:
      type: http
      scheme: bearer
      description: Pass your `pk_live_...` API key as a Bearer token.

````