Fetch a day's bank statement and import it
bank_statement.fetch_and_import
Asks the bank that mirrors the account for one finished day's statement, as bank_account.read does in statement mode, and imports the document it answers in the same operation, as bank_statement.import does: camt.053 or MT940 when the bank sends one, else the bank's JSON statement. The answer is stored as a receipt either way. A refused read or a day with no booked line imports nothing. A person's fetch books a pool's bank charges as the import does; the boundary worker's scheduled daily fetch, bank_statement.daily_fetch, posts nothing and leaves a pool's statement that carries charges for a person to import. The same document fetched again returns the statement imported before. Callers: the account owner's CLI login, or an agent token with products:write whose grant spans every Product (`hyperscale agent setup --all-products`), or a personal access token with finance:write. A grant on some Products is refused: this reaches all of them.
POST /v1/bank-accounts/{accountId}/statement-import
Principal user_session. Idempotency required. Environment either.
Input
| Field | In | Type | Description |
|---|---|---|---|
accountId required | path | string | Hyperscale account ID |
X-Hyperscale-Environment | header | sandbox | live | |
Idempotency-Key required | header | string | |
X-Hyperscale-Rehearsal | header | "true" | `true` runs the request through admission and execution, keeps nothing, and answers OperationRehearsal with 200 in place of the operation's own output. Needs a signed-in caller. Identity operations, such as sign-in, sessions, team members and agent grants, refuse it with invalid_request. |
tenantId required | body | string | Organization tenant ID |
date required | body | string | The finished bank day whose statement to fetch. |
Output
| Field | Type | Description |
|---|---|---|
accountId required | string | Hyperscale account ID |
date required | string | |
adapter required | string | The bank adapter that mirrors the account. |
outcome required | confirmed | rejected | Rejected when the bank refused the statement read. |
providerCode required | string | null | |
reasonCode required | string | null | |
externalConfirmationId required | string | The receipt that stores the bank's answer. |
format required | camt053 | csv | json | mt940 | mt942 | null | The format of the bank's document; null when the bank refused or the day booked no line, and set on a pool statement the daily fetch left for a person, which it did not import. |
statement required | object | null | The import's answer, as bank_statement.import returns it; null when the bank refused, when the day booked no line, or when the daily fetch left a pool's statement with bank charges for a person. |
chargesBooked required | boolean | False on the scheduled daily fetch, which posts nothing. |
deferredChargeLines required | integer | The bank-charge lines on a pool's statement that the scheduled daily fetch left for a person: it stores no such statement, so bank_statement.fetch_and_import or bank_statement.import of the same day books the charges. 0 otherwise. |
Request sample
Only a signed-in person may call this: the CLI after hyperscale auth login, or curl with a personal access token (hyperscale_pat_...) with finance:write or an agent token with products:write. The agent's grant must span every Product the call reads. A Product key cannot, so the SDK, which signs in with a Product key or a customer session, has no sample for it.
curl
curl --request POST 'https://hyperscale0.ai/v1/bank-accounts/acct_sandbox_example0001/statement-import' \
--header "Authorization: Bearer $HYPERSCALE_TOKEN" \
--header 'X-Hyperscale-Environment: sandbox' \
--header "Idempotency-Key: $(uuidgen)" \
--header 'Content-Type: application/json' \
--data-raw '{"tenantId":"ten_sandbox_example0001","date":"2026-01-01"}'CLI
hyperscale api call bank_statement.fetch_and_import \
--input '{"accountId":"acct_sandbox_example0001","tenantId":"ten_sandbox_example0001","date":"2026-01-01"}'Errors
| Code | HTTP | Cause |
|---|---|---|
agent_cap_exceeded | 202 | A capped agent's call would move more than its grant allows per operation, per rolling day or per rolling 30 days. |
agent_reason_required | 400 | An agent sent a change without saying why, or the reason is shorter than 8 or longer than 280 characters. |
agent_result_already_delivered | 409 | A caller already claimed this approval's one-time result. |
approval_rejected | 403 | A person rejected the call or returned it to the maker, so it never runs. |
approval_required | 202 | The call waits for decisions: an agent's call over its grant waits on its delegator, and a program action under `requires approval` waits on distinct people other than the maker. |
csrf_token_invalid | 403 | A browser session mutation did not carry a current Hyperscale CSRF token. |
environment_mismatch | 403 | The session was issued for sandbox or live and the request targets the other environment. |
idempotency_conflict | 409 | The request reused an Idempotency-Key for a different logical mutation. |
idempotency_required | 400 | The operation is a mutation and Hyperscale requires a replay key before executing it. |
internal_error | 500 | Hyperscale hit an unexpected server-side condition and hid internal implementation details from this audience. |
invalid_request | 400 | The request does not match the API reference. |
method_not_allowed | 405 | The route exists, but not for the request's HTTP method. |
missing_required_permission | 403 | The signed-in member's current role does not grant the permission required for this operation. |
missing_required_scope | 403 | The credential is valid but does not grant one or more operation scopes. |
not_found | 404 | No Hyperscale route matched the requested path and method. |
oauth_client_not_admitted | 403 | The bearer is an OAuth client token, and this operation does not admit the oauth2_client principal. |
product_access_suspended | 403 | The Product is disabled or closed, so its credentials are suspended in every environment. |
product_activation_required | 403 | The live Product or required live capability is not active yet. |
rate_limited | 429 | The credential sent more than its limit in the current 60-second window: 600 requests per API key or session, 1,200 per IP address. Every response carries `x-ratelimit-limit`, `x-ratelimit-remaining` and `x-ratelimit-reset` (Unix seconds). |
request_body_too_large | 413 | The JSON request body exceeded Hyperscale's accepted payload size. |
resource_not_found | 404 | The requested resource does not exist in the credential's visible scope. |
state_conflict | 409 | The operation conflicts with the current durable state of the resource. |
state_constraint_failed | 422 | The request is syntactically valid but violates a business-state constraint. |
tenant_mismatch | 403 | The request mixed tenant-owned identifiers across tenant boundaries. |
tenant_not_found | 404 | The credential resolved to a tenant Hyperscale cannot find. |
unauthorized | 403 | The request did not include a valid Hyperscale bearer credential for this environment. |
account_not_found | 404 | No account with the id this request names exists in the caller's tenant and environment. The id comes from `accountId`, `destinationAccountId` or `entityAccountId`, depending on the operation. |
agent_token_expired | 401 | The agent token is real, but its grant ended. A grant lasts 30 days, or 7 days unused. `details.expiresAt` holds the date in ISO 8601 and `details.agentName` names the agent. |
agent_token_replaced | 401 | The account owner ran `hyperscale agent setup` again for this agent, which replaced this token with a newer one. `details.agentName` names the agent and `details.replacedAt` holds the date. |
bank_statement_invalid | 422 | The document is over 512 KiB of UTF-8, or is not a camt.053 statement with one Stmt and booked entries, or not a CSV whose header names date, amount and currency with one well-formed row per line. Nothing was stored. |
company_period_closed | 409 | The company already closed this period in this environment. A period closes once and the close never changes. In sandbox a money operation dated by its Product clock inside a closed month refuses too, so the close's VAT return and journal stay whole; `details.period` names the month. |
cross_tenant_transfer_forbidden | 409 | An account on this transfer belongs to another tenant, or it has no tenant and is not a platform account. `details.accountId` names it. No intent or ledger effect was created. |
currency_mismatch | 400 | The currency on the request does not match the settlement currency of the account or transfer it targets. Hyperscale never converts between currencies, so the two must be identical. |
device_login_expired | 401 | The bearer is the account owner's own device login from `hyperscale auth login`, not an agent token. Its access token lasts an hour and the CLI refreshes it; the login itself ends after 30 days, or 7 days unused. `details.expiresAt` holds when it ended in ISO 8601. |
external_confirmation_conflict | 409 | This tenant and environment already recorded the provider reference in `details.provider` and `details.providerReference` against a different operation, resource or body. A provider observation that does not match its boundary instruction, or an instruction that changed during recovery, also raises this code. |
instrument_instance_not_found | 404 | No record of this instrument matches the `instanceId` in this Product, company and environment. `details.instrumentId` and `details.instrumentInstanceId` name what was looked up. |
insufficient_balance | 409 | The source (debit) account's available balance is below the transfer amount, so the ledger refused the transfer. No money moved. The transfer was not created and its charge/transfer rows are recorded as failed. |
invalid_credentials | 401 | Hyperscale could not accept the account or credential request. Signup, login, and bearer authentication use one 401 for every case they reject, so the response exposes no credential-specific reason or registered-email verdict. The single exception is a key that is real but homed in the other environment: because the presented secret already matched a stored key, the message names the mismatch instead of leaving a working credential looking unknown. A bearer that matched nothing gets text that fits its prefix (an agent token, a refresh token, a personal access token, a session or no Hyperscale token at all), which says only what the caller sent, never whether a credential like it exists. |
ledger_transfer_rejected | 409 | The ledger refused the transfer for a reason other than insufficient balance. No money moved. `details` carries `transferId`, the debit-side `accountId`, `amount` and `currency`. The ledger's own reason stays in the server log. |
ledger_unavailable | 503 | The ledger could not be reached, did not answer in time, or returned incomplete evidence for the accounts this request reads. `details.reason` is `request_timeout` when the call timed out. |
operation_not_finalized | 409 | The operation in `details.operationId` has started but has no final receipt. It is still running, or its outcome is unknown after a failure past the point where it may have committed. `details.error` carries the underlying failure when there is one. |
provider_egress_failed | 502 | The call to the bank or provider failed in transit, or the bank has no adapter or no final answer for the read. Nothing was imported, and a money hold stays held until the same key runs again. |
session_expired | 401 | The session behind this request has ended. A console session ends 30 days after sign-in, or after 12 hours with no request. An admin or customer session ends 24 hours after sign-in, or after 15 minutes with no request. A personal access token ends at the `expiresAt` set when it was created. |
session_required | 401 | This operation needs a person signed in through the browser or the `hyperscale` CLI. A Product API key cannot call it. The request carried no session, or its token matched no live session. |
session_revoked | 401 | The session or personal access token behind this request was ended before its expiry. Sign-out, `user.session.revoke`, a password reset, a role change, removal from the team, user suspension and `personal_access_token.revoke` all end sessions. |
tenant_status_forbidden | 409 | The company is suspended or closed, so every credential bound to it is refused, reads included. `details.tenantId` names the company. |