---
title: "Check an export"
method: GET
path: "/api/v1/exports/{id}"
tags: ["Exports"]
---

# Check an export

`GET /api/v1/exports/{id}`

## Request

- Base URL: `https://arcnautical.com`
- URL: `https://arcnautical.com/api/v1/exports/{id}`
- Auth: one of:
  - HTTP bearer
  - API key in header `X-ArcNautical-Key`
  - HTTP bearer
  - API key in header `X-ArcNautical-Key`
  - HTTP bearer
  - API key in header `X-ArcNautical-Key`

Poll until status is completed, then follow download_url. download_url is absent until there is something to download, so readiness never has to be inferred from a status string next to a URL that would fail.

Statuses: queued, running, completed, failed. A failed export carries the machine error under error.

Required scope: any one of vessel:screen, cargo:screen, logs:read, whichever governs the resource you name.

## Path parameters

- `id` string, uuid, required

## Response `200`

Successful response.

- Export
  - `id` string, uuid, required
  - `resource` 'screenings' | 'cargo_screenings' | 'access_log' | 'voyage_assessments', required: What to export. Each is governed by the same scope that governs reading it one record at a time: screenings by vessel:screen, cargo_screenings by cargo:screen, access_log by logs:read.
  - `format` 'csv' | 'jsonl', required
  - `status` 'queued' | 'running' | 'completed' | 'failed', required
  - `filters` object, required: The filters as applied, including the pinned created_before.
  - `estimated_row_count` integer, nullable: Rows matched when the export was accepted.
  - `row_count` integer, nullable: Rows actually written. Null until completed.
  - `byte_size` integer, nullable
  - `checksum_sha256` string, nullable: SHA-256 of the file body, hex.
  - `download_url` string: Present only when status is completed.
  - `error` ApiErrorEnvelope
    - `code` 'missing_idempotency_key' | 'invalid_idempotency_key' | 'invalid_json' | 'unauthorized' | 'invalid_api_key' | 'quota_exhausted' | 'insufficient_scope' | 'entitlement_inactive' | 'ip_not_allowed' | 'monitoring_unavailable_in_test' | 'simulation_unavailable_in_live' | 'not_found' | 'unsupported_api_version' | 'method_not_allowed' | 'unsupported_media_type' | 'idempotency_conflict' | 'idempotency_in_progress' | 'export_not_ready' | 'delivery_in_flight' | 'endpoint_disabled' | 'endpoint_deleted' | 'monitor_limit_exceeded' | 'vessel_monitor_limit_exceeded' | 'vessel_monitor_exists' | 'export_unavailable' | 'validation_failed' | 'route_not_found' | 'export_too_large' | 'webhook_url_blocked' | 'webhook_url_unresolvable' | 'rate_limit_exceeded' | 'concurrency_limit' | 'service_concurrency_limit' | 'export_concurrency_limit' | 'internal_error' | 'assessment_failed' | 'screening_failed' | 'export_failed' | 'export_row_count_grew' | 'api_paused' | 'assessment_timeout' | 'screening_timeout', required: Stable machine code. Branch on this, never on the message text, which we reword. Generated from the list the server throws from rather than restated here, because a hand-kept copy of a server-side vocabulary has drifted on us before. The HTTP status does NOT tell you whether to retry: 409 idempotency_in_progress resolves by waiting while 409 idempotency_conflict never resolves, and 500 export_row_count_grew fails identically on every retry. Retryability per code: - `missing_idempotency_key` (400) — not retryable. A POST arrived with no Idempotency-Key header. - `invalid_idempotency_key` (400) — not retryable. The Idempotency-Key was present but unusable (empty or over-long). - `invalid_json` (400) — not retryable. The body did not parse as JSON. - `unauthorized` (401) — not retryable. No credential was supplied. - `invalid_api_key` (401) — not retryable. The key is unknown, revoked, expired, or its prefix does not match the environment. - `quota_exhausted` (402) — not retryable. The allowance for this resource is spent: the month's (GET /api/v1/usage carries the reset date), or a one-time total (live screenings on an account opened from 2026-10-01, or a pilot), which does not reset. - `insufficient_scope` (403) — not retryable. The key does not hold the scope this endpoint requires. - `entitlement_inactive` (403) — not retryable. The account has no active entitlement. - `ip_not_allowed` (403) — not retryable. The key is IP-restricted and this source address is not on its list. - `monitoring_unavailable_in_test` (403) — not retryable. Vessel and corridor monitors are not available on a test key. - `simulation_unavailable_in_live` (403) — not retryable. Simulated monitor events are available only on a test key. A synthetic risk change on a live monitor would enter your compliance record as a real finding about a real vessel. - `not_found` (404) — not retryable. No such resource, or it is not yours. A malformed id answers this way too, deliberately. - `unsupported_api_version` (404) — not retryable. The path names an /api/vN this service does not publish. Answered by the edge, so it is the one code that carries no rate-limit headers. NEVER retry: our own guidance says an HTML body means a network layer answered and should be retried, and this exists so that advice is not applied to a permanent 404. - `method_not_allowed` (405) — not retryable. The path exists but not with this verb. The Allow header names the verbs that do work. - `unsupported_media_type` (415) — not retryable. Content-Type declared something other than application/json. Omitting the header is accepted; declaring the wrong one is not. - `idempotency_conflict` (409) — not retryable. This Idempotency-Key was already used with a different body. Never resolves — use a new key. - `idempotency_in_progress` (409) — RETRYABLE. The original request with this key is still running, and this retry waited for it (up to 30s) without it finishing. Retry with the same key: the next retry waits again and returns the original result the moment it lands, flagged X-ArcNautical-Idempotent-Joined: true. Carries Retry-After. - `export_not_ready` (409) — RETRYABLE. The export job has not finished. Poll it; carries Retry-After. - `delivery_in_flight` (409) — RETRYABLE. That webhook delivery is being attempted right now. - `endpoint_disabled` (409) — not retryable. The webhook endpoint is disabled. Re-enable it first. - `endpoint_deleted` (409) — not retryable. The webhook endpoint no longer exists. - `monitor_limit_exceeded` (409) — not retryable. Corridor monitor ceiling reached. Delete one first. - `vessel_monitor_limit_exceeded` (409) — not retryable. Vessel monitor ceiling reached. Delete one first. - `vessel_monitor_exists` (409) — not retryable. A monitor already watches this hull. - `export_unavailable` (410) — not retryable. The export file has aged out. The records behind it are unaffected — create a new one. - `validation_failed` (422) — not retryable. One or more fields are invalid; field_violations names each one. - `route_not_found` (422) — not retryable. Both ports are known but no sea route connects them. - `export_too_large` (422) — not retryable. The requested range exceeds the per-export row cap. Narrow the filters and export in parts. - `webhook_url_blocked` (422) — not retryable. The URL resolves to a private, loopback or link-local address. - `webhook_url_unresolvable` (422) — not retryable. The URL host does not resolve. - `rate_limit_exceeded` (429) — RETRYABLE. Over the per-key request rate. Shed RATE; back off to X-RateLimit-Reset. - `concurrency_limit` (429) — RETRYABLE. Over your own in-flight ceiling. Shed CONCURRENCY, or use the batch endpoint. Retry-After carries a live estimate, not a fixed number. - `service_concurrency_limit` (429) — RETRYABLE. The shared pool is full and your account is within its allowance. A graded screen QUEUES for that pool first and is served round-robin between accounts, so this means the queue itself ran out of time — you were not stuck behind one customer's batch. Reducing your fan-out will NOT help; retry unchanged after Retry-After. include_vetting: false skips this queue entirely, and /api/v1/screening-batches is not subject to it at all. - `export_concurrency_limit` (429) — RETRYABLE. Too many exports building at once. Wait for one to finish. - `internal_error` (500) — RETRYABLE. An unhandled failure. Retry with backoff; quote request_id if it persists. - `assessment_failed` (500) — RETRYABLE. Voyage scoring failed to produce a result. - `screening_failed` (500) — RETRYABLE. The screening engine failed to produce a verdict. No unit is charged. - `export_failed` (500) — RETRYABLE. The export job failed while building. - `export_row_count_grew` (500) — not retryable. The matching rows grew past the cap while the file was being written, so it was abandoned rather than shipped short. Narrow the filters — an identical retry fails identically. - `api_paused` (503) — RETRYABLE. The API is paused for a short while (an operator lever against abuse, rarely pulled). Nothing ran and nothing was charged. Retry the same request after Retry-After. - `assessment_timeout` (504) — RETRYABLE. Scoring exceeded its deadline. Retry; a warm route usually succeeds. - `screening_timeout` (504) — RETRYABLE. The screening exceeded its time budget (screeningComputeBudgetMs) and was abandoned before it could be stored. No unit is charged, and the Idempotency-Key is RELEASED — so retry with the SAME key; it is a clean attempt, not a replay. Deliberately raised below the socket timeout at the edge, so this arrives as JSON with a request_id rather than as a gateway 504 we never see.
    - `message` string, required
    - `request_id` string, required
    - `field_violations` FieldViolation[]
      - `field` string, required
      - `message` string, required
  - `download_count` integer
  - `downloaded_at` string, date-time, nullable
  - `created_at` string, date-time, required
  - `completed_at` string, date-time, nullable
  - `expires_at` string, date-time, required: When the FILE is deleted. The records it was built from are unaffected.

## Other responses

- `400`: Validation error. `code` is one of: - `missing_idempotency_key` — A POST arrived with no Idempotency-Key header. - `invalid_idempotency_key` — The Idempotency-Key was present but unusable (empty or over-long). - `invalid_json` — The body did not parse as JSON.
- `401`: Missing or invalid API key. `code` is one of: - `unauthorized` — No credential was supplied. - `invalid_api_key` — The key is unknown, revoked, expired, or its prefix does not match the environment.
- `402`: The allowance for this resource is used up: the month's, or a one-time total (live screenings on an account opened from 2026-10-01, or a pilot), which does not reset (then there is no reset instant and no Retry-After). The refused request is NOT metered. message states used/limit and the reset instant when there is one; a replay under an Idempotency-Key already answered is still free and is not metered, reads are never metered, and a test-environment key has its own allowance. `code` is one of: - `quota_exhausted` — The allowance for this resource is spent: the month's (GET /api/v1/usage carries the reset date), or a one-time total (live screenings on an account opened from 2026-10-01, or a pilot), which does not reset.
- `403`: The key is not entitled to this environment or scope. `code` is one of: - `insufficient_scope` — The key does not hold the scope this endpoint requires. - `entitlement_inactive` — The account has no active entitlement. - `ip_not_allowed` — The key is IP-restricted and this source address is not on its list. - `monitoring_unavailable_in_test` — Vessel and corridor monitors are not available on a test key. - `simulation_unavailable_in_live` — Simulated monitor events are available only on a test key. A synthetic risk change on a live monitor would enter your compliance record as a real finding about a real vessel.
- `404`: Resource not found. `code` is one of: - `not_found` — No such resource, or it is not yours. A malformed id answers this way too, deliberately. - `unsupported_api_version` — The path names an /api/vN this service does not publish. Answered by the edge, so it is the one code that carries no rate-limit headers. NEVER retry: our own guidance says an HTML body means a network layer answered and should be retried, and this exists so that advice is not applied to a permanent 404.
- `405`: The path exists but not with this method. The Allow header names the methods that do. `code` is one of: - `method_not_allowed` — The path exists but not with this verb. The Allow header names the verbs that do work.
- `409`: Idempotency conflict. `code` is one of: - `idempotency_conflict` — This Idempotency-Key was already used with a different body. Never resolves — use a new key. - `idempotency_in_progress` (retryable) — The original request with this key is still running, and this retry waited for it (up to 30s) without it finishing. Retry with the same key: the next retry waits again and returns the original result the moment it lands, flagged X-ArcNautical-Idempotent-Joined: true. Carries Retry-After. - `export_not_ready` (retryable) — The export job has not finished. Poll it; carries Retry-After. - `delivery_in_flight` (retryable) — That webhook delivery is being attempted right now. - `endpoint_disabled` — The webhook endpoint is disabled. Re-enable it first. - `endpoint_deleted` — The webhook endpoint no longer exists. - `monitor_limit_exceeded` — Corridor monitor ceiling reached. Delete one first. - `vessel_monitor_limit_exceeded` — Vessel monitor ceiling reached. Delete one first. - `vessel_monitor_exists` — A monitor already watches this hull.
- `415`: Content-Type describes a body that is not JSON (form-encoded, multipart, XML). application/json, text/plain and an absent header are all accepted. `code` is one of: - `unsupported_media_type` — Content-Type declared something other than application/json. Omitting the header is accepted; declaring the wrong one is not.
- `422`: Request or route validation failed. Also returned for a body field this endpoint does not read — field_violations names it and lists the accepted keys. `code` is one of: - `validation_failed` — One or more fields are invalid; field_violations names each one. - `route_not_found` — Both ports are known but no sea route connects them. - `export_too_large` — The requested range exceeds the per-export row cap. Narrow the filters and export in parts. - `webhook_url_blocked` — The URL resolves to a private, loopback or link-local address. - `webhook_url_unresolvable` — The URL host does not resolve.
- `429`: Rate limit exceeded. `code` is one of: - `rate_limit_exceeded` (retryable) — Over the per-key request rate. Shed RATE; back off to X-RateLimit-Reset. - `concurrency_limit` (retryable) — Over your own in-flight ceiling. Shed CONCURRENCY, or use the batch endpoint. Retry-After carries a live estimate, not a fixed number. - `service_concurrency_limit` (retryable) — The shared pool is full and your account is within its allowance. A graded screen QUEUES for that pool first and is served round-robin between accounts, so this means the queue itself ran out of time — you were not stuck behind one customer's batch. Reducing your fan-out will NOT help; retry unchanged after Retry-After. include_vetting: false skips this queue entirely, and /api/v1/screening-batches is not subject to it at all. - `export_concurrency_limit` (retryable) — Too many exports building at once. Wait for one to finish.
- `500`: Internal or upstream error. `code` is one of: - `internal_error` (retryable) — An unhandled failure. Retry with backoff; quote request_id if it persists. - `assessment_failed` (retryable) — Voyage scoring failed to produce a result. - `screening_failed` (retryable) — The screening engine failed to produce a verdict. No unit is charged. - `export_failed` (retryable) — The export job failed while building. - `export_row_count_grew` — The matching rows grew past the cap while the file was being written, so it was abandoned rather than shipped short. Narrow the filters — an identical retry fails identically.
- `503`: Service temporarily unavailable. `code` is one of: - `api_paused` (retryable) — The API is paused for a short while (an operator lever against abuse, rarely pulled). Nothing ran and nothing was charged. Retry the same request after Retry-After.
- `504`: The request exceeded its server-side time budget and was abandoned. Raised by us, below the socket timeout at the edge, so it arrives as JSON with a request_id. `code` is one of: - `assessment_timeout` (retryable) — Scoring exceeded its deadline. Retry; a warm route usually succeeds. - `screening_timeout` (retryable) — The screening exceeded its time budget (screeningComputeBudgetMs) and was abandoned before it could be stored. No unit is charged, and the Idempotency-Key is RELEASED — so retry with the SAME key; it is a clean attempt, not a replay. Deliberately raised below the socket timeout at the edge, so this arrives as JSON with a request_id rather than as a gateway 504 we never see.

---

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