---
title: "List inbound email requests"
method: GET
path: "/inbound-requests"
tags: ["Inbound Requests"]
---

# List inbound email requests

`GET /inbound-requests`

## Request

- Base URL: `https://inkseal.net/api/v1`
- URL: `https://inkseal.net/api/v1/inbound-requests`
- Auth: HTTP bearer

The mail agent's conversations: one row per email the workspace's inbox accepted, newest first, paginated.

The lifecycle is `received` -> `parsing` -> `parsed` -> `drafted` -> `awaiting_approval`, then one of the terminal states `approved`, `cancelled`, `expired`, `rejected`, or `failed`. `parsing` may instead go to `needs_info` when the parser could not determine something, which loops back to `parsing` when the sender replies; that loop is capped, and `clarificationRoundTrips` says how many rounds have been used.

`?state=awaiting_approval` is the set an agent can act on. `?state=needs_info` is the set waiting on a human to answer the clarification email.

Every row is redacted: no message bodies, no storage keys, no reply token, no provider message ids, and no row ids. What is published is the workflow, not the mail.

Costs both `envelopes:read` and `account:read`, because a row names the parsed signers and the public ids of the document and envelope it produced.

## Query parameters

- `page` integer
- `limit` integer
- `state` 'all' | 'received' | 'parsing' | 'parsed' | 'drafted' | 'awaiting_approval' | 'approved' | 'cancelled' | 'expired' | 'needs_info' | 'rejected' | 'failed'

## Response `200`

One page of inbound requests.

- object
  - `data` InboundRequest[], required
    - `id` string, required
    - `state` 'received' | 'parsing' | 'parsed' | 'drafted' | 'awaiting_approval' | 'approved' | 'cancelled' | 'expired' | 'needs_info' | 'rejected' | 'failed', required: Where the conversation is. `awaiting_approval` is the only actionable state. `approved`, `cancelled`, `expired`, `rejected`, and `failed` are terminal. `needs_info` means the agent has emailed the sender for missing detail and is waiting.
    - `error` string, nullable, required: Why the request failed or was rejected, or a non-fatal warning recorded while drafting. Null when nothing went wrong.
    - `intent` InboundRequestIntent, required: What the parser understood from the email. Nothing the model was given is echoed back, and a stored intent whose shape this API no longer recognizes is published as null rather than forwarded verbatim.
      - `signers` object[], required
        - `name` string, nullable, required
        - `email` string, email, required
        - `order` integer, nullable, required: 1-based position for a sequential send, or null when the sender did not order them.
      - `signingOrder` 'parallel' | 'sequential', required
      - `subject` string, nullable, required
      - `message` string, nullable, required
      - `expiresInDays` integer, nullable, required
      - `attachmentIndex` integer, nullable, required: Which attachment the sender chose, by position in `attachments`.
      - `notes` string, nullable, required: Anything the parser recorded that does not fit the other fields.
    - `missingInformation` string[], required: What the parser could not determine. This is the field to branch on when deciding whether to reply to the sender with the missing detail.
    - `attachments` InboundRequestAttachment[], required
      - `filename` string, required
      - `contentType` string, required
      - `size` integer, required: Bytes stored, or the size the provider declared for a refused file.
      - `status` 'stored' | 'refused', required
      - `refusedReason` 'null' | 'too_many_attachments' | 'file_too_large' | 'message_too_large', nullable, required: Why the file was skipped. Null on a stored attachment.
    - `document` InboundRequestResourceRef, required: A resource this conversation produced, by public id.
      - `id` string, required
    - `envelope` InboundRequestResourceRef, required: A resource this conversation produced, by public id.
      - `id` string, required
    - `clarificationRoundTrips` integer, required: How many `needs_info` rounds the conversation has used. The loop is capped, and hitting the cap fails the request.
    - `createdAt` string, date-time, required
    - `updatedAt` string, date-time, required
  - `pagination` Pagination, required: Where the returned page sits in the full result set.
    - `page` integer, required: The 1-based page returned.
    - `limit` integer, required: Items per page, as requested.
    - `total` integer, required: Total items matching the query.
    - `totalPages` integer, required: `ceil(total / limit)`.

## Other responses

- `400`: The request is malformed or the resource is in the wrong state for a synchronous check. Codes: `validation_error`, `invalid_body`, `invalid_parameter`, `invalid_idempotency_key`, `invalid_event_id`, `invalid_file`, `invalid_url`, `invalid_status`, `key_mismatch`, `no_signers`, `not_completed`, `envelope_exists`, `document_not_ready`, `upload_failed`.
- `401`: The credential is missing, malformed, unknown, expired, revoked, or past its rotation grace window. Code: `unauthorized`. Every authentication failure is deliberately indistinguishable.
- `403`: The credential is valid but may not do this. Codes: `insufficient_scope` (the route's scopes are not all held; `details` names `requiredScopes` and `missingScopes`), `forbidden` (the capability check on the resolved resource failed), `scope_escalation` (a grant wider than the caller's own was requested).
- `429`: A limit was reached. Codes: `rate_limited` (the credential's per-bucket HTTP limit, or the per-workspace detection throttle), `workspace_limit_exceeded` (a workspace content or send limit; `details.limit` names it), `daily_budget_exceeded` (the workspace's daily detection budget). The four rate-limit headers are sent on this response and on no successful one, so a client cannot read its remaining budget without being refused. Retrying after `Retry-After` is always safe: a rate-limit refusal happens before the handler runs.
- `503`: A dependency the request needs is unreachable and nothing was changed. Codes: `queue_unavailable` (a background job could not be enqueued; retry the call), `billing_unavailable` (Stripe would not open a checkout session; nothing was charged, retry the call), `service_unavailable` (the rate-limit store is down, so the request was refused before running).

---

[API](https://skmtc.dev/inkseal/apis/inkseal-api.md) · [All operations](https://skmtc.dev/inkseal/apis/inkseal-api/llms.txt) · [OpenAPI document](https://skmtc.dev/inkseal/apis/inkseal-api/revisions/c440c981d578?raw)
