Skip to main content
Account Insights answers two questions for a customer: “how is my account doing?” and “what should I do about it?” — as data your UI can render directly, and as answers the payment agent gives in conversation.
  • GET /customers/{customer_id}/insights — a computed report: a snapshot of balances and obligations, observations about recent activity, and advisory suggestions. No LLM anywhere in this path — every number, date, and sentence is computed deterministically from the customer’s own objects.
  • The drafting conversation — ask the payment agent about the account in the same conversation that drafts payments, and it narrates the same deterministic data. See Asking about the account.
Beta — part of the agentic early-access surface. The report is read-only by construction: it cannot move money, create, or change anything.
POST /customers/{customer_id}/insights/chat has been removed. The standalone advisory chat is gone; its Q&A now happens inside the drafting conversation, which has the account in front of it. If you called it, see Asking about the account for the replacement.

The report

The report is a view, not a stored object — computed on demand from the customer’s scheduled payments, mandates, recipients, wallets, and balances. There is nothing to create, poll into existence, or clean up.
Three parts:
  • snapshot — typed facts for stat cards: per-wallet balances (aggregated over all the customer’s linked wallets), upcoming-payment totals per asset, open/active counts.
  • insights[] — observations: what is happening.
  • suggestions[] — advice: what the customer may want to do. Always advisory — acting on one is a separate, human-gated step through the normal payment flow.
Both arrays share one item schema: {kind, severity, message, detail, evidence}.

Rendering items

  • severity is a closed set: info | warn | critical. Sort and color by it.
  • kind is an open set — new kinds appear over time without a breaking change. Render an unrecognized kind generically from message + severity; never drop it.
  • message is a complete, human-readable sentence. A minimal UI can show messages alone and be correct.
  • detail carries the raw computed values behind the sentence, for custom rendering.
  • evidence[] contains typed references ({type, id}wallet, scheduled_payment, mandate, recipient; up to 10 per item) to the exact objects the item was computed from — deep-link each claim to the data behind it. evidence.type is open-set like kind.

The kind catalog

A mandate that is exactly on plan — filled by its own scheduled series — stays silent; headroom items fire only on breach or tightness.

Degradation, not errors

A deployment without a balance index simply omits balance-derived parts (snapshot balances, shortfall math); the rest of the report still computes. Missing data degrades the report — it never 500s.

Asking about the account

There is no separate chat endpoint. A customer asks about the account in the same conversation that drafts paymentsPOST /payment-agents/{payment_agent_id}/proposals, documented in the quickstart. “Pay Brightline 2,000 USDC” and “why did my payments to Brightline fail?” are the same call.
A question is answered in reply, and there is no proposals field at all — the key is omitted, not returned as an empty array, because nothing was drafted:
Branch on presence, not length: proposals is absent whenever the turn drafted nothing, so a client testing proposals.length === 0 will throw rather than take the no-op path. That absence is the safety property, and it is why the two surfaces merged. A question cannot become a payment by being phrased like one: the agent still cannot move money, and anything it does draft arrives as proposals your customer reviews and signs in the normal way.
Enabled per client. Account narration is an admission decision, not a deployment side effect — it is off by default even for clients already using agentic payments. Ask Dakota to enable it. With it off, the drafting conversation is unchanged: same tools, same behaviour, and account questions simply go unanswered.

Why merge them

Splitting them meant your application had to guess, per message, whether the customer was instructing or asking, and route to a different endpoint accordingly. That guess is made from the words alone, before anyone has looked at the account — and it is asymmetric: mistaking a question for an instruction is mild, while mistaking “pay Brightline” for a question silently drops a payment. The agent makes the same decision with the account actually in front of it, and does not have to choose one or the other — a turn can answer a question and draft, which is exactly what “pay MeatCo and tell me how much I’ve spent on them” asks for.

Where the numbers come from

The model never computes facts. It reads them from deterministic, server-computed, read-only tools: These read the customer’s whole account, not just the conversing agent’s slice of it — the same view GET /customers/{id}/insights already returns — and results say which view they are narrating. None of them can write, and none can be pointed at another customer: they are scoped to the agent’s customer by construction.

Scope and bounds

conversation_status reports how the boundary screen treated the turn: Account questions ride the drafting conversation, so they take its caps and budget rather than any chat-specific ones: 200 messages and 512 KB of text per request, 30 drafts/hour and 200/day per customer. See Limits.

Report or conversation?

Render the report — it is structured, deterministic, and cheap, and it needs no LLM. Use the conversation where a customer benefits from asking follow-ups (“why did my payments to Brightline fail?”) — its answers read the same data the report shows, so the two surfaces always agree.