Every API here is available over the APIs.io API and to AI agents over MCP.
components:
headers:
ETag:
description: "Opaque STRONG entity-tag validator for the returned representation, currently a quoted 32-hex-character token (e.g. \"9f86d081884c7d65…\"). Treat it as opaque: never parse, derive, or construct one. Store the received value and replay it VERBATIM in a later If-Match to make a write conditional. Any accepted write moves the validator, so a stale value cannot match and the conditional write is rejected with 412 precondition_failed."
schema:
type: string
RateLimitLimit:
description: Request quota for the current limiter window.
schema:
type: integer
RateLimitRemaining:
description: Requests remaining in the current limiter window.
schema:
type: integer
RateLimitReset:
description: Seconds until the current limiter window resets.
schema:
type: integer
ResourceLocation:
description: "Canonical path-relative URL of the affected resource. Path segments are percent-encoded PER SEGMENT, which legally leaves the sub-delimiters @ + & = : $ unescaped — /v1/contacts/a.partner@fund.vc is an expected value, and so is the fully-escaped /v1/contacts/a.partner%40fund.vc. Neither form is promised, so never string-compare this header against a URL built locally: percent-decode the final path segment to recover the canonical resource key, then compare that."
schema:
format: uri-reference
type: string
RetryAfter:
description: Positive integer seconds to wait before retrying a transient 429 or 503 response.
schema:
minimum: 1
type: integer
XRequestID:
description: Always-present request correlation id. Error responses echo the same value in error.request_id.
schema:
type: string
schemas:
APIKeyExportEntry:
additionalProperties: true
properties:
created_at:
format: date-time
type: string
id:
type: string
key_prefix:
type: string
last_used_at:
format: date-time
type: string
name:
type: string
revoked_at:
format: date-time
type: string
required:
- id
- name
- key_prefix
- created_at
type: object
x-stability-level: beta
APIKeyView:
additionalProperties: true
properties:
agent_email:
description: Bound inbox email for agent-scoped keys; omitted for account scope.
type: string
created_at:
format: date-time
type: string
expires_at:
format: date-time
type: string
id:
type: string
key_prefix:
description: Non-secret visible prefix (e.g. e2a_acct_… / e2a_agt_…).
type: string
last_used_at:
format: date-time
type: string
name:
type: string
scope:
description: "account = workspace admin; agent = bound to one inbox. Open set: new values may be added over time, so treat these as strings and tolerate unknown values. Known values: account, agent."
type: string
required:
- id
- name
- key_prefix
- scope
- created_at
type: object
AccountDailyLimit:
additionalProperties: true
properties:
clean_active_days:
format: int64
type: integer
limit:
format: int64
type: integer
resets_at:
format: date-time
type: string
shared_limit:
format: int64
type: integer
shared_used:
format: int64
type: integer
used:
format: int64
type: integer
required:
- limit
- used
- shared_limit
- shared_used
- clean_active_days
- resets_at
type: object
AccountMetricsView:
additionalProperties: true
properties:
agents:
description: Per-agent breakdown, busiest first. Empty unless group_by=agent was requested.
items:
$ref: "#/components/schemas/AgentMetricsGroupView"
type:
- array
- "null"
agents_truncated:
description: "True when the account has more agents with traffic than the breakdown returned (cap: 200). The account-wide totals above stay complete — only the breakdown is cut."
type: boolean
buckets:
description: Per-day breakdown, oldest first. Empty unless bucket=day was requested. Each bucket's counters sum to the window totals above; its rates do not average to the window rate, because a rate of rates is not the rate.
items:
$ref: "#/components/schemas/MetricsBucketView"
type:
- array
- "null"
counters:
description: Every reason code observed across the account in the window, ordered by code.
items:
$ref: "#/components/schemas/MetricsCounterView"
type:
- array
- "null"
end:
description: Exclusive end of the cohort window.
format: date-time
type: string
messages_in_window:
description: Messages created in the window across every agent this account owns.
format: int64
type: integer
messages_with_lifecycle:
description: Messages in the window carrying at least one persisted lifecycle observation. Below messages_in_window means part of the window predates the lifecycle ledger, and every counter here undercounts by that difference.
format: int64
type: integer
rates:
$ref: "#/components/schemas/MetricsRatesView"
description: Account-wide rates, on the same fixed denominators the per-agent operation uses.
reconstructed_observations:
description: Observations derived from durable message state rather than recorded at the boundary. Included in the counts above; reported separately so the inferred share is visible.
format: int64
type: integer
start:
description: Inclusive start of the cohort window.
format: date-time
type: string
summary:
$ref: "#/components/schemas/MetricsSummaryView"
description: Account-wide counters. Always computed across every agent, never from the possibly-truncated agents array.
webhooks:
$ref: "#/components/schemas/WebhookMetricsView"
required:
- start
- end
- messages_in_window
- messages_with_lifecycle
- reconstructed_observations
- summary
- rates
- counters
- agents
- agents_truncated
- webhooks
- buckets
type: object
x-stability-level: beta
AccountUserView:
additionalProperties: true
properties:
email:
type: string
id:
type: string
required:
- id
- email
type: object
AccountView:
additionalProperties: true
properties:
agent_email:
type: string
daily_limit:
$ref: "#/components/schemas/AccountDailyLimit"
description: External-recipient allowance for this UTC day. Used includes pending or uncertain provider submissions. Shared-identity usage is included in total usage and also bounded by shared_limit. Internal recipients (own live agents and verified owner mailbox) do not count. Omitted when this deployment does not enable the account trust ladder.
deleted_at:
description: When the account was moved to the trash. Absent for a live account.
format: date-time
type: string
limits:
$ref: "#/components/schemas/LimitsCapsView"
plan_code:
type: string
purge_after:
description: When a trashed account becomes eligible for permanent purge. Absent for a live account.
format: date-time
type: string
read_only:
description: "True while the account is read-only because its sending is paused pending an abuse review: every write is refused with 403 account_read_only, while reads and moving the account to the trash keep working. False otherwise. Absent when the deployment does not report it or its state is unavailable."
type: boolean
restored_at:
description: "When the account was last restored from the trash. Absent if it never was. API keys and domain verification do not survive a trash: keys must be re-created and domains re-verified after a restore."
format: date-time
type: string
scope:
description: "Credential scope. Open set: new values may be added over time, so treat these as strings and tolerate unknown values. Known values: account, agent."
type: string
sending_access:
$ref: "#/components/schemas/SendingAccessView"
description: External sending access eligibility (beta). Booleans only; describes what the account may do, not a promise that a given send passes pause, quota, content or domain checks. Omitted when the deployment does not enable external sending access, or when its state is unavailable.
x-stability-level: beta
upgrade_url:
type: string
usage:
$ref: "#/components/schemas/LimitsUsageView"
user:
$ref: "#/components/schemas/AccountUserView"
required:
- user
- scope
- plan_code
- limits
- usage
- upgrade_url
type: object
AgentIdentity:
additionalProperties: true
properties:
created_at:
format: date-time
type: string
deleted_at:
format: date-time
type: string
domain:
type: string
domain_verified:
type: boolean
email:
type: string
inbound_7d:
format: int64
type: integer
inbound_allowlist:
items:
type: string
type:
- array
- "null"
inbound_policy:
type: string
inbound_policy_action:
type: string
inbound_scan:
type: string
inbound_scan_block_threshold:
format: double
type: number
inbound_scan_review_threshold:
format: double
type: number
inbound_scan_sensitivity:
type: string
last_delivery_at:
format: date-time
type: string
name:
type: string
on_expiry:
type: string
outbound_7d:
format: int64
type: integer
outbound_allowlist:
items:
type: string
type:
- array
- "null"
outbound_policy:
type: string
outbound_policy_action:
type: string
outbound_scan:
type: string
outbound_scan_block_threshold:
format: double
type: number
outbound_scan_review_threshold:
format: double
type: number
outbound_scan_sensitivity:
type: string
pending_count:
format: int64
type: integer
public:
type: boolean
registered_domain:
type: string
suppress_notifications:
type: boolean
ttl_seconds:
format: int64
type: integer
user_id:
type: string
webhook_status:
description: "Webhook posture for this agent, derived from the account's webhook subscribers that match it (a webhook with no agent filter matches every agent). Open set; tolerate unknown values. Known values: none (no webhook matches this agent), healthy (an enabled webhook matches and none serving this agent has a terminally-failed delivery in the last 24h), failing (an enabled webhook matches but at least one delivery on a matching enabled webhook terminally failed in the last 24h), disabled (webhooks match but every one is disabled, turned off manually), auto_disabled (webhooks match, every one is disabled, and at least one was auto-disabled by the chronic-failure sweep). Present on enriched surfaces (account export, dashboard agent list); absent where not computed."
type: string
required:
- domain
- registered_domain
- email
- name
- domain_verified
- public
- created_at
- user_id
- ttl_seconds
- on_expiry
- suppress_notifications
- inbound_7d
- outbound_7d
- pending_count
- inbound_policy
- inbound_policy_action
- outbound_policy
- outbound_policy_action
- inbound_scan
- inbound_scan_review_threshold
- inbound_scan_block_threshold
- outbound_scan
- outbound_scan_review_threshold
- outbound_scan_block_threshold
- inbound_scan_sensitivity
- outbound_scan_sensitivity
type: object
x-stability-level: beta
AgentMetricsGroupView:
additionalProperties: true
properties:
agent_email:
type: string
counters:
description: Every reason code this agent produced in the window, ordered by code.
items:
$ref: "#/components/schemas/MetricsCounterView"
type:
- array
- "null"
messages_in_window:
format: int64
type: integer
messages_with_lifecycle:
format: int64
type: integer
rates:
$ref: "#/components/schemas/MetricsRatesView"
reconstructed_observations:
format: int64
type: integer
summary:
$ref: "#/components/schemas/MetricsSummaryView"
required:
- agent_email
- messages_in_window
- messages_with_lifecycle
- reconstructed_observations
- summary
- rates
- counters
type: object
x-stability-level: beta
AgentMetricsView:
additionalProperties: true
properties:
agent_email:
description: The agent these metrics describe.
type: string
counters:
description: Every reason code observed in the window, ordered by code. Codes with no observations are omitted rather than reported as zero.
items:
$ref: "#/components/schemas/MetricsCounterView"
type:
- array
- "null"
end:
description: Exclusive end of the cohort window.
format: date-time
type: string
messages_in_window:
description: Messages created in the window, from the message table itself.
format: int64
type: integer
messages_with_lifecycle:
description: Messages in the window carrying at least one persisted lifecycle observation. Below messages_in_window means part of the window predates the lifecycle ledger, and every counter here undercounts by that difference.
format: int64
type: integer
rates:
$ref: "#/components/schemas/MetricsRatesView"
reconstructed_observations:
description: Observations in the window derived from durable message state rather than recorded at the boundary. Included in the counts above; reported separately so the inferred share is visible.
format: int64
type: integer
start:
description: Inclusive start of the cohort window.
format: date-time
type: string
summary:
$ref: "#/components/schemas/MetricsSummaryView"
required:
- agent_email
- start
- end
- messages_in_window
- messages_with_lifecycle
- reconstructed_observations
- summary
- rates
- counters
type: object
x-stability-level: beta
AgentSuppressionAddedData:
additionalProperties: true
properties:
address:
type: string
agent_email:
type: string
source:
description: "How the suppression was created. Known values: unsubscribe, manual."
type: string
required:
- agent_email
- address
- source
type: object
x-stability-level: beta
AgentSuppressionView:
additionalProperties: true
properties:
address:
type: string
agent_email:
type: string
created_at:
format: date-time
type: string
reason:
type: string
source:
description: "How the block was created. Known values: unsubscribe, manual."
type: string
required:
- agent_email
- address
- source
- created_at
type: object
x-stability-level: beta
AgentView:
additionalProperties: true
properties:
created_at:
format: date-time
type: string
deleted_at:
description: When the agent was moved to the trash. Omitted for live agents. A trashed agent is restorable until purged — 30 days after deletion by default (deployment-configurable). Live message data is otherwise retained indefinitely.
format: date-time
type: string
domain:
description: The exact domain in the agent email address.
type: string
domain_verified:
type: boolean
email:
type: string
name:
type: string
registered_domain:
description: The explicitly registered domain identity that authorizes this agent. For an inherited subdomain agent, this is its verified parent domain.
type: string
required:
- domain
- registered_domain
- email
- name
- domain_verified
- created_at
type: object
ApproveRequest:
additionalProperties: false
properties:
attachments:
items:
$ref: "#/components/schemas/Attachment"
type: array
bcc:
description: Override Bcc recipients. The message is limited to 50 recipients across to, cc, and bcc combined. Each recipient string (display name + address combined) is limited to 320 characters.
items:
maxLength: 320
type: string
type: array
cc:
description: Override Cc recipients. The message is limited to 50 recipients across to, cc, and bcc combined. Each recipient string (display name + address combined) is limited to 320 characters.
items:
maxLength: 320
type: string
type: array
html:
maxLength: 1048576
type: string
subject:
maxLength: 2000
type: string
text:
maxLength: 1048576
type: string
to:
description: Override primary recipients. The message is limited to 50 recipients across to, cc, and bcc combined. Each recipient string (display name + address combined) is limited to 320 characters.
items:
maxLength: 320
type: string
type: array
type: object
x-stability-level: beta
Attachment:
additionalProperties: false
properties:
content_type:
examples:
- application/pdf
type: string
data:
description: Base64-encoded file content. Each attachment must be ≤ 10 MiB decoded; a message may carry at most 10 attachments totaling ≤ 25 MiB decoded.
examples:
- base64-encoded-content
type: string
filename:
description: Attachment filename. Maximum 1024 UTF-8 bytes; longer names are rejected as invalid_attachment.
examples:
- report.pdf
type: string
required:
- filename
- content_type
- data
type: object
AttachmentMetaView:
additionalProperties: true
properties:
content_id:
description: "Content-ID (angle brackets stripped) for an inline part referenced by a body 'cid:' URL, e.g. an embedded image; the key a cid: reference resolves against. Omitted for non-inline attachments."
type: string
content_type:
type: string
filename:
type: string
index:
description: Stable 0-based attachment index (document order) — the fetch key for the attachment-bytes endpoint.
format: int64
type: integer
size_bytes:
description: DECODED attachment payload size in bytes (Content-Transfer-Encoding undone) — the size of the file a download yields, not its encoded size inside the raw MIME.
format: int64
type: integer
required:
- size_bytes
- index
type: object
AttachmentView:
additionalProperties: true
properties:
content_id:
description: Content-ID (angle brackets stripped) for an inline part referenced by a body 'cid:' URL, e.g. an embedded image. Omitted for non-inline attachments.
type: string
content_type:
type: string
data:
type: string
download_url:
type: string
expires_at:
format: date-time
type: string
filename:
type: string
index:
format: int64
type: integer
size_bytes:
description: DECODED attachment payload size in bytes (Content-Transfer-Encoding undone) — exactly what download_url serves and what the 256 KB inline cap is checked against; not the encoded size inside the raw MIME.
format: int64
type: integer
required:
- index
- size_bytes
- download_url
- expires_at
type: object
Authentication:
additionalProperties: true
properties:
dkim:
description: One result per DKIM signature, in message header order. An unsigned message carries an empty array.
items:
$ref: "#/components/schemas/DKIMResult"
type: array
dmarc:
$ref: "#/components/schemas/DMARCResult"
description: DMARC evaluation of the RFC 5322 Author Domain against aligned SPF and DKIM evidence.
spf:
$ref: "#/components/schemas/SPFResult"
description: SPF evidence for the SMTP peer and RFC 5321 identity.
required:
- spf
- dkim
- dmarc
type: object
ContactDueContact:
additionalProperties: true
properties:
address:
description: The contact's canonical address — identical to the payload's top-level address.
type: string
display_name:
description: The contact's display name; empty string when unset.
type: string
metadata:
additionalProperties: {}
description: The contact's caller-owned metadata, verbatim and uninterpreted. An empty object when the contact carries none.
type: object
required:
- address
- display_name
- metadata
type: object
x-stability-level: beta
ContactDueData:
additionalProperties: true
properties:
address:
description: The contact's canonical address — who the agent owes an action to.
type: string
agent_email:
description: The agent that owns this outreach — its id and address (an agent's id IS its email).
type: string
contact:
$ref: "#/components/schemas/ContactDueContact"
description: The contact's identity, inlined so an agent-scoped consumer needs no account-wide contact read.
last_conversation_id:
description: Conversation id of the most recent exchange with this contact, to continue that thread. Omitted when there is none.
type: string
last_outbound_at:
description: When this agent last sent to the contact. Omitted when it never has.
format: date-time
type: string
next_action_at:
description: The schedule instant that came due — the value set on the engagement, not the time the sweep observed it.
format: date-time
type: string
outbound_count:
description: How many messages this agent has sent to the contact since the engagement was created. Computed at claim time, not a stored counter.
format: int64
type: integer
replied:
description: True when the contact has replied since this agent's first outbound to them.
type: boolean
stage:
description: The caller-owned outreach stage, verbatim. e2a never interprets it; empty when unset.
type: string
required:
- address
- agent_email
- contact
- next_action_at
- outbound_count
- replied
- stage
type: object
x-stability-level: beta
ContactEngagementView:
additionalProperties: true
properties:
address:
type: string
agent_email:
type: string
contact:
$ref: "#/components/schemas/EmbeddedContactView"
created_at:
format: date-time
type: string
first_outbound_at:
description: Server-owned.
format: date-time
type:
- string
- "null"
inbound_count:
description: DMARC-authenticated inbound messages delivered since enrollment. Spoofed, held, blocked, and pre-enrollment messages are excluded. Server-owned.
format: int64
type: integer
last_conversation_id:
description: Server-owned.
type: string
last_inbound_at:
description: Server-owned.
format: date-time
type:
- string
- "null"
last_outbound_at:
description: Server-owned. Include it in the due query (last_outbound_before) so a lost client state-write cannot cause a duplicate send.
format: date-time
type:
- string
- "null"
metadata:
additionalProperties: {}
description: Caller-owned key/value data scoped to this relationship. Opaque to e2a.
type: object
next_action_at:
description: When the caller wants to act next. e2a does not act on it; it drives the outreach query and the contact.due wake-up.
format: date-time
type:
- string
- "null"
outbound_count:
description: Successfully submitted outbound messages since enrollment. Queue failures and pre-enrollment history are excluded. Server-owned.
format: int64
type: integer
replied:
description: Whether this contact has answered since outreach began — computed as last_inbound_at > first_outbound_at, so it means 'replied to us' rather than 'has ever written'. Server-owned.
type: boolean
stage:
description: Caller-defined outreach stage. Opaque to e2a — there is no server-side state machine, and any string is valid.
type: string
suppressed:
description: Whether sends to this address are blocked, by an account-wide or agent-scoped suppression. Server-owned; reflects the same state the send path enforces.
type: boolean
suppression_reason:
description: Free-text detail recorded with the block, when present.
type: string
suppression_source:
description: "Why the block exists, when suppressed. Open set; tolerate unknown values. Known values: unsubscribe, manual, bounce, complaint."
type: string
updated_at:
format: date-time
type: string
required:
- agent_email
- address
- stage
- next_action_at
- metadata
- replied
- suppressed
- first_outbound_at
- last_outbound_at
- last_inbound_at
- outbound_count
- inbound_count
- contact
- created_at
- updated_at
type: object
x-stability-level: beta
ContactImportItemResult:
additionalProperties: true
properties:
address:
description: Canonicalized address. Absent when the row could not be parsed.
type: string
code:
description: "Machine-branchable reason, present for skipped and failed rows. Known values: duplicate_in_batch, already_exists, invalid_recipient, invalid_request, contact_limit_reached."
type: string
enrolled:
description: True when this import created the optional per-agent outreach enrolment for this row. False means no agent was requested or the enrolment already existed.
type: boolean
index:
description: Zero-based position of this row in the submitted contacts array.
format: int64
type: integer
message:
description: Human-readable explanation for a skipped or failed row.
type: string
status:
description: "Outcome for this row. Known values: created, updated, skipped, failed."
type: string
suppressed:
description: True when this address is on a suppression list. The contact is still recorded — suppression is surfaced here so the import count stays honest rather than silently smaller — but sends to it will be refused.
type: boolean
required:
- index
- status
type: object
x-stability-level: beta
ContactImportResult:
additionalProperties: true
properties:
batch_id:
description: Identifier for this import. Pass it to DELETE /v1/contacts/imports/{batch_id} to reverse the upload, or as a filter on the contacts list.
type: string
created:
format: int64
type: integer
failed:
format: int64
type: integer
results:
description: One entry per submitted row, in request order.
items:
$ref: "#/components/schemas/ContactImportItemResult"
type: array
skipped:
format: int64
type: integer
updated:
format: int64
type: integer
required:
- batch_id
- created
- updated
- skipped
- failed
- results
type: object
x-stability-level: beta
ContactImportRow:
additionalProperties: false
properties:
address:
description: Email address. Accepts a bare address or an RFC 5322 mailbox ("A. Partner <partner@fund.vc>"). At most 320 Unicode code points; a longer value fails this row alone with invalid_recipient and does not reject the batch.
type: string
display_name:
description: Optional human-readable name, at most 320 Unicode code points; a longer value fails this row alone with invalid_request and does not reject the batch. Omit it and an existing contact keeps the name it already has — so a narrower re-upload that drops the name column does not erase names. Send an explicit empty string to clear one.
type: string
metadata:
additionalProperties: {}
description: "Optional flat key/value data owned by the caller and stored verbatim; e2a never interprets it. A row that exceeds a bound fails on its own, without affecting the rest of the batch. Bounds, all enforced (400 invalid_request on violation): at most 50 keys; each key at most 128 bytes; each value must be a string, number, boolean, or null — nested objects and arrays are rejected, never flattened; each string value at most 4096 bytes; the whole object at most 16384 bytes once JSON-encoded. The byte-counted limits are UTF-8 octets, so a non-ASCII key or value reaches its limit sooner than its character count suggests."
maxProperties: 50
propertyNames:
maxLength: 128
type: object
required:
- address
# --- truncated at 32 KB (395 KB total) ---
# Full source: https://artifacts.apis.io/e2a-dev/openapi/_original/e2a-dev-api-openapi.yml