# taxInfo.save

Add, replace or remove one of your tax numbers (SIN, business number, ITN, or your country's tax number) for your tax slips. It's stored encrypted and only ever shown partly again. Add or replace a tax number in your contractor portal. Agents and API tokens can't handle full tax numbers.

`POST /api/v1/contractor/taxInfo.save`

Permissions: `contractor:read`, `contractor:write` · Roles: contractor · Idempotency key required · Send `expectedRevision`

**INTERACTIVE_PORTAL_REQUIRED.** Only the contractor does this, in their own portal. API and MCP calls are refused with a portalUrl to the exact step.

MCP tool: `contractor_tax_info_save`

## Fields

| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `expectedRevision` | integer or null |  | 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. |
| `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–200 characters. |
| `taxNumber` | object |  | No other fields. |
| `taxNumber.kind` | enum | Yes | Which kind of record or job this is. One of: `sin`, `bn`, `itn`, `foreign`. |
| `taxNumber.value` | string | Yes | 1–40 characters. |
| `taxNumber.country` | string or null |  |  |
| `removeTaxNumber` | enum |  | One of: `sin`, `bn`, `itn`, `foreign`. |

## Example request

```bash
curl https://app.getoatmilk.com/api/v1/contractor/taxInfo.save \
  -H "Authorization: Bearer $OATMILK_OAUTH_TOKEN" \
  -H "X-Accounting-Organization: $OATMILK_ORGANIZATION_ID" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "taxNumber": {
    "kind": "sin",
    "value": "example"
  }
}'
```

Reference page: https://app.getoatmilk.com/docs/api/contractor/taxInfo.save
