# ai.subscriptions.register

Connect an official Codex app-server or unmodified Claude Code runner owned by the signed-in person. Stores its name and model capabilities, never subscription credentials. Human sign-in required.

`POST /api/v1/accounting/ai.subscriptions.register`

Permissions: `accounting:read`, `accounting:write` · Roles: admin, finance, contributor · Idempotency key required

Not available over MCP: Choosing and sharing a personal subscription is the signed-in person's explicit choice in Settings or the CLI, never an agent's delegation.

## Fields

| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `provider` | enum | Yes | One of: `codex`, `claude-code`. |
| `label` | string | Yes | 1–80 characters. |
| `models` | array of objects | Yes | 1–32 items. |
| `models[].modelId` | string | Yes | 1–160 characters; Matches ^[a-zA-Z0-9][a-zA-Z0-9_./:@+-]*$. |
| `models[].efforts` | array of enum values | Yes | One of: `none`, `low`, `medium`, `high`, `xhigh`, `max`, `ultra`. at most 7 items. |
| `models[].tools` | boolean | Yes |  |
| `models[].vision` | boolean | Yes |  |
| `models[].json` | boolean | Yes |  |
| `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. |

## Example request

```bash
curl https://app.getoatmilk.com/api/v1/accounting/ai.subscriptions.register \
  -H "Authorization: Bearer $OATMILK_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "provider": "codex",
  "label": "example",
  "models": [
    {
      "modelId": "model_id",
      "efforts": [
        "none"
      ],
      "tools": true,
      "vision": true,
      "json": true
    }
  ]
}'
```

Reference page: https://app.getoatmilk.com/docs/api/ai.subscriptions.register
