Skip to main content
Use structured reads when your app or agent needs individual financial records for its own storage and analysis. Results preserve provider IDs and account attribution, without passing the records through a language model.
This guide describes the financial-data release. It requires a compatible SDK or MCP build and an API environment with structured reads enabled. Availability on the hosted endpoint is controlled separately from this documentation.

Request permission

Configure your server’s PaymanConnect instance with scopes: ["financial_data:read"], then use the normal authorization and callback flow. The customer’s consent screen shows the data permission. Use payman.forUser(customerId).startAuthorization() to request new consent for an existing customer. The default scope remains interact. Request both scopes only when your app needs money tasks and data reads. Changing client configuration does not upgrade an existing grant: the customer must consent again on the existing primary connection, or revoke and reconnect. Adding another provider cannot broaden permissions. Device-code pairing currently supports only interact; use the browser authorization flow for data access.

Read through the SDK

After authorization, discover the connections the customer has shared with your app, then use exact account IDs from that connection:
The example assumes an authorized payman instance and IDs selected from the returned lists. Do not substitute account labels, last-four digits, or an ID from another connection. Account balances may be cached; a missing available balance means unknown, not zero. Use user.data.read({ connectionId, read: { operation, arguments } }) for any operation. Snapshots depend on each provider’s configured read tools. A connection’s transactionSync describes implementation support; it does not prove that its runtime catalog is published or that the bank is healthy. Investments, liabilities, and statement PDFs are outside this release.

Record why a read was requested

Include optional intent whenever the caller’s purpose is known. Hosted and local MCP advertise it by default and ask the bot to include the known purpose without asking the user just to populate metadata. Omitting it or sending null keeps existing integrations working. Payman does not invent a reason when none is supplied. String values are trimmed and must not be blank. Keep the purpose concise; do not include credentials or the full conversation. Intent is descriptive context and does not change permissions, tool arguments, or trigger a model call. The SDK accepts intent on data.start() / data.read() requests, or in the options passed to those methods and accounts(), transactions(), and syncTransactions(). An explicit request value overrides the options value; intent: null explicitly omits shared context. Keep the same intent when retrying the same requestId. Submission responses and JSON results always include intent (or null). It is stored encrypted with the read request and expires with the job after 24 hours. Save runId, createdAt, intent, and the final status in your own records for longer retention. CSV exports contain only financial rows; retain the JSON metadata separately. On compatible runtimes, each provider-page attempt also creates a Studio execution trace under the read job’s session. It shows purpose, connection/account/date scope, tool name, result counts, timing, and outcome with zero model calls. Response rows and cursor contents are excluded. Each saved page includes executionId and sessionId for correlation. In Studio, open the connection’s conversations and the read’s trace; failed attempts are recorded there too. These runtime traces follow existing execution retention and survive the Cloud job’s 24-hour expiry. The agent’s trace storage setting still applies: DETAILED captures this context by default, METRICS retains timing only, and NONE disables the trace blob. Older runtimes may omit the page trace IDs until upgraded.

Keep Plaid transactions in sync

Start without a cursor. On subsequent imports, supply the checkpoint from the previous committed batch:
Key records by (connectionId, accountId, id). Keep one checkpoint per grant, connection, and account. Serialize imports for that stream, or compare and swap the stored checkpoint when committing. A new grant or replaced bank connection requires a full sync. Reuse the same request ID for an identical submission retry; give each new import a fresh request ID. Posted records can replace pending records under a different ID. Use pendingTransactionId when supplied, and apply removals. Plaid’s exact amountDecimal is an absolute amount in major currency units; type supplies the credit/debit direction. Prefer this over rounded amountCents for precision. Use the source date/datetime fields; legacy createdAt may be synthesized from a date. These extra source fields are not certified across every provider. The server stages the whole sync batch before returning it and restarts pagination if the source changes during the read. Incomplete sync jobs expose neither staged pages nor a checkpoint. Apply every returned page and persist the final checkpoint in one database transaction.

Use MCP

Request OAuth scope financial_data:read and reauthorize your hosted MCP connection. Read-only grants expose payman_connection_status, payman_read_data, and payman_read_result, with money and approval tools omitted. The API feature flag must also be enabled.
  1. Call payman_connection_status to discover a deploymentId.
  2. Call payman_read_data with list_accounts to discover exact account IDs.
  3. Poll payman_read_result with its runId.
  4. Submit a transaction read using the same deployment and chosen account.
Tools return structuredContent as well as text. payman_read_result returns one saved page: data.data contains its records and data.fetchedAt its retrieval time. Follow nextPage by passing page on the next call. Retrieve every saved page before committing a sync checkpoint, even when the job is already completed. For the local stdio package, set PAYMAN_SCOPES=financial_data:read, restart it, and reconnect through payman_connect. Local discovery uses payman_data_connections and local read input uses connectionId instead of deploymentId. These identify the same connection. The SDK uses connectionId too. See MCP setup for building and configuring the local package. If a hosted client always requests only interact and does not allow scope selection, use the configurable local MCP build. Asking for raw data in chat does not change an OAuth grant’s permissions.

Jobs, limits, and recovery

For manual polling, call data.start(request), then data.result(runId) or data.wait(runId). The HTTP equivalents are: HTTP read input uses deploymentId. Confidential clients send x-paygent-connect-app-key and x-paygent-connect-grant. Public OAuth clients send their token in x-paygent-connect-grant without an app key. The hosted /mcp endpoint uses Authorization: Bearer instead. See the API reference for the request schemas. A completed snapshot can also be requested with ?format=csv; check x-payman-read-state and x-payman-rows-complete before using it. Change feeds require JSON. data.read() and the convenience methods throw FinancialDataError when a job is incomplete. Inspect error.result; do not treat a partial export as complete. read_timeout and read_aborted carry runId so you can resume polling without submitting a new job. read_submission_unknown carries requestId; retry the same input with that ID. These data methods throw, unlike money-task run()’s result union. If a sync batch exceeds the bounds, do not save a partial cursor. Try a larger page size up to 500 through data.read(). If it still exceeds the limit, the integration needs a larger export path before that batch can be committed. rowsComplete=true means the requested provider pagination finished. It does not certify that the bank supplied all historical records. historyComplete remains false; sourceUpdatedAt remains null until independently verified. fetchedAt is retrieval time, not the bank’s refresh time. Reconcile against statements before relying on an import as complete books.