Skip to main content
The Reporting API exports your Shippo account data as downloadable CSV or Parquet files. You create a run, poll until it finishes, then download the file. See the Quickstart for a runnable walkthrough, or Authentication for token setup.

Report types

A report type is a versioned export definition, such as invoice.v1. Fetch the catalog:
The response is { "items": [...] }. Each item has: To fetch a single type, call GET /v2/reporting/reports/{report_type}. An unknown key returns 404. While the window is still being determined, data_availability is { "status": "pending" }. Once it’s ready, it becomes { "status": "ready", "start": ..., "end": ..., "updated": ... } in UTC epoch seconds. The updated field records when those bounds were last checked. If you request a run outside the ready range, you get a 404 (data-unavailable).

Columns

Pass column name values in your run request to pick the columns you want. Omit columns to get the default set. Each report type allows its own set of columns, listed as available_columns.

Runs

Create a run with POST /v2/reporting/runs:
All timestamps are integer UTC epoch seconds, not ISO strings or milliseconds. There are no filters. You pick the report type, the date range, and the columns, and a run exports every row in that window.
Unknown fields in the request body are rejected with 422.
To list recent runs, call GET /v2/reporting/runs. You can pass limit (default 50, range 1 to 500). List responses never include a download URL, so fetch a single run to get one.

Lifecycle

A run moves through these states: Reporting API uses uppercase run statuses to match Shippo’s existing reports API lifecycle vocabulary.
Poll GET /v2/reporting/runs/{run_id} until status is SUCCEEDED or FAILED. A run that exceeds the processing limit ends as FAILED with run_timeout.
A run with status: FAILED returns HTTP 200 with status: FAILED, not an HTTP error. Check status (and error.code) before treating a run as successful.
A run with status: SUCCEEDED looks like this:

Download

The result.download field is either { "status": "available", "url": ..., "expires": ... } or { "status": "unavailable" }. When it’s unavailable, GET the run again to get a fresh URL.
The URL is time-limited. If it expires, fetch the run again for a new one.

Idempotency

You can pass an optional idempotency_key, a string of your choosing, 1 to 128 characters, to make a create call safe to retry. Without a key, every create makes a new run; there is no automatic dedup. Reuse a key only when you mean to retry the exact same request.

Errors

Reporting API errors use RFC 7807 application/problem+json, except authentication failures, which use 401 application/json with a detail field. Match problem responses on the trailing <code> segment of type. Runs with status: FAILED return 200 OK with status: FAILED and an error.code:

Quickstart

Run your first report end to end.

API reference

Browse every endpoint and schema.
Last modified on September 16, 2026