Retry a statement extraction
POST/api/v1/bank_statements/:id/retry
Re-runs the extraction on a file whose first attempt did not finish. Read retryable on the statement before calling: the affordance and this endpoint read the same rule. The 202 returns the statement reset to pending, with the previous error cleared.
This queues the same external OCR flow the upload does - the file is made available to Mistral AI again. See the upload operation for what that involves; a retry is a second reading, not a local re-parse of the first.
Request
Responses
- 202
- 401
- 403
- 404
- 409
- 422
The extraction was re-enqueued. The statement is back to pending.
The request carries no bearer token, or one that is invalid or expired. doorkeeper_authorize! is the first gate of the chain, so this is answered before the workspace, the company, the feature flag and the statement are ever resolved - and before any Idempotency-Key is claimed.
The token may not perform this call, and three gates of the shared chain answer it identically: the OAuth SCOPE derived from the HTTP verb (this one needs write), the workspace GRANT the application holds, and the bank_reconciliation FEATURE FLAG. The action's own Pundit check is a fourth. All four render the same body, so message is what distinguishes them; nothing was performed in any case. The example below is refused on the scope.
No statement with this id is reachable by the token's grants. One belonging to another workspace answers the same way, so the response cannot be used to probe for one.
This Idempotency-Key is claimed and its outcome is not replayable - idempotency_request_in_progress. Nothing was enqueued by THIS call. That is USUALLY a first call still running, but it is also what you get when a first call DID enqueue the extraction and then failed while rendering its response - so it does not mean the retry never happened, and the two are not distinguishable from the outside today. Do not retry in a loop: read the statement with GET /bank_statements/{id} and let its state tell you whether an extraction is under way (processing) or still owed (pending). The key frees itself 24 hours after first receipt. A retry carries no body, so its fingerprint can never differ from the first call's - idempotency_key_reuse is unreachable here, and a completed first call replays its stored 202 rather than conflicting.
Either the statement is in a state that forbids a retry - it is archived, or the extraction already completed, and statement_not_reviewable names the state, so the remedy is to read the statement rather than to call again - or the Idempotency-Key header is missing or outside the accepted 1-255 characters, which is validation_failed with details.idempotency_key. The first refusal is about the statement and carries no details; the second is about the request and always does, so details is what tells them apart. Nothing was enqueued in either case.
A THIRD refusal reports the platform rather than your request: operation_failed, with no details, means the extraction could not be queued. The statement has been reset and is back to pending, so nothing is being read yet and this same call is the remedy - retry it. It is deliberately not statement_not_reviewable: the statement's state is fine, so waiting for it to change would never end. operation_failed is also the answer when the company has AI extraction turned off, which retryable already reports as false: the statement is left exactly as it was and nothing was queued, so turn the setting on before calling again.