# mail.drafts.update

Save reviewed company financial facts with current message and draft revisions.

`POST /api/v1/accounting/mail.drafts.update`

Permissions: `mail:read`, `mail:write` · Roles: admin, finance · Idempotency key required · Send `expectedRevision`

MCP tool: `accounting_mail_drafts_update`

## Fields

| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `id` | string (ID) | Yes | The record's ID. |
| `expectedRevision` | integer | Yes | The record's current revision, from the last time you read it. If someone changed the record since, the request is refused with a conflict so you can reload and check before trying again. at most 9007199254740991; greater than 0. |
| `idempotencyKey` | string | Yes | Any unique text you generate once per intended change, so a retried request only happens once. Send it as the Idempotency-Key header instead if you prefer; if you send both they must match. 8–160 characters. |
| `messageRevision` | integer | Yes | The related record's current revision, from the last time you read it. at most 9007199254740991; greater than 0. |
| `facts` | object | Yes | No other fields. |
| `facts.receipts` | array of objects | Yes | at most 20 items. |
| `facts.receipts[].merchant` | string or null | Yes |  |
| `facts.receipts[].merchantAddress` | string or null |  |  |
| `facts.receipts[].travelAddress` | string or null |  |  |
| `facts.receipts[].date` | string or null | Yes | A date, as YYYY-MM-DD. |
| `facts.receipts[].currency` | string or null | Yes | Three-letter currency code, such as CAD or USD. |
| `facts.receipts[].total` | string or null | Yes |  |
| `facts.receipts[].subtotal` | string or null | Yes |  |
| `facts.receipts[].tax` | string or null | Yes |  |
| `facts.receipts[].tip` | string or null | Yes |  |
| `facts.receipts[].discount` | string or null | Yes |  |
| `facts.receipts[].type` | enum | Yes | One of: `expense`, `income`, `income_refund`, `refund`, `transfer`, `fee`. |
| `facts.receipts[].invoiceNumber` | string or null | Yes |  |
| `facts.receipts[].description` | string | Yes | A short description. at most 1000 characters. |
| `facts.receipts[].taxes` | array of objects | Yes | at most 10 items. |
| `facts.receipts[].taxes[].label` | string | Yes | at most 100 characters. |
| `facts.receipts[].taxes[].amount` | string or null | Yes |  |
| `facts.receipts[].sourceEvidenceIds` | array of strings (ID) | Yes | A list of record IDs. 1–40 items. |
| `facts.receipts[].lineItems` | array of objects |  | at most 50 items. |
| `facts.receipts[].lineItems[].description` | string | Yes | A short description. 1–500 characters. |
| `facts.receipts[].lineItems[].amount` | string or null | Yes |  |
| `facts.receipts[].lineItems[].basis` | enum | Yes | One of: `gross`, `net`, `unknown`. |
| `facts.receipts[].lineItems[].sourceEvidenceIds` | array of strings | Yes | A list of record IDs. 1–10 items. |
| `facts.receipts[].warnings` | array of strings | Yes | at most 20 items; each at most 500 characters. |
| `facts.receipts[].documentKind` | enum | Yes | One of: `receipt`, `invoice`, `statement`, `refund_notice`, `credit_note`, `other`, `unknown`. |
| `facts.receipts[].paymentState` | enum | Yes | One of: `paid`, `unpaid`, `partial`, `refunded`, `unknown`. |
| `facts.receipts[].categoryId` | string (ID) or null |  | The ID of a category, from categories.list. |
| `facts.receipts[].documentClaims` | object or null |  |  |
| `facts.receipts[].documentClaims.kind` | enum | Yes | Which kind of record or job this is. One of: `receipt`, `invoice`, `credit_note`, `refund_notice`, `statement`, `other`, `unknown`. |
| `facts.receipts[].documentClaims.issuer` | object or null | Yes |  |
| `facts.receipts[].documentClaims.issuer.name` | string or null | Yes | A display name. |
| `facts.receipts[].documentClaims.issuer.taxId` | string or null | Yes |  |
| `facts.receipts[].documentClaims.issuer.email` | string or null | Yes | An email address. |
| `facts.receipts[].documentClaims.customer` | object or null | Yes |  |
| `facts.receipts[].documentClaims.customer.name` | string or null | Yes | A display name. |
| `facts.receipts[].documentClaims.customer.taxId` | string or null | Yes |  |
| `facts.receipts[].documentClaims.customer.email` | string or null | Yes | An email address. |
| `facts.receipts[].documentClaims.issueDate` | string or null | Yes | The date the document was issued, as YYYY-MM-DD. |
| `facts.receipts[].documentClaims.dueDate` | string or null | Yes | The date payment is due, as YYYY-MM-DD. |
| `facts.receipts[].documentClaims.taxPointDate` | string or null | Yes |  |
| `facts.receipts[].documentClaims.paymentState` | enum | Yes | One of: `paid`, `unpaid`, `partial`, `refunded`, `unknown`. |
| `facts.receipts[].documentClaims.amountPaid` | string or null | Yes |  |
| `facts.receipts[].documentClaims.amountDue` | string or null | Yes |  |
| `facts.receipts[].documentClaims.relatedInvoiceNumber` | string or null | Yes |  |
| `facts.receipts[].paymentCard` | object or null |  |  |
| `facts.receipts[].paymentCard.brand` | string or null | Yes |  |
| `facts.receipts[].paymentCard.lastFour` | string or null | Yes |  |
| `facts.receipts[].paymentBreakdown` | object or null |  |  |
| `facts.receipts[].paymentBreakdown.cardAmount` | string or null | Yes |  |
| `facts.receipts[].paymentBreakdown.giftCardAmount` | string or null | Yes |  |
| `facts.receipts[].paymentBreakdown.creditAmount` | string or null | Yes |  |
| `facts.receipts[].paymentBreakdown.pointsValue` | string or null | Yes |  |
| `facts.receipts[].otherCharges` | array of objects |  | at most 20 items. |
| `facts.receipts[].otherCharges[].label` | string | Yes | at most 100 characters. |
| `facts.receipts[].otherCharges[].amount` | string or null | Yes |  |
| `facts.warnings` | array of strings | Yes | at most 20 items; each at most 500 characters. |
| `facts.documentReadings` | array of objects |  | at most 60 items. |
| `facts.documentReadings[].evidenceId` | string (ID) | Yes | The ID of the related record. |
| `facts.documentReadings[].filename` | string | Yes | The file's name, including its extension. at most 255 characters. |
| `facts.documentReadings[].mimeType` | string | Yes | The file's type, such as image/jpeg or application/pdf. at most 200 characters. |
| `facts.documentReadings[].status` | enum | Yes | Only include records with this status. One of: `read`, `unreadable`, `unsupported`. |
| `facts.documentReadings[].text` | string | Yes | at most 12000 characters. |
| `facts.documentReadings[].sourceEvidenceIds` | array of strings (ID) | Yes | A list of record IDs. at most 60 items. |
| `facts.documentReadings[].warnings` | array of strings | Yes | at most 20 items; each at most 500 characters. |

## Example request

```bash
curl https://app.getoatmilk.com/api/v1/accounting/mail.drafts.update \
  -H "Authorization: Bearer $OATMILK_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
  "expectedRevision": 3,
  "messageRevision": 3,
  "facts": {
    "receipts": [
      {
        "merchant": "example",
        "date": "2026-09-30",
        "currency": "CAD",
        "total": "1.5",
        "subtotal": "1.5",
        "tax": "1.5",
        "tip": "1.5",
        "discount": "1.5",
        "type": "expense",
        "invoiceNumber": "example",
        "description": "Synthetic example from the docs",
        "taxes": [
          {
            "label": "example",
            "amount": "1.5"
          }
        ],
        "sourceEvidenceIds": [
          "7f0f6c1e-1c1f-4b5e-9c8d-2f5e8e3c1a10"
        ],
        "warnings": [
          "example"
        ],
        "documentKind": "receipt",
        "paymentState": "paid"
      }
    ],
    "warnings": [
      "example"
    ]
  }
}'
```

Reference page: https://app.getoatmilk.com/docs/api/mail.drafts.update
