Z Zise Developers 简体中文

Get an export task's status (poll here)

GET /v1/reports/{id} scope: merchant:read
Merchant account

Poll here until status: ready. This call also advances the queue once, only when work is available. A sweep runs every 5 minutes, so tasks created without polling are also completed, just more slowly.

⚠ Advancement runs in the background and does not make this request wait for the whole report to finish, which would reintroduce the CPU limit that asynchronous tasks avoid. The response therefore contains the current state; poll again afterward.

Five status values: queued · building · ready · failed · expired. ⚠ Display unknown values unchanged; do not use a default fallback.

Path Parameters

FieldTypeRequiredDescription
id string Required Task ID; accepts rep_<uuid> or a bare <uuid>.

Response

200OK
{
  "id": "rep_4c8a10d2-91f7-4a3e-b0c6-52d8e7f19b34",
  "kind": "statements",
  "status": "ready",
  "rows": 1842,
  "bytes": 214093,
  "error": "",
  "download_url": "https://api.zinfra.vip/v1/reports/rep_4c8a10d2-91f7-4a3e-b0c6-52d8e7f19b34/content",
  "expires_at": "2026-08-20T05:00:07.220Z",
  "created_at": "2026-08-13T05:00:00.000Z",
  "updated_at": "2026-08-13T05:00:07.220Z"
}
403insufficient_scope: missing merchant:read.
404resource_not_found, including tasks belonging to another merchant, with the same response.

Additional Details

download_url is not an unauthenticated direct link

  • It is non-null only when status: ready.
  • It points to GET /v1/reports/{id}/content; **downloading still requires x-auth-token**, along with all other Key restrictions, including the IP allowlist.

We deliberately do not issue a permanent signed URL: a leaked link would remain readable indefinitely, while the export contains all your business figures.

expires_at: files remain available for 7 days after ready; then the object is deleted and status becomes expired. Business data should not remain in object storage indefinitely. Create another export after expiry.

The path id accepts both prefixed and unprefixed rep_ IDs; passing back the ID we returned is natural. Nonexistent tasks and tasks belonging to another merchant receive the same response; distinguishing them would enable cross-merchant ID probing.

Request
curl -X GET 'https://api.zinfra.vip/v1/reports/{id}' \
  -H 'x-auth-token: Bearer $TOKEN'
const res = await fetch("https://api.zinfra.vip/v1/reports/{id}", {
  method: "GET",
  headers: {
    "x-auth-token": "Bearer $TOKEN",
  },
});
// Keep monetary amounts as strings, never numbers.
const data = await res.json();
import requests

res = requests.get(
    "https://api.zinfra.vip/v1/reports/{id}",
    headers={
        "x-auth-token": "Bearer $TOKEN",
    },
)
# Use Decimal(str(...)) for amounts, not float.
data = res.json()
req, _ := http.NewRequest("GET", "https://api.zinfra.vip/v1/reports/{id}",
    nil)
req.Header.Set("x-auth-token", "Bearer $TOKEN")
res, err := http.DefaultClient.Do(req)
// Decode amount fields as string, not float64.
HttpRequest req = HttpRequest.newBuilder()
    .uri(URI.create("https://api.zinfra.vip/v1/reports/{id}"))
    .header("x-auth-token", "Bearer $TOKEN")
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
// Use String / BigDecimal for amounts, not double.
$ch = curl_init('https://api.zinfra.vip/v1/reports/{id}');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    'x-auth-token: Bearer $TOKEN',
  ],
]);
$res = curl_exec($ch);
// Use bcmath / strings for amounts, not floatval.
200
{
  "id": "rep_4c8a10d2-91f7-4a3e-b0c6-52d8e7f19b34",
  "kind": "statements",
  "status": "ready",
  "rows": 1842,
  "bytes": 214093,
  "error": "",
  "download_url": "https://api.zinfra.vip/v1/reports/rep_4c8a10d2-91f7-4a3e-b0c6-52d8e7f19b34/content",
  "expires_at": "2026-08-20T05:00:07.220Z",
  "created_at": "2026-08-13T05:00:00.000Z",
  "updated_at": "2026-08-13T05:00:07.220Z"
}