---
title: "The state of one export job, and the SHA-256 of its file once it is produced."
method: GET
path: "/api/v1/finance/exports/status"
tags: ["read"]
---

# The state of one export job, and the SHA-256 of its file once it is produced.

`GET /api/v1/finance/exports/status`

## Request

- Base URL: `https://app.magistry.io`
- URL: `https://app.magistry.io/api/v1/finance/exports/status`
- Auth: one of:
  - HTTP bearer
  - OAuth 2 (authorization code, authorization URL `https://app.magistry.io/api/oauth/authorize`, token URL `https://app.magistry.io/api/oauth/token`, scopes: `finance:read`)

`status` is `queued`, `running`, `succeeded` or `failed`. A failed job carries `failure.code` (a refusal by the auditfile codec names the accounts in `failure.detail.subjects` and what to add in `failure.detail.hint`); a job that could not finish in time is `failed` with `timed_out`. A succeeded job carries `file` (name, bytes, `sha256`, `complete`, and the choices the writer made that the books do not state) and `download_url`. Only the app that started a job sees it, and only while it still holds the entity.

The GET form of `finance_export_status`: the same arguments as query parameters.

## Query parameters

- `export_id` string, uuid, required: The `id` POST /api/v1/finance/exports returned.

## Response `200`

Result

- object
  - `ok` boolean, required
  - `result` unknown, required

## Other responses

- `400`: `invalid_request` — The request is malformed or an argument is unusable. The message names which. `invalid_body` — The body is not a JSON object. `invalid_expiry` — An approval request must end: `expires_at` lies at least 5 minutes and at most 7 days after it is filed. A request with no decision by then closes as expired, which means not approved. `invalid_rule` — The rule could not bind as written: a fact or action outside the vocabulary, an operator that cannot compare that fact, or a limit with no bound. Nothing was saved.
- `401`: `unauthorized` — No credential was presented, or the one presented is not valid. This deliberately does not say whether it was unknown or forged: a 401 that tells those apart is an oracle for guessing tokens. A credential that VERIFIED and is refused answers with its own code (expired, grant_revoked, app_disabled, address_not_allowed). `expired` — The credential verified and its expiry has passed. `grant_revoked` — The OAuth token verified, and the merchant revoked this connection after it was issued. `app_disabled` — The OAuth token verified, and Magistry has disabled this application for every merchant. No token of the application is admitted and none is issued. `address_not_allowed` — The credential verified and carries an IP allowlist that this request did not come from. `credential_rejected` — Diagnose could not resolve the credential at all. `no_credential` — Diagnose was called with no Authorization header, so there is nothing to report on. `invalid_client` — The client authentication on this request did not verify.
- `403`: `forbidden` — The credential is valid and does not hold a scope this tool requires. `insufficient_scope` — As `forbidden`, and the body names `required_scopes`. A webhook subscription needs both `automation:write` to configure the store and the read scope for every type it filters — a webhook is a read. `entity_not_granted` — The credential holds a finance scope, and the entity's owner has not given this app those books (or has taken them back). A finance scope says what an app may do; the owner's grant says which entities. A natural person's books need the person's own explicit delegate grant.
- `404`: `not_found` — No tool of that name is exposed to this credential. Note that a tool hidden by a missing scope answers `forbidden`, not this — the two are told apart deliberately.
- `409`: `idempotency_conflict` — This idempotency key was already used with DIFFERENT arguments. Replaying it would be a second, different write under a key that promises one. `idempotency_in_flight` — A request with this key is still running. This is not an error — it is "ask again", and the response carries `Retry-After`. `no_policy` — The app has no grant for this field on this store. Owning a field is a separate, larger grant than a scope: the reconciler pushes what the owner declares, and nobody else may touch the field meanwhile. `held_by_other` — Another owner holds this field, named in `held_by`. A field has at most one owner, enforced by a unique index, and an app never takes a field over from a live holder. `raced` — Another owner took this field in the same instant as this declaration. The database let exactly one of the two through. `merchant_kept` — The merchant kept an outside change to this field. Once kept, the database refuses every new declaration on it unless a store rule allows declaring it again. `too_many_pending` — This app already has the maximum number of approval requests pending on this store (the body carries `pending` and `limit`). The bound keeps one app from burying the merchant's screen. `already_closed` — The approval request was decided, expired or withdrawn before this call; `status` says which. A closed request never reopens. `store_unavailable` — The store is not accepting approval requests because Magistry is not installed on it. `too_many_rules` — The store already holds the maximum number of rules. `in_flight` — The declaration is being written to the platform at this moment, so it cannot be reverted underneath that write. `overwritten_externally` — Someone other than this app changed the field on the platform after the app's value was applied, and the merchant has not yet decided whether that change stays. A revert now would overwrite it, so nothing was reverted. `finance_proposal_refused` — The books refused the proposal in their current state: the entity's owner has not switched app proposals on (Books → Assistant), or the period it would land in is closed. Nothing was recorded and nothing was posted. `reason` names which. `export_not_ready` — The export job has not produced its file (yet): `status` in the body says whether it is still `queued`/`running` or `failed`, with the failure's own code.
- `410`: `finance_cursor_gone` — The change-feed cursor is older than the feed keeps (guarantees.finance_change_feed_retention_days in /api/v1/changelog.json) and events after it have been removed. The body carries `oldest_cursor`. `export_expired` — The export's file was downloadable until `expires_at` and is no longer kept.
- `413`: `payload_too_large` — The body exceeds the endpoint’s size bound.
- `429`: `rate_limited` — This credential exceeded its per-minute limit. The body carries the limit and the count, and the response carries `Retry-After` and the `RateLimit-*` headers.
- `500`: `simulation_unverified` — The simulation could not prove that its transaction was aborted, so no verdict is given: an answer from a run that may have kept something would read as a clean one. Reported on our side. `server_error` — Something on our side failed. The request may or may not have taken effect.
- `502`: `sandbox_failed` — Creating or seeding the sandbox failed. Provisioning is one transaction, so nothing was created and the key shown to nobody was never stored.
- `503`: `idempotency_unavailable` — The idempotency claim could not be taken, so the write was NOT attempted. This fails closed on purpose: running an unguarded write because the guard was unreadable is how a customer gets refunded twice. `approvals_unavailable` — Approval requests are not enabled on this server yet. Nothing was written. `receipts_unavailable` — Receipts are not enabled on this server yet. Nothing was exported. `policies_unavailable` — Store rules are not enabled on this server yet. Nothing was read or written. `sandbox_unavailable` — Developer sandboxes are not open: the database fence that keeps a sandbox key on demo data is not in place, or the provisioning worker is not configured. Nothing was created. `unavailable` — A read could not be served just now. Nothing was written or exported. `overwrites_unreadable` — We could not confirm that nobody else has changed this field since it was applied, and a revert that cannot check could overwrite a merchant's change. Nothing was reverted. `rls_scoped_execution_unavailable` — This deployment is not currently running the row-level-scoped execution mode the headless surface requires, so it refuses rather than executing with wider reach than the grant. `finance_grants_unavailable` — The entities this app may read could not be established for this request, so nothing was read — an unreadable grant is never treated as a wider one, nor as "no entities". `finance_unavailable` — The books could not be read or a figure could not be computed from them just now, so nothing was returned — never a partial list or a zero that would read as the ledger. `export_unavailable` — The export job could not be started, read or served just now — including a stored file whose bytes do not match the SHA-256 the job recorded, which is never sent. Nothing was started or sent. `corpus_unavailable` — The corpus this endpoint reads could not be loaded.

---

[API](https://skmtc.dev/magistry/apis/magistry-api.md) · [All operations](https://skmtc.dev/magistry/apis/magistry-api/llms.txt) · [OpenAPI document](https://skmtc.dev/magistry/apis/magistry-api/revisions/13dae20d49cb?raw)
