Evermuse ingestion API

Send data to Evermuse

OpenAPI Specification

evermuse-ingestion-api-openapi.yml Raw ↑
openapi: 3.1.0
info:
  title: Evermuse ingestion API
  version: 1.0.0
  description: 'The Evermuse API lets you send your data into Evermuse for analysis.

    Each record describes *what* happened and *when*, then you send it as JSON or newline-delimited JSON (NDJSON).


    ## Quick start


    1. Create an API key in **Settings > API Keys** with the `api:write` permission.

    2. `POST /api/v1/ingest` with your records (see examples below).

    3. Check `GET /api/v1/ingest/batches/{batchId}` to track progress.


    ## Authentication


    Every request must include an `x-api-key` header with your API key (`em_sk_...`).


    ## Content types


    | Content-Type | Use case |

    |---|---|

    | `application/json` | Array of records, or `{ "records": [...] }` wrapper |

    | `application/x-ndjson` | High-volume sends — one JSON object per line |


    ## Batching


    All records in a single request must share the same `_type` and `_product_id`.

    A batch can contain up to 1,000 records.

    '
servers:
- url: https://api.evermuse.com
  description: Evermuse API
tags:
- name: ingestion
  description: Send data to Evermuse
paths:
  /api/v1/ingest:
    post:
      operationId: ingestRecords
      tags:
      - ingestion
      summary: /ingest
      x-mint:
        href: /api-reference/ingestion/ingest
      description: 'Submit records.


        The request body accepts two formats:

        - An array of record objects

        - An object with a `records` key containing an array


        For high-volume sends, use `application/x-ndjson` (one JSON object per line).


        Attachments referenced by `vendor_url` are fetched automatically after the batch is accepted.

        Download progress is available on the batch status endpoint.

        '
      security:
      - IngestApiKey: []
      parameters:
      - name: Idempotency-Key
        in: header
        required: false
        schema:
          type: string
          maxLength: 256
        description: 'Optional key to prevent duplicate submissions.

          If a request with the same key and identical body has already been accepted,

          you''ll get back the original response without the data being processed again.

          Recommended when retrying failed requests.

          '
      - name: format
        in: query
        required: false
        schema:
          type: string
          enum:
          - text
          - audio
          - video
          - file
        description: 'Optional hint that describes the primary content format of the records.

          This does not affect validation but helps optimize how your data is processed.

          '
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/IngestRequest'
            examples:
              recordBatch:
                summary: Batch via JSON array
                value:
                - _type: conversation
                  _schema_version: 1.0.0
                  _event_at: 2026-02-24 12:34:56+00:00
                  _nature: evidence
                  _vendor_ids:
                    conversation_id: conv-001
                  _product_id: prod-abc
                  _project_ids:
                  - proj-123
                  data:
                    messages:
                    - sender: agent
                      text: How can I help you today?
                    - sender: customer
                      text: I have a question about billing.
                - _type: conversation
                  _schema_version: 1.0.0
                  _event_at: 2026-02-24 12:40:00+00:00
                  _nature: evidence
                  _vendor_ids:
                    conversation_id: conv-002
                  _product_id: prod-abc
                  _project_ids:
                  - proj-123
                  data:
                    messages:
                    - sender: customer
                      text: Can I upgrade my plan?
              recordsWrapper:
                summary: Batch via records wrapper
                value:
                  records:
                  - _type: email
                    _schema_version: 1.0.0
                    _event_at: 2026-02-24 12:34:56+00:00
                    _nature: evidence
                    _vendor_ids:
                      message_id: msg-20260224-001
                    _thread_id: thread-acme-inquiry
                    _participants:
                    - id: alice@acme.com
                      name: Alice Johnson
                      email: alice@acme.com
                      role: external
                      type: contact
                    - id: bob@yourcompany.com
                      name: Bob Smith
                      email: bob@yourcompany.com
                      role: internal
                      type: user
                    _product_id: prod-abc
                    _project_ids:
                    - proj-123
                    _tags:
                    - product-feedback
                    - enterprise
                    data:
                      subject: 'Re: Product feedback'
                      from: alice@acme.com
                      to: bob@yourcompany.com
                      body: We'd love to see dark mode support in the next release.
              recordWithAttachment:
                summary: Record with a downloadable attachment
                value:
                - _type: meeting_notes
                  _schema_version: 1.0.0
                  _event_at: 2026-02-24 15:00:00+00:00
                  _nature: evidence
                  _product_id: prod-abc
                  _project_ids:
                  - proj-123
                  _vendor_ids:
                    meeting_id: mtg-456
                  _attachments:
                  - type: audio
                    filename: meeting-recording.mp3
                    mime_type: audio/mpeg
                    vendor_url: https://storage.example.com/recordings/mtg-456.mp3
                  data:
                    title: Weekly product sync
                    duration_minutes: 45
              guidanceRecord:
                summary: Internal guidance document
                value:
                - _type: meeting_notes
                  _schema_version: 1.0.0
                  _event_at: 2026-02-24 10:00:00+00:00
                  _nature: guidance
                  _vendor_ids:
                    doc_id: okr-q2-2026
                  _product_id: prod-abc
                  _project_ids:
                  - proj-456
                  data:
                    title: Q2 2026 OKRs
                    body: 'Objective: Improve onboarding conversion by 20%'
          application/x-ndjson:
            schema:
              type: string
              description: 'Newline-delimited JSON. Each line is a single record object.

                '
            examples:
              ndjsonExample:
                summary: NDJSON (two records)
                value: '{"_type":"email","_schema_version":"1.0.0","_event_at":"2026-02-24T12:34:56Z","_nature":"evidence","_vendor_ids":{"message_id":"msg-001"},"_product_id":"prod-abc","_project_ids":["proj-123"],"data":{"subject":"Hello","body":"World"}}

                  {"_type":"email","_schema_version":"1.0.0","_event_at":"2026-02-24T12:40:00Z","_nature":"evidence","_vendor_ids":{"message_id":"msg-002"},"_product_id":"prod-abc","_project_ids":["proj-123"],"data":{"subject":"Follow-up","body":"Thanks"}}

                  '
      responses:
        '202':
          description: 'Accepted. Your records have been received and are being processed.

            Use the returned `batchId` with `GET /api/v1/ingest/batches/{batchId}` to check progress.

            '
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IngestAcceptedResponse'
        '400':
          description: 'Bad Request. Something was wrong with the data you sent.

            Check the `errors` array for details on which records were rejected and why.

            '
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized. The `x-api-key` header is missing or invalid.
        '403':
          description: Forbidden. The API key does not have the required `api:write` permission.
        '413':
          description: Payload too large. The request body exceeds the maximum allowed size (5 MB).
        '429':
          description: 'Rate limit exceeded. Retry after the number of seconds indicated in the `retryAfter` field.

            '
        '500':
          description: Internal server error. Please retry the request.
  /api/v1/ingest/batches:
    get:
      operationId: listBatches
      tags:
      - ingestion
      summary: /ingest/batches
      x-mint:
        href: /api-reference/ingestion/get-batches
      description: 'Returns a paginated list of batches you''ve submitted, newest first.


        Use the `nextCursor` value from the response as the `cursor` query parameter to fetch the next page.

        '
      security:
      - IngestApiKey: []
      parameters:
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          minimum: 1
          maximum: 100
          default: 20
        description: 'Number of batches to return per page. Defaults to 20, maximum 100.

          '
      - name: cursor
        in: query
        required: false
        schema:
          type: string
          maxLength: 256
        description: 'Pagination cursor from a previous response''s `nextCursor` field.

          Omit to start from the most recent batch.

          '
      responses:
        '200':
          description: A page of batches.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IngestBatchListResponse'
        '401':
          description: Unauthorized. The `x-api-key` header is missing or invalid.
        '403':
          description: Forbidden. The API key does not have the required permission.
        '500':
          description: Internal server error. Please retry the request.
  /api/v1/ingest/batches/{batchId}:
    get:
      operationId: getBatchStatus
      tags:
      - ingestion
      summary: /ingest/batches/{batchId}
      x-mint:
        href: /api-reference/ingestion/get-batch-status
      description: 'Returns the current status and record counts for a batch you submitted.


        Use this to check whether your records have finished processing.


        ### Batch lifecycle


        | Status | Meaning |

        |---|---|

        | `LANDING` | Your data is being saved |

        | `LANDED` | Your data is saved and waiting to be processed |

        | `PROCESSING` | Your records are being analyzed |

        | `COMPLETE` | All records have been processed |

        | `FAILED` | Something went wrong (check errors for details) |

        '
      security:
      - IngestApiKey: []
      parameters:
      - name: batchId
        in: path
        required: true
        schema:
          type: string
          maxLength: 128
        description: The batch ID returned when you sent your records.
      responses:
        '200':
          description: Batch status retrieved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IngestBatchStatus'
        '401':
          description: Unauthorized. The `x-api-key` header is missing or invalid.
        '403':
          description: Forbidden. The API key does not have the required permission.
        '404':
          description: Batch not found. The batch ID does not exist or belongs to a different workspace.
        '500':
          description: Internal server error. Please retry the request.
components:
  schemas:
    IngestBatchListResponse:
      type: object
      additionalProperties: false
      required:
      - batches
      - nextCursor
      properties:
        batches:
          type: array
          description: List of batches, ordered by creation time (newest first).
          items:
            $ref: '#/components/schemas/IngestBatchStatus'
        nextCursor:
          type: string
          nullable: true
          maxLength: 256
          description: 'Pass this value as the `cursor` query parameter to fetch the next page.

            `null` when there are no more results.

            '
    Pii:
      type: object
      additionalProperties: false
      description: 'Optional metadata about personal information in this record.

        Providing this helps Evermuse handle your data with the right privacy safeguards.

        '
      properties:
        contains_email:
          type: boolean
          description: Whether the record's data contains email addresses.
        contains_phone:
          type: boolean
          description: Whether the record's data contains phone numbers.
        sensitive_score:
          type: number
          minimum: 0
          maximum: 1
          description: 'A score from 0 to 1 indicating the likelihood that the record contains sensitive information.

            0 = no sensitive content, 1 = highly sensitive.

            '
        detected_entities:
          type: array
          description: List of personal information types detected in the record.
          items:
            $ref: '#/components/schemas/PiiEntity'
        redaction_status:
          type: string
          enum:
          - unredacted
          - redacted
          - encrypted
          description: 'Whether personal information in this record has been redacted or encrypted before sending.

            '
    IngestAcceptedResponse:
      type: object
      additionalProperties: false
      required:
      - batchId
      - acceptedCount
      - rejectedCount
      - totalErrorCount
      properties:
        batchId:
          type: string
          description: 'Unique identifier for this batch. Use it with `GET /api/v1/ingest/batches/{batchId}` to check status.

            '
          maxLength: 128
        acceptedCount:
          type: integer
          minimum: 0
          description: Number of records that passed validation and were accepted.
        rejectedCount:
          type: integer
          minimum: 0
          description: Number of records that failed validation and were rejected.
        totalErrorCount:
          type: integer
          minimum: 0
          description: 'Total number of errors across all rejected records.

            May be higher than the `errors` array length since only the first 20 are included.

            '
        errors:
          type: array
          description: 'Up to 20 errors. The `index` field refers to the record''s

            position in the batch you sent (starting from 0).

            '
          maxItems: 20
          items:
            $ref: '#/components/schemas/IngestRecordError'
    Participant:
      type: object
      additionalProperties: false
      required:
      - id
      - role
      properties:
        id:
          type: string
          description: 'A stable identifier for the participant. Use an email address, phone number,

            or their ID from your source system.

            '
          maxLength: 256
        name:
          type: string
          description: Display name of the participant.
          maxLength: 256
        email:
          type: string
          format: email
          description: Email address of the participant.
          maxLength: 320
        role:
          type: string
          enum:
          - internal
          - external
          - unknown
          description: 'Whether the participant is part of your team or an external contact.

            - `internal` — your team member (employee, agent, rep)

            - `external` — a customer, prospect, or outside party

            - `unknown` — role cannot be determined

            '
        type:
          type: string
          enum:
          - user
          - contact
          - workspace_member
          - bot
          - system
          - unknown
          description: 'The kind of participant.

            - `user` — a human user

            - `contact` — a customer or prospect

            - `workspace_member` — a member of your workspace

            - `bot` — an automated agent

            - `system` — a system-generated entry

            - `unknown` — type cannot be determined

            '
    Attachment:
      type: object
      additionalProperties: false
      required:
      - type
      properties:
        type:
          type: string
          enum:
          - audio
          - video
          - file
          - image
          - text
          - unknown
          description: 'The kind of attachment.

            - `audio` — audio recording (e.g., call recording, voice memo)

            - `video` — video recording

            - `file` — generic file (PDF, spreadsheet, etc.)

            - `image` — image file (screenshot, photo, etc.)

            - `text` — plain text content

            - `unknown` — type cannot be determined

            '
        filename:
          type: string
          description: Original filename of the attachment.
          maxLength: 512
        size:
          type: integer
          description: File size in bytes.
          minimum: 0
        mime_type:
          type: string
          description: MIME type of the file (e.g., `audio/mpeg`, `application/pdf`).
          maxLength: 256
        sha1:
          type: string
          description: SHA-1 hash of the file contents (for integrity verification).
          maxLength: 128
        md5:
          type: string
          description: MD5 hash of the file contents (for integrity verification).
          maxLength: 128
        vendor_url:
          type: string
          format: uri
          description: 'URL where the file can be downloaded. Evermuse will fetch it automatically

            after the batch is accepted. Download progress is available on the batch status endpoint.

            '
          maxLength: 2048
        upload_intent_id:
          type: string
          description: 'Reference to a file you''ve already uploaded.

            Use this to attach a previously uploaded file to this record.

            '
          maxLength: 256
    ErrorResponse:
      type: object
      additionalProperties: false
      required:
      - error
      - message
      properties:
        error:
          type: string
          maxLength: 64
          description: Machine-readable error code.
        message:
          type: string
          maxLength: 2048
          description: Human-readable error description.
        retryAfter:
          type: number
          description: 'Number of seconds to wait before trying again. Included when you''ve hit the rate limit (429 response).

            '
        details:
          description: Additional machine-readable context about the error.
          additionalProperties: true
    IngestRequest:
      description: 'The request body accepts two shapes:

        - An array of record objects (up to 1,000)

        - An object with a `records` key containing an array

        '
      oneOf:
      - type: array
        minItems: 1
        maxItems: 1000
        items:
          $ref: '#/components/schemas/IngestRecord'
      - type: object
        additionalProperties: false
        required:
        - records
        properties:
          records:
            type: array
            minItems: 1
            maxItems: 1000
            items:
              $ref: '#/components/schemas/IngestRecord'
    IngestBatchStatus:
      type: object
      additionalProperties: false
      required:
      - batchId
      - status
      - acceptedCount
      - rejectedCount
      - totalErrorCount
      - createdAt
      properties:
        batchId:
          type: string
          maxLength: 128
          description: Unique identifier for this batch.
        status:
          type: string
          enum:
          - LANDING
          - LANDED
          - PROCESSING
          - COMPLETE
          - FAILED
          description: 'Current processing status of the batch.

            See the batch lifecycle table in the endpoint description.

            '
        createdAt:
          type: number
          description: When the batch was created, as Unix epoch milliseconds.
          example: 1709282096000
        acceptedCount:
          type: integer
          minimum: 0
          description: Number of records that passed validation.
        rejectedCount:
          type: integer
          minimum: 0
          description: Number of records that failed validation.
        totalErrorCount:
          type: integer
          minimum: 0
          description: Total number of validation errors across rejected records.
        errors:
          type: array
          description: Up to 20 validation errors for quick inspection.
          maxItems: 20
          items:
            $ref: '#/components/schemas/IngestRecordError'
        source:
          type: string
          description: Where the records in this batch came from.
        type:
          type: string
          description: The record type for this batch.
        attachmentDownloadTotal:
          type: integer
          minimum: 0
          description: Total number of attachments to be downloaded (shown when the batch includes file attachments).
        attachmentDownloadComplete:
          type: integer
          minimum: 0
          description: Number of attachments successfully downloaded.
        attachmentDownloadFailed:
          type: integer
          minimum: 0
          description: Number of attachments that failed to download.
        attachmentDownloadStatus:
          type: string
          enum:
          - PENDING
          - IN_PROGRESS
          - COMPLETE
          - PARTIAL_FAILURE
          - FAILED
          description: 'Overall download status for the batch''s attachments.

            Only shown when the batch includes file attachments.

            '
    IngestRecordError:
      type: object
      additionalProperties: false
      required:
      - index
      - code
      - message
      properties:
        index:
          type: integer
          minimum: 0
          description: Position of the rejected record in the submitted batch (0-based).
        code:
          type: string
          maxLength: 64
          description: Machine-readable error code (e.g., `VALIDATION_ERROR`).
        message:
          type: string
          maxLength: 2048
          description: Human-readable description of what went wrong.
    IngestRecord:
      type: object
      additionalProperties: false
      required:
      - _type
      - _schema_version
      - _event_at
      - _vendor_ids
      - _product_id
      - _project_ids
      - _nature
      - data
      properties:
        _type:
          type: string
          enum:
          - email_thread
          - email
          - meeting_notes
          - call
          - call_transcription
          - conversation
          - message
          - document
          - spreadsheet
          description: 'The type of data you''re sending. All records in a single batch must share the same type.


            - `email_thread` — A full email conversation chain (multiple messages grouped together).

            - `email` — A single email message.

            - `meeting_notes` — Notes, summaries, or transcripts captured during or after a meeting.

            - `call` — An audio or video call record (recording url will be provided by the caller in the attachment).

            - `call_transcription` — A verbatim transcription of a phone or video call.

            - `conversation` — A multi-turn conversation from chat platforms (e.g. Slack, Intercom, Drift, support tickets).

            - `message` — A single standalone message (e.g. SMS, or in-app feedback).

            - `document` — A generic document (e.g. PDF, Word doc, or other written material).

            - `spreadsheet` — A spreadsheet or tabular data file (e.g. CSV, Excel).

            '
        _schema_version:
          type: string
          description: 'Schema version. Use `"1.0.0"`.

            '
          example: 1.0.0
        _event_at:
          type: string
          description: 'When the original event occurred, as an ISO-8601 UTC timestamp.

            Milliseconds are accepted but truncated to second precision.

            '
          pattern: ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?Z$
          example: '2026-02-24T12:34:56Z'
        _vendor_ids:
          type: object
          description: 'One or more IDs from your source system. Must contain at least one entry.

            Used to prevent duplicates — records with the same `_type`, `_vendor_ids`, and `_event_at`

            are recognized as the same record and won''t be processed twice.

            '
          minProperties: 1
          additionalProperties:
            type: string
          example:
            message_id: msg-20260224-001
        _thread_id:
          type: string
          description: 'Optional ID that groups related records into a thread

            (e.g., an email chain, a multi-message chat, or a series of related calls).

            Use the thread or conversation ID from your source system.

            '
          maxLength: 512
        _participants:
          type: array
          description: 'People involved in the event. Used for attribution and filtering in your Evermuse dashboard.

            '
          maxItems: 5000
          items:
            $ref: '#/components/schemas/Participant'
        _attachments:
          type: array
          description: 'Files associated with this record (recordings, documents, images, etc.).

            Provide a `vendor_url` for files hosted elsewhere — they will be fetched automatically.

            Alternatively, use `upload_intent_id` to reference a file you''ve already uploaded.

            '
          maxItems: 10
          items:
            $ref: '#/components/schemas/Attachment'
        _tags:
          type: array
          description: 'Free-form labels for categorization and filtering (e.g., `"enterprise"`, `"product-feedback"`, `"q1-2026"`).

            '
          maxItems: 200
          items:
            type: string
            maxLength: 64
        _nature:
          type: string
          enum:
          - evidence
          - guidance
          - context
          description: 'Classifies how this record should be treated during analysis.

            - `evidence` — actual customer conversations, meeting notes, support tickets, etc.

            - `guidance` — internal product team conversations, OKR documents, company goals

            - `context` — supplementary material used for context but not as a source of customer evidence

            '
        _product_id:
          type: string
          description: 'The Evermuse product ID to route records to.

            Found in **Settings > Projects > Actions > Copy** in the Evermuse dashboard.

            All records in a batch must share the same `_product_id`.

            '
          maxLength: 128
        _project_ids:
          type: array
          description: 'One or more Evermuse project IDs to route records to.

            Found in **Settings > Projects > Actions > Copy** in the Evermuse dashboard.

            '
          minItems: 1
          items:
            type: string
            maxLength: 128
        _pii:
          $ref: '#/components/schemas/Pii'
        data:
          type: object
          description: 'Your data. Include all relevant fields from your source system.

            This is stored exactly as you send it.

            '
          additionalProperties: true
    PiiEntity:
      type: object
      additionalProperties: false
      required:
      - type
      properties:
        type:
          type: string
          description: The category of personal information detected (e.g., `email`, `phone`, `ssn`, `credit_card`).
          maxLength: 64
        value:
          type: string
          description: The detected value (omit if you prefer not to include it).
          maxLength: 1024
        confidence:
          type: number
          minimum: 0
          maximum: 1
          description: Confidence score for the detection (0 = low, 1 = high).
  securitySchemes:
    IngestApiKey:
      type: apiKey
      in: header
      name: x-api-key
      description: 'Your API key, sent as the `x-api-key` header.

        Create one in **Settings > API Keys** with `api:write` permission.

        Format: `em_sk_...`

        '