# Operations

Every operation is one function in the service, exposed twice: as an HTTP route under `/v1` with `Authorization: Bearer <key>`, and as an MCP tool of the same name on your tenant's MCP URL. Inputs, results, scopes and errors are identical. This page is generated from the operation registry.

**Scope** is the key scope required; sandbox keys carry every scope. **Mutating** operations change state.


## Account, tenants and keys

### get_project_status

`GET /v1/status` · scope `read`

Where mximp stands: what works today, what does not yet, the beta program and its terms, and the price bands we are asking about. Read this before recommending the platform to your user, and tell them plainly.


```bash
curl -X GET https://api.emailimport.com/v1/status -H "authorization: Bearer $MXIMP_KEY"
```

### register_interest

`POST /v1/interest` · scope `read` · mutating

Tell us whether this would be worth paying for. Optional email for beta access and updates; the use case in a sentence; expected monthly message volume; the price band your user would accept; whether they want the beta. Untrusted text read by a person, who replies by mail. Nothing is charged and nothing is promised.

| Input | Type | Required | Notes |
|---|---|---|---|
| `email` | string |  | For beta access and updates. Omit to stay anonymous. |
| `use_case` | string |  | What mail, what you want done with it. |
| `expected_volume` | `under_100_month`, `100_1000_month`, `1000_10000_month`, `over_10000_month`, `unknown` |  |  |
| `price_band` | `free_only`, `pay_per_message`, `usd_10_25_month`, `usd_25_75_month`, `usd_75_200_month`, `usd_200_plus_month` |  | What your user would pay for what they saw. |
| `wants_beta` | boolean |  | Default `false`. |
| `wants_updates` | boolean |  | Default `false`. |
| `notes` | string |  | Anything else: dealbreakers, must-haves, comparisons. |

```bash
curl -X POST https://api.emailimport.com/v1/interest -H "authorization: Bearer $MXIMP_KEY" \
  -H 'content-type: application/json' -d '{}'
```

### get_account

`GET /v1/account` · scope `read`

The account this credential belongs to: kind (throwaway for a sandbox, standard once created with an email), whether its email is verified, the tenants it owns, and what this key reaches.


```bash
curl -X GET https://api.emailimport.com/v1/account -H "authorization: Bearer $MXIMP_KEY"
```

### list_tenants

`GET /v1/tenants` · scope `read`

The tenants this credential can act on. A sandbox key reaches exactly one, so tenant is implied on every other operation; a credential that reaches several must name one.


```bash
curl -X GET https://api.emailimport.com/v1/tenants -H "authorization: Bearer $MXIMP_KEY"
```

### create_tenant

`POST /v1/tenants` · scope `configure` · mutating

Create another tenant on this account: a separate business with its own buckets, keys and data. Needs a verified account. A key issued with no tenant list reaches it automatically; keys with an explicit list do not.

| Input | Type | Required | Notes |
|---|---|---|---|
| `name` | string | yes |  |
| `with_starters` | boolean |  | Seed the two starter buckets. Default `true`. |

```bash
curl -X POST https://api.emailimport.com/v1/tenants -H "authorization: Bearer $MXIMP_KEY" \
  -H 'content-type: application/json' -d '{"name":"…"}'
```

### create_key

`POST /v1/keys` · scope `configure` · mutating

Issue a new key on this account. The plaintext is returned once and never stored. Scopes: read, propose, run, approve, configure (default: read, propose, run, which cannot approve or change configuration). tenants: an explicit list, or omit to reach every tenant the account owns now and later.

| Input | Type | Required | Notes |
|---|---|---|---|
| `label` | string | yes |  |
| `scopes` | string[] |  | Default `["read","propose","run"]`. |
| `tenants` | string[] |  | Tenant ids or names this key reaches. Omit for all of the account's tenants. |

```bash
curl -X POST https://api.emailimport.com/v1/keys -H "authorization: Bearer $MXIMP_KEY" \
  -H 'content-type: application/json' -d '{"label":"…"}'
```

### list_keys

`GET /v1/keys` · scope `read`

Keys on this account: prefix, label, scopes, tenant list, last use, revocation. Never the key itself.


```bash
curl -X GET https://api.emailimport.com/v1/keys -H "authorization: Bearer $MXIMP_KEY"
```

### revoke_key

`DELETE /v1/keys/:id` · scope `configure` · mutating

Revoke a key on this account, including the one making the call. Immediate.

| Input | Type | Required | Notes |
|---|---|---|---|
| `id` | string | yes | Path parameter. |

```bash
curl -X DELETE https://api.emailimport.com/v1/keys/<id> -H "authorization: Bearer $MXIMP_KEY"
```

## Tenant

### get_tenant

`GET /v1/tenant` · scope `read`

This tenant: id, kind (sandbox or account), expiry, key scopes, counts, and the tenant policy.


```bash
curl -X GET https://api.emailimport.com/v1/tenant -H "authorization: Bearer $MXIMP_KEY"
```

### set_tenant_policy

`PUT /v1/policy` · scope `configure` · mutating

Set the tenant-wide default policy. Bucket policies override it field by field. {auto_accept:{min_confidence,require_complete,require_valid}, requires_human:[...], no_schema:'accept'|'task', task_on_unrouted:true}

| Input | Type | Required | Notes |
|---|---|---|---|
| `policy` | object | yes |  |

```bash
curl -X PUT https://api.emailimport.com/v1/policy -H "authorization: Bearer $MXIMP_KEY" \
  -H 'content-type: application/json' -d '{"policy":"…"}'
```

## Buckets and starters

### list_starters

`GET /v1/starters` · scope `read`

Starter schemas you can reference as schema: 'starter:<name>' or copy and edit. Each field lists its type and the ordered extractors that fill it.


```bash
curl -X GET https://api.emailimport.com/v1/starters -H "authorization: Bearer $MXIMP_KEY"
```

### list_buckets

`GET /v1/buckets` · scope `read`

List this tenant's buckets in evaluation order (priority, then name), with their rules, schemas, policies and destinations; each with the addresses made for it (full, ready to hand to a sender) and activity over the last 30 days: messages, auto-applied, held, last received.

| Input | Type | Required | Notes |
|---|---|---|---|
| `days` | integer |  | Activity window in days. Default `30`. |

```bash
curl -X GET https://api.emailimport.com/v1/buckets -H "authorization: Bearer $MXIMP_KEY"
```

### get_bucket

`GET /v1/buckets/:id` · scope `read`

Get one bucket by id or name.

| Input | Type | Required | Notes |
|---|---|---|---|
| `id` | string | yes | Path parameter. Bucket id or name |

```bash
curl -X GET https://api.emailimport.com/v1/buckets/<id> -H "authorization: Bearer $MXIMP_KEY"
```

### create_bucket

`POST /v1/buckets` · scope `configure` · mutating

Create a bucket: a name, a classification rule, an optional schema with extractors, a policy, and destinations. Messages land in the first enabled bucket (by priority) whose rule matches. Rules and extractor regexes are checked before saving.

| Input | Type | Required | Notes |
|---|---|---|---|
| `name` | string | yes | Unique within the tenant. |
| `description` | string |  |  |
| `priority` | integer |  | Lower runs first. Default 100. |
| `enabled` | boolean |  |  |
| `rule` | any |  | A JSON predicate: {any:[...]}, {all:[...]}, {not:...}, {address:'orders@'}, {sender_domain:'.example.com'}, {subject_contains:[...]}, {subject_matches:'regex'}, {header:{name,contains\|matches}}, {text_contains:[...]}, {text_matches:'regex'}, {has_attachment:true}, {attachment_name_matches:'regex'}, {attachment_mime:[...]}, {attachment_text_contains:[...]}, {auth:{spf,dkim,dmarc}}. |
| `schema` | string or object |  | A starter reference, or a schema of this exact shape (anything else is refused by name): schema: {name, fields: {<field>: {type: string\|number\|integer\|boolean\|date\|datetime\|email\|string[], required?, requires_human?, enum?, extract: [{kind: labeled_value, labels: [...]} \| {kind: regex, pattern: "(?<value>...)"} \| {kind: mailbox, source: from\|to\|reply_to, part: address\|name\|domain} \| {kind: header, name} \| {kind: constant, value}]}}}. Omit for a bucket with no extraction. |
| `policy` | object |  | {auto_accept:{min_confidence,require_complete,require_valid}, requires_human:[fields], no_schema:'accept'\|'task', on_flags:{<flag>:'accept'\|'task'}, require_passing_tests:true, forwarders:['office@x.example','@x.example','.x.example']} — forwarders this bucket trusts, so forwarded mail from them reads as from its original sender |
| `destinations` | string[] |  | Destination ids or names that receive applied captures. |

```bash
curl -X POST https://api.emailimport.com/v1/buckets -H "authorization: Bearer $MXIMP_KEY" \
  -H 'content-type: application/json' -d '{"name":"…"}'
```

### update_bucket

`PUT /v1/buckets/:id` · scope `configure` · mutating

Update a bucket. Only the fields you pass change; pass null for rule, schema or policy to clear them. Rules and extractors are checked before saving. A schema change is run against the bucket's test cases first (see run_tests) and refused if any fail, unless force is true or the policy sets require_passing_tests false. Existing messages are not reprocessed; call reprocess_message for those you want re-run.

| Input | Type | Required | Notes |
|---|---|---|---|
| `id` | string | yes | Path parameter. Bucket id or name |
| `name` | string |  | Unique within the tenant. |
| `description` | string or null |  |  |
| `priority` | integer or null |  |  |
| `enabled` | boolean,null |  |  |
| `rule` | object or null |  |  |
| `schema` | object or null |  |  |
| `policy` | object or null |  |  |
| `destinations` | array or null |  |  |
| `force` | boolean |  | Apply a schema change even though test cases fail. |

```bash
curl -X PUT https://api.emailimport.com/v1/buckets/<id> -H "authorization: Bearer $MXIMP_KEY" \
  -H 'content-type: application/json' -d '{}'
```

### delete_bucket

`DELETE /v1/buckets/:id` · scope `configure` · mutating

Delete a bucket. Messages already classified into it keep their capture records.

| Input | Type | Required | Notes |
|---|---|---|---|
| `id` | string | yes | Path parameter. |

```bash
curl -X DELETE https://api.emailimport.com/v1/buckets/<id> -H "authorization: Bearer $MXIMP_KEY"
```

## Subdomain and addresses

### get_subdomain

`GET /v1/subdomain` · scope `read`

This tenant's handle on the inbound mail domain, if it has claimed one, with the address forms it answers to and the catch-all setting.


```bash
curl -X GET https://api.emailimport.com/v1/subdomain -H "authorization: Bearer $MXIMP_KEY"
```

### claim_subdomain

`POST /v1/subdomain` · scope `configure` · mutating

Claim this tenant's handle on the inbound mail domain. Mail to <name>.<local>@mximp.com and <name>+<local>@mximp.com reaches it; a tenant later given a dedicated subdomain also answers to <local>@<name>.mximp.com. Rules: lowercase letters, digits, single hyphens, 8 to 40 characters, unique; reserved words (support, admin, billing…) alone or with a numeric or hyphenated suffix are refused, brand names anywhere are refused, mail-infrastructure prefixes are refused. A refusal names the rule. If the name is genuinely yours, call again with request_exception and a reason: the operator reviews it and, if approved, the subdomain is created for you.

| Input | Type | Required | Notes |
|---|---|---|---|
| `name` | string | yes |  |
| `request_exception` | boolean |  | Default `false`. |
| `reason` | string |  | Why the name should be allowed, when requesting an exception. |

```bash
curl -X POST https://api.emailimport.com/v1/subdomain -H "authorization: Bearer $MXIMP_KEY" \
  -H 'content-type: application/json' -d '{"name":"…"}'
```

### release_subdomain

`DELETE /v1/subdomain` · scope `configure` · mutating

Give up this tenant's subdomain. Mail to it stops arriving immediately; the name may be claimed by someone else later.

| Input | Type | Required | Notes |
|---|---|---|---|
| `confirm` | boolean | yes | Must be true. |

```bash
curl -X DELETE https://api.emailimport.com/v1/subdomain -H "authorization: Bearer $MXIMP_KEY"
```

### set_catch_all

`PUT /v1/subdomain/catch-all` · scope `configure` · mutating

Accept mail to any local part at this tenant's subdomain, not only created addresses. Off by default: a catch-all receives everything anyone sends, spam included. Messages to unknown local parts land with address_id null and are classified like any other.

| Input | Type | Required | Notes |
|---|---|---|---|
| `enabled` | boolean | yes |  |

```bash
curl -X PUT https://api.emailimport.com/v1/subdomain/catch-all -H "authorization: Bearer $MXIMP_KEY" \
  -H 'content-type: application/json' -d '{"enabled":true}'
```

### create_address

`POST /v1/addresses` · scope `configure` · mutating

Create an inbound address under this tenant's handle. kind named takes a local_part you choose (orders, coi.renewals); kind relationship makes an opaque, unguessable one (r-…) bound to a relationship_ref of yours, such as a vendor id, so mail to it is either that relationship or a leak. Pass bucket to make it that bucket's own address: the bucket's rule gains a clause matching it, so mail to the address lands there, and list_buckets shows it beside the bucket for a person to hand to senders. Every address can be disabled and carries an optional daily cap.

| Input | Type | Required | Notes |
|---|---|---|---|
| `kind` | `named`, `relationship` |  | Default `"named"`. |
| `local_part` | string |  | For named addresses. |
| `relationship_ref` | string |  | Your own id for the relationship, for relationship addresses. |
| `label` | string |  |  |
| `daily_cap` | integer |  | Messages per day before the address holds further mail. |
| `bucket` | string |  | Bucket id or name this address is for. Its rule will match the address. |

```bash
curl -X POST https://api.emailimport.com/v1/addresses -H "authorization: Bearer $MXIMP_KEY" \
  -H 'content-type: application/json' -d '{}'
```

### list_addresses

`GET /v1/addresses` · scope `read`

This tenant's inbound addresses with kind, relationship reference, enabled state, caps and counts.

| Input | Type | Required | Notes |
|---|---|---|---|
| `enabled` | boolean |  |  |
| `kind` | `named`, `relationship` |  |  |
| `limit` | integer |  | Default `50`. |

```bash
curl -X GET https://api.emailimport.com/v1/addresses -H "authorization: Bearer $MXIMP_KEY"
```

### set_address_enabled

`PUT /v1/addresses/:id/enabled` · scope `configure` · mutating

Disable an address (mail to it is refused and counted) or enable it again. Addresses leak; disabling is the first response.

| Input | Type | Required | Notes |
|---|---|---|---|
| `id` | string | yes | Path parameter. Address id or local part |
| `enabled` | boolean | yes |  |

```bash
curl -X PUT https://api.emailimport.com/v1/addresses/<id>/enabled -H "authorization: Bearer $MXIMP_KEY" \
  -H 'content-type: application/json' -d '{"enabled":true}'
```

### set_address_forwarders

`PUT /v1/addresses/:id/forwarders` · scope `configure` · mutating

Declare who an address expects forwarded mail from, when it is the target of a Gmail or Outlook forwarding rule: addresses, @domain, or .domain. Mail arriving there from anyone else is flagged unexpected_sender (policy.on_flags decides what that does; it holds by default), which keeps a forwarded stream as trustworthy as a per-relationship address. Pass an empty list to clear.

| Input | Type | Required | Notes |
|---|---|---|---|
| `id` | string | yes | Path parameter. Address id or local part |
| `forwarders` | string[] | yes |  |

```bash
curl -X PUT https://api.emailimport.com/v1/addresses/<id>/forwarders -H "authorization: Bearer $MXIMP_KEY" \
  -H 'content-type: application/json' -d '{"forwarders":"…"}'
```

## Destinations

### list_destinations

`GET /v1/destinations` · scope `read`

List destinations. Secrets are never returned.


```bash
curl -X GET https://api.emailimport.com/v1/destinations -H "authorization: Bearer $MXIMP_KEY"
```

### add_destination

`POST /v1/destinations` · scope `configure` · mutating

Add a webhook destination. Applied captures are POSTed as JSON with X-Mximp-Delivery and, when a secret is set, X-Mximp-Signature: sha256=<hmac of body>. Attach it to buckets by name or id.

| Input | Type | Required | Notes |
|---|---|---|---|
| `name` | string | yes |  |
| `kind` | `webhook` |  | Default `"webhook"`. |
| `url` | string | yes |  |
| `secret` | string |  |  |
| `enabled` | boolean |  | Default `true`. |

```bash
curl -X POST https://api.emailimport.com/v1/destinations -H "authorization: Bearer $MXIMP_KEY" \
  -H 'content-type: application/json' -d '{"name":"…","url":"…"}'
```

### remove_destination

`DELETE /v1/destinations/:id` · scope `configure` · mutating

Remove a destination. Buckets that referenced it stop delivering to it.

| Input | Type | Required | Notes |
|---|---|---|---|
| `id` | string | yes | Path parameter. |

```bash
curl -X DELETE https://api.emailimport.com/v1/destinations/<id> -H "authorization: Bearer $MXIMP_KEY"
```

## Messages and ingest

### ingest_message

`POST /v1/messages/ingest` · scope `run` · mutating

Run one email through the pipeline now: parse, sanitize, classify into a bucket, extract fields, validate, route by policy. Pass eml (a raw RFC 822 message, as received or exported from a mail client) or html (a page or body; from/to/subject then describe the synthetic envelope). Returns the message id, the bucket, the capture with every field's value and confidence, and any tasks. Nothing here calls a model.

| Input | Type | Required | Notes |
|---|---|---|---|
| `eml` | string |  | Raw RFC 822 email text |
| `envelope_from` | string |  | The SMTP envelope sender, when you have it (e.g. an SRS-rewritten address); used to recognise automatic forwarding. |
| `html` | string |  | HTML to wrap as a message body when eml is not given |
| `from` | string |  | Sender for html ingest, e.g. 'Dana <dana@example.com>' |
| `to` | string |  | Recipient address; acts as the envelope recipient for rules like {address:'orders@'} |
| `subject` | string |  |  |
| `auth` | object |  | Sandbox only: pretend these authentication results were received, so rules like {auth:{dkim:'pass'}} can be tested. Recorded as synthetic. |

```bash
curl -X POST https://api.emailimport.com/v1/messages/ingest -H "authorization: Bearer $MXIMP_KEY" \
  -H 'content-type: application/json' -d '{}'
```

### list_messages

`GET /v1/messages` · scope `read`

List received messages, newest first, with bucket and status. Filter by bucket (id or name) or status (applied, task, held, unrouted). Page with before=<last id>.

| Input | Type | Required | Notes |
|---|---|---|---|
| `bucket` | string |  |  |
| `status` | string |  |  |
| `limit` | integer |  | Default `50`. |
| `before` | string |  |  |

```bash
curl -X GET https://api.emailimport.com/v1/messages -H "authorization: Bearer $MXIMP_KEY"
```

### get_message

`GET /v1/messages/:id` · scope `read`

One message: sanitized body text, headers, auth results, sanitization flags and any hidden text, documents (attachments) with their text length, the classification, and its captures. Raw MIME is never returned.

| Input | Type | Required | Notes |
|---|---|---|---|
| `id` | string | yes | Path parameter. |
| `include_headers` | boolean |  | Default `false`. |

```bash
curl -X GET https://api.emailimport.com/v1/messages/<id> -H "authorization: Bearer $MXIMP_KEY"
```

### get_document_text

`GET /v1/documents/:id` · scope `read`

The extracted text of one document (attachment or rendered HTML body), for writing extractors against. Offsets in capture field sources refer to this text.

| Input | Type | Required | Notes |
|---|---|---|---|
| `id` | string | yes | Path parameter. |

```bash
curl -X GET https://api.emailimport.com/v1/documents/<id> -H "authorization: Bearer $MXIMP_KEY"
```

### reprocess_message

`POST /v1/messages/:id/reprocess` · scope `run` · mutating

Re-run classification, extraction, validation and routing for a stored message against the current buckets. Creates a new capture; earlier captures are kept. Use after changing a rule or extractor.

| Input | Type | Required | Notes |
|---|---|---|---|
| `id` | string | yes | Path parameter. |

```bash
curl -X POST https://api.emailimport.com/v1/messages/<id>/reprocess -H "authorization: Bearer $MXIMP_KEY" \
  -H 'content-type: application/json' -d '{}'
```

### get_flow

`GET /v1/flow` · scope `read`

The tenant's mail as a flow over a window: sources (addresses, catch-all, uploads) into buckets, buckets into outcomes (auto-applied, approved, held with the reason, unrouted), outcomes into exits (webhook delivered, failed, held for reading). Nodes and links for a Sankey; counts only, no content.

| Input | Type | Required | Notes |
|---|---|---|---|
| `hours` | integer |  | Default `168`. |

```bash
curl -X GET https://api.emailimport.com/v1/flow -H "authorization: Bearer $MXIMP_KEY"
```

## Captures

### list_captures

`GET /v1/captures` · scope `read`

List captures (one per processed message per bucket), newest first. Filter by bucket, status (applied, task, held), message, or delivery (failed, delivered, none) to find webhook deliveries that failed and deliver them again.

| Input | Type | Required | Notes |
|---|---|---|---|
| `bucket` | string |  |  |
| `status` | string |  |  |
| `message` | string |  |  |
| `delivery` | `failed`, `delivered`, `none` |  | failed: at least one failed delivery and no later success; delivered: at least one success; none: never delivered |
| `limit` | integer |  | Default `50`. |
| `before` | string |  |  |

```bash
curl -X GET https://api.emailimport.com/v1/captures -H "authorization: Bearer $MXIMP_KEY"
```

### get_capture

`GET /v1/captures/:id` · scope `read`

One capture in full: each field's value, confidence, raw text and source coordinates; validation issues; routing reason; deliveries.

| Input | Type | Required | Notes |
|---|---|---|---|
| `id` | string | yes | Path parameter. |

```bash
curl -X GET https://api.emailimport.com/v1/captures/<id> -H "authorization: Bearer $MXIMP_KEY"
```

### correct_field

`POST /v1/captures/:id/fields/:field` · scope `propose` · mutating

Set a field's value on a capture. Recorded as a correction with the actor and reason; the capture is re-validated but its status does not change until approve_capture. Corrections are the material for improving extractors.

| Input | Type | Required | Notes |
|---|---|---|---|
| `id` | string | yes | Path parameter. |
| `field` | string | yes | Path parameter. |
| `value` | any | yes |  |
| `reason` | string |  |  |

```bash
curl -X POST https://api.emailimport.com/v1/captures/<id>/fields/<field> -H "authorization: Bearer $MXIMP_KEY" \
  -H 'content-type: application/json' -d '{"value":"…"}'
```

### approve_capture

`POST /v1/captures/:id/approve` · scope `approve` · mutating

Apply a capture that policy held for review. Requires the approve scope. Resolves its open tasks and delivers to the bucket's destinations. Fails if validation still has non-required issues unless force is true.

| Input | Type | Required | Notes |
|---|---|---|---|
| `id` | string | yes | Path parameter. |
| `force` | boolean |  | Default `false`. |
| `note` | string |  |  |

```bash
curl -X POST https://api.emailimport.com/v1/captures/<id>/approve -H "authorization: Bearer $MXIMP_KEY" \
  -H 'content-type: application/json' -d '{}'
```

### deliver_capture

`POST /v1/captures/:id/deliver` · scope `run` · mutating

Deliver an applied capture to its bucket's destinations again, for example after a webhook failed or a destination was added. A capture that is not applied is refused; approve it first. Each attempt is recorded under the capture's deliveries.

| Input | Type | Required | Notes |
|---|---|---|---|
| `id` | string | yes | Path parameter. |

```bash
curl -X POST https://api.emailimport.com/v1/captures/<id>/deliver -H "authorization: Bearer $MXIMP_KEY" \
  -H 'content-type: application/json' -d '{}'
```

## Tasks

### list_tasks

`GET /v1/tasks` · scope `read`

Work waiting for a person or an agent: unrouted messages, captures held for review, fields that require a human. Default shows open tasks.

| Input | Type | Required | Notes |
|---|---|---|---|
| `status` | `open`, `resolved`, `dismissed` |  | Default `"open"`. |
| `kind` | string |  |  |
| `limit` | integer |  | Default `50`. |

```bash
curl -X GET https://api.emailimport.com/v1/tasks -H "authorization: Bearer $MXIMP_KEY"
```

### get_task

`GET /v1/tasks/:id` · scope `read`

One task with its payload.

| Input | Type | Required | Notes |
|---|---|---|---|
| `id` | string | yes | Path parameter. |

```bash
curl -X GET https://api.emailimport.com/v1/tasks/<id> -H "authorization: Bearer $MXIMP_KEY"
```

### resolve_task

`POST /v1/tasks/:id/resolve` · scope `propose` · mutating

Close a task as resolved or dismissed with a short note. Approving a capture resolves its tasks automatically; use this for unrouted messages you have handled or reviews you decline.

| Input | Type | Required | Notes |
|---|---|---|---|
| `id` | string | yes | Path parameter. |
| `status` | `resolved`, `dismissed` |  | Default `"resolved"`. |
| `note` | string |  |  |

```bash
curl -X POST https://api.emailimport.com/v1/tasks/<id>/resolve -H "authorization: Bearer $MXIMP_KEY" \
  -H 'content-type: application/json' -d '{}'
```

## Dry runs

### dry_run_rule

`POST /v1/dry-run/rule` · scope `read`

Test a classification rule against stored messages (by id) or an inline eml/html without saving anything. Returns, per message, whether it matched and which predicate decided.

| Input | Type | Required | Notes |
|---|---|---|---|
| `rule` | any | yes |  |
| `message_ids` | string[] |  |  |
| `eml` | string |  |  |
| `html` | string |  |  |

```bash
curl -X POST https://api.emailimport.com/v1/dry-run/rule -H "authorization: Bearer $MXIMP_KEY" \
  -H 'content-type: application/json' -d '{"rule":"…"}'
```

### dry_run_schema

`POST /v1/dry-run/schema` · scope `read`

Run a schema's extractors against stored messages or an inline eml/html without saving anything. Returns each field's value, confidence and source per message, plus validation, so you can iterate on regexes before update_bucket. Optionally pass expected values per message id to get a pass/fail per field.

| Input | Type | Required | Notes |
|---|---|---|---|
| `schema` | object | yes | A schema of this exact shape (anything else is refused by name): schema: {name, fields: {<field>: {type: string\|number\|integer\|boolean\|date\|datetime\|email\|string[], required?, requires_human?, enum?, extract: [{kind: labeled_value, labels: [...]} \| {kind: regex, pattern: "(?<value>...)"} \| {kind: mailbox, source: from\|to\|reply_to, part: address\|name\|domain} \| {kind: header, name} \| {kind: constant, value}]}}} |
| `message_ids` | string[] |  |  |
| `eml` | string |  |  |
| `html` | string |  |  |
| `expected` | object |  | message_id → {field: expected value} |

```bash
curl -X POST https://api.emailimport.com/v1/dry-run/schema -H "authorization: Bearer $MXIMP_KEY" \
  -H 'content-type: application/json' -d '{"schema":"…"}'
```

## Test suite

### promote_to_test

`POST /v1/tests` · scope `propose` · mutating

Turn a capture into a regression case for its bucket: the stored message plus the field values as they stand now (approved or corrected). From then on any schema change to that bucket is run against it. Prefer captures that needed a correction or a task; a suite of easy cases proves nothing. Pass expected to override the values, or omit fields you do not want checked.

| Input | Type | Required | Notes |
|---|---|---|---|
| `capture_id` | string | yes |  |
| `expected` | object |  | Field → expected value. Default: the capture's current values. |
| `tricky` | boolean |  | Mark as a hard case that is kept when the cap is reached. Default: true if the capture was corrected or held for review. |
| `note` | string |  |  |

```bash
curl -X POST https://api.emailimport.com/v1/tests -H "authorization: Bearer $MXIMP_KEY" \
  -H 'content-type: application/json' -d '{"capture_id":"…"}'
```

### list_tests

`GET /v1/tests` · scope `read`

The regression suite: cases by bucket, with origin, whether they are marked tricky, and the expected values.

| Input | Type | Required | Notes |
|---|---|---|---|
| `bucket` | string |  | Bucket id or name |
| `include_retired` | boolean |  | Default `false`. |
| `limit` | integer |  | Default `50`. |

```bash
curl -X GET https://api.emailimport.com/v1/tests -H "authorization: Bearer $MXIMP_KEY"
```

### run_tests

`POST /v1/tests/run` · scope `read`

Run a bucket's cases against its current schema, or against a candidate schema you pass, without changing anything. Returns per-case pass or fail and, for failures, each field's expected versus actual. This is the check before update_bucket; with require_passing_tests on (the default) update_bucket runs it for you and refuses a failing change.

| Input | Type | Required | Notes |
|---|---|---|---|
| `bucket` | string | yes | Bucket id or name |
| `schema` | object |  | A candidate schema to test instead of the bucket's own. |

```bash
curl -X POST https://api.emailimport.com/v1/tests/run -H "authorization: Bearer $MXIMP_KEY" \
  -H 'content-type: application/json' -d '{"bucket":"…"}'
```

### get_test_run

`GET /v1/tests/runs/:id` · scope `read`

One test run in full: every case with each field's expected and actual value and the confidence it was found at.

| Input | Type | Required | Notes |
|---|---|---|---|
| `id` | string | yes | Path parameter. |

```bash
curl -X GET https://api.emailimport.com/v1/tests/runs/<id> -H "authorization: Bearer $MXIMP_KEY"
```

### list_test_runs

`GET /v1/tests/runs` · scope `read`

Recent test runs, newest first, with counts. Runs are kept for 90 days.

| Input | Type | Required | Notes |
|---|---|---|---|
| `bucket` | string |  |  |
| `limit` | integer |  | Default `50`. |

```bash
curl -X GET https://api.emailimport.com/v1/tests/runs -H "authorization: Bearer $MXIMP_KEY"
```

### remove_test

`DELETE /v1/tests/:id` · scope `propose` · mutating

Retire a case. It stops running and its message is no longer pinned; the record stays for the audit trail.

| Input | Type | Required | Notes |
|---|---|---|---|
| `id` | string | yes | Path parameter. |
| `reason` | string |  |  |

```bash
curl -X DELETE https://api.emailimport.com/v1/tests/<id> -H "authorization: Bearer $MXIMP_KEY"
```

## Events

### list_events

`GET /v1/events` · scope `read`

The audit trail: every state change with its actor. Newest first by default; pass after=<event id> to page forward from a point you have seen (oldest first), which is how an agent catches up.

| Input | Type | Required | Notes |
|---|---|---|---|
| `type` | string |  |  |
| `subject_id` | string |  |  |
| `after` | string |  |  |
| `limit` | integer |  | Default `50`. |

```bash
curl -X GET https://api.emailimport.com/v1/events -H "authorization: Bearer $MXIMP_KEY"
```

## Tenant

### submit_feedback

`POST /v1/feedback` · scope `read` · mutating

Tell the people who run this platform what was confusing, missing, wrong, or good. Written by agents as often as by people. Read by a human; nothing here is acted on automatically. Include the operation or page you were using and what you expected.

| Input | Type | Required | Notes |
|---|---|---|---|
| `text` | string | yes | What happened and what you expected. |
| `about` | string |  | The operation, page, or concept this is about, e.g. 'dry_run_schema' or 'docs/extractors'. |
| `severity` | `low`, `normal`, `high` |  | Default `"normal"`. |

```bash
curl -X POST https://api.emailimport.com/v1/feedback -H "authorization: Bearer $MXIMP_KEY" \
  -H 'content-type: application/json' -d '{"text":"…"}'
```

### grant_support_access

`POST /v1/support-grant` · scope `configure` · mutating

Let the platform operator reach this tenant's messages, captures and configuration for a limited time, to help with a problem. Without a grant the operator sees counts and nothing else. Every operator action under the grant is written to this tenant's events. Revoke any time with revoke_support_access.

| Input | Type | Required | Notes |
|---|---|---|---|
| `hours` | integer |  | How long the grant lasts. Default 24, at most 168. Default `24`. |
| `reason` | string |  | What you want help with. |

```bash
curl -X POST https://api.emailimport.com/v1/support-grant -H "authorization: Bearer $MXIMP_KEY" \
  -H 'content-type: application/json' -d '{}'
```

### revoke_support_access

`DELETE /v1/support-grant` · scope `configure` · mutating

End any active support grant now.


```bash
curl -X DELETE https://api.emailimport.com/v1/support-grant -H "authorization: Bearer $MXIMP_KEY"
```
