> For the complete documentation index, see [llms.txt](https://archer-bot.gitbook.io/archer.bot/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://archer-bot.gitbook.io/archer.bot/publish-on-archer/records.md).

# Records: Durable Outcomes

The response envelope has four arms: `data` renders, `cost` settles, `authorizations[]` gets signed, and `record` describes a durable outcome the user owns once the first three are done. A booking, an order, a subscription, a position in a vault: each of these outlives the chat turn that created it, and the user expects to find it again later on their activity page without asking you again what it was. `record` is how you tell Archer that. `recordKind` is a string you choose (`booking`, `order`, `subscription`, `position`, anything that fits your service); Archer stores it opaque and never branches on it. A position and a booking are handled by the exact same code path on Archer's side.

## When to return a record

Return a record when the outcome outlives this response: a reservation the user can look up next week, an order they will want to track, a position they can add to or exit later. Return only `data` when it does not: a price quote, a search result, a balance check. If nothing changes state on your side and there is nothing to look up again tomorrow, there is no record to write.

## The record descriptor

A generic example: a hotel-style booking service confirms a reservation and returns both the transaction to sign and the record to keep.

```json
{
  "recordKind": "booking",
  "ref": "CONF-48213",
  "basisMicro": "184000000",
  "activeUntil": "2026-09-20T15:00:00Z",
  "disclosure": {
    "custody": "NONE",
    "exitModel": "RESTRICTED",
    "payment": "pay_at_property"
  },
  "exitInstructions": {
    "confirmationNumber": "CONF-48213",
    "contactEmail": "on-file-with-your-service"
  },
  "actions": [
    { "key": "refresh", "label": "Check status", "instructions": { "confirmationNumber": "CONF-48213" }, "style": "default" },
    { "key": "cancel", "label": "Cancel booking", "instructions": { "confirmationNumber": "CONF-48213" }, "style": "danger" }
  ]
}
```

A later response for the same booking (say, from a cancellation sub-tool) only needs enough to identify and update it:

```json
{
  "recordKind": "booking",
  "ref": "CONF-48213",
  "terminal": true
}
```

### Fields

| Field              | Type                         | Meaning                                                                                                                                                                                                                     |
| ------------------ | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `recordKind`       | string, required             | What kind of outcome this is. Yours to name, up to 64 characters. Opaque to Archer.                                                                                                                                         |
| `ref`              | string, up to 128 characters | The identity of this outcome (a confirmation number, an order ID). Required to update or close a record later. Scoped to your own namespace, see Lifecycle below.                                                           |
| `groupKey`         | string, up to 128 characters | Set this when repeat invocations should accrue into ONE record instead of creating a new row each time, for example three deposits into the same vault position. Omit it for a distinct outcome like a booking or an order. |
| `basisMicro`       | decimal string               | What the user committed, in micro-USD (`1000000` = $1.00). Always a decimal string, never a float.                                                                                                                          |
| `valueMicro`       | decimal string               | The outcome's current value, once known. Same encoding as `basisMicro`.                                                                                                                                                     |
| `activeUntil`      | ISO-8601 string              | The point at which this outcome resolves on its own: a checkout date, an expiry, a settlement date. Once this passes, the record displays as Completed even if you never send a closing update.                             |
| `terminal`         | boolean                      | Set `true` on the response that closes this record: cancelled, redeemed, refunded, fully withdrawn.                                                                                                                         |
| `disclosure`       | object                       | Trust fields shown to the user before they commit. `custody` and `exitModel` are the two Archer surfaces directly; add any other keys you want disclosed alongside them.                                                    |
| `exitInstructions` | object                       | Whatever your own endpoint needs to reverse or check on this outcome later. Opaque to Archer: stored server-side, never rendered to the user, and sent back to you verbatim if the user exits.                              |
| `viewUrl`          | string                       | A link to your own per-user page for this outcome, if you have one.                                                                                                                                                         |
| `actions`          | array, up to 4 entries       | Buttons the user can trigger from their activity page. See below.                                                                                                                                                           |

Each entry in `actions` is `{ key, label, instructions, style }`. `key` is lowercase letters, digits, `_` and `-`, up to 32 characters, and cannot be `exit` or `close` (those are reserved for the built-in exit affordance). `label` is what the user sees on the button: 1 to 24 characters, and cannot look like a domain or URL, or mix lookalike characters from different scripts. `instructions` is an opaque object, handled the same way as `exitInstructions`. `style` is `default`, `primary`, or `danger`. The whole descriptor, encoded as JSON, must stay under 16KB.

## Lifecycle: open, update, close

The first response carrying a given `ref` for your intent opens a new record. Any later response reusing that same `ref` updates the existing record: a new `valueMicro`, a new `activeUntil`, refreshed `disclosure` or `actions`, or a new `viewUrl`. A response with `terminal: true` closes it; if `valueMicro` on that closing response is lower than the recorded `basisMicro`, the record closes as reduced instead of fully closed, which covers a partial withdrawal or a partial refund.

`ref` is scoped to your own namespace as a builder, not to the single sub-tool that issued it. If you publish a booking-creation tool and a separate cancellation tool as two different `IntentDefinition` rows, a lifecycle response from the cancellation tool using the same `ref` updates the exact record the booking tool opened. You do not need to correlate the two tools yourself; returning the same `ref` is enough.

Display status is derived, not something you set directly. A closed record shows as Completed. A reduced record shows as Reduced. Anything else shows as Active until its `activeUntil` passes, at which point it shows as Completed automatically, so a booking past checkout reads as done without you having to send a final update.

The user sees their records in two places: the activity page in the app (every builder's outcomes in one list) and the `list_activity` MCP tool, which any connected agent can call read-only and free of charge. Both surfaces show `recordKind`, your handle, status, amounts, `ref`, `activeUntil`, `viewUrl`, and the action buttons' keys, labels, and styles. Neither ever exposes `exitInstructions` or an action's `instructions`; those stay server-side.

## The action round-trip

When a user clicks one of your declared actions, Archer re-dispatches that action's `instructions` back to you as a signed envelope, using the same signature scheme as your original dispatch. By default the request goes to `<your toolEndpoint>/action`. You can send it somewhere else by adding an `endpoint` key inside that action's `instructions`; Archer resolves it against your registered `toolEndpoint`'s origin, so a declared endpoint can never point off the host you registered.

The re-dispatch carries `actionKey`, the `instructions` object you originally declared for that action, the record's `ref` (as `recordRef`) when one exists, and any `params` the user supplied. You respond with the same response envelope shape as any other dispatch: return `authorizations[]` if the action needs a new signature (a top-up, a claim), or `data` with an updated `record` arm if the action resolves entirely on your side (a cancellation, a status refresh). When you send a `record` arm on that response, use the same `ref`; Archer updates or closes the same row rather than creating a new one.

## Privacy: opaque instructions

`exitInstructions` and every action's `instructions` are opaque to Archer. They are stored so the user's own record stays usable, never rendered on any screen, and sent back only to your own declared endpoints when the user exits or triggers an action. Do not put a secret in them that you cannot re-verify on your side, such as a credential with no expiry or a way to skip your own auth checks. Anything that would matter if it leaked belongs behind your own lookup, keyed by the confirmation number or reference you already control.
