---
title: "Cancel a trader export job"
method: POST
path: "/api/v1/trader/{address}/export/cancel"
tags: ["Traders"]
---

# Cancel a trader export job

`POST /api/v1/trader/{address}/export/cancel`

Cancels a submitted export and returns the job resource, the same shape the status route returns. A queued job reads cancelled at once and no worker will start it. A running job reads cancel_requested until the worker reaches its next safe point, then cancelled: the worker checks every 5 seconds while it reads the snapshot and between upload parts, and once more at the last point before the file is published; a storage request already in flight finishes first (each is bounded at 120 seconds), and a partial upload is discarded. If the worker itself stops first, the job reads cancelled after its 30-minute lease lapses, at the next hourly cleanup. A job a cancel can no longer reach is returned unchanged with 200: once its upload is being completed it finishes as ready (or reconcile_required, then ready or failed), and ready, failed, expired and cancelled jobs are terminal. A cancel never deletes a ready file; compare status before and after. Repeating the request is safe: it converges on the same state and never repeats a transition, so a client that lost the answer can send it again or read the status route. While terminal is false, poll the status route after poll_after_s. Quota is unchanged: the submit's reservation keeps counting toward the per-user daily and per-address hourly export caps for its full window, as a failed export's does, and a job its owner asked to cancel is never reused by a later submit, which reserves a new job. Webhook endpoints subscribed to export_job_cancelled receive it when the job reaches cancelled. An unknown job id, or a job owned by another account or submitted for another trader, answers 404 exactly as the status route does.

## Path parameters

- `address` string, required

## Query parameters

- `job_id` integer, required

## Headers

- `X-Query-Validation` 'strict'

## Response `200`

The job after the cancel: cancelled, cancel_requested, or unchanged when a cancel can no longer reach it.

- TraderExportJob
  - `object` 'trader_export_job', required
  - `data` object, required
    - `job_id` integer, required
    - `status` 'queued' | 'running' | 'ready' | 'failed' | 'reconcile_required' | 'expired' | 'cancel_requested' | 'cancelled', required — queued: accepted, not started. running: the worker is streaming rows. reconcile_required: the upload finished but the storage completion answer was lost; the hourly reconciler reads the object back and moves the job to ready or failed, and expires_at bounds the wait. ready: downloadable until expires_at. failed: terminal; error says why; submit a new export. expired: the retention window passed; the file is retired, the download route answers 410, submit a new export. cancel_requested: the owner cancelled a running job (POST /api/v1/trader/{address}/export/cancel); the worker stops at its next safe point and the job reads cancelled. cancelled: terminal; the owner cancelled the job and no file was published; submit a new export. A job that has not reached ready by expires_at reads failed with error 'export expired before completion'. failed, cancelled and expired rows stay readable for 48 hours, then the job answers 404.
    - `format` 'json' | 'ndjson' | 'csv', required
    - `total_trades` integer, nullable, required
    - `processed_trades` integer, nullable, required
    - `file_size` integer, nullable, required
    - `error` string, nullable, required
    - `terminal` boolean, required — True when status never changes again (ready, failed, expired, cancelled). Stop polling.
    - `next_action` 'poll' | 'download' | 'resubmit', required — What to do next: poll the status route after poll_after_s, follow the download route, or submit a new export. Published beside status so a status value added later does not strand a client.
    - `poll_after_s` integer — Seconds to wait before polling again. Absent when terminal. 5 while queued, running or cancel_requested; 300 while reconcile_required, the cadence that state can change at.
    - `created_at` string, date-time, required
    - `started_at` string, date-time, nullable, required — When the worker last claimed the job; null while queued.
    - `ready_at` string, date-time, nullable, required — When the file became downloadable. null before ready, and on jobs finalized before this field existed.
    - `failed_at` string, date-time, nullable, required
    - `expires_at` string, date-time, required — The retention window: 24 hours from submit. A ready file downloads until this instant; a job that has not reached ready by it fails. A reused job (200 on submit) keeps its original window.
    - `expired_at` string, date-time, nullable, required — When the job became expired; null until then.
    - `data_as_of` string, date-time, nullable, required — What the file is a snapshot of: the trader's served-data clock (the latest position refresh, else the last completed sync) when the file was written; the same value as export_metadata.data_as_of inside the file. null until the file is written, or when the trader had neither. Read this, not ready_at, to decide whether a reused job is fresh enough; submit with fresh=true for a newer snapshot.
    - `cancel_requested_at` string, date-time, nullable, required — When the owner asked to cancel the job; null otherwise. Set on every cancelled job, including one cancelled while queued. While status is cancel_requested this is the instant the worker was asked to stop.
    - `cancelled_at` string, date-time, nullable, required — When the job reached cancelled; null until then.
    - `attempt` integer, required — Worker claims so far.
    - `max_attempts` integer, required — The job fails when attempt reaches this.
    - `artifact` object — Present only while status is ready: the stored object's identity, so a client can check the download it receives.
      - `artifact_id` string, required — Stable identity for this completed export artifact; unchanged when a temporary download URL is renewed.
      - `etag` string, nullable, required — The storage ETag of the object.
      - `compressed_size_bytes` integer, nullable, required — Bytes on the wire (gzip); file_size is the decompressed size.
      - `content_type` 'application/json' | 'application/x-ndjson' | 'text/csv', required
      - `content_encoding` 'gzip', required
      - `manifest` TraderExportArtifactManifest, required
        - `manifest_version` string, required — Version of the artifact manifest contract.
        - `format` 'json' | 'ndjson' | 'csv', required — Serialization used for the decompressed content.
        - `schema_version` 'trader-export-json-v1' | 'trader-export-ndjson-v1' | 'trader-export-csv-v1', required — Stable schema identifier for the selected serialization.
        - `coverage` 'full_envelope_and_trades' | 'trades_only', required — Sections represented by the artifact. JSON and NDJSON carry the full envelope and trades; CSV carries trade rows only.
        - `generation` TraderExportGeneration, required
          - `id` string, uuid, required — Opaque generation identity selected for the coherent read snapshot.
          - `selected_at` string, date-time, required
          - `consistency` 'repeatable_read', required
          - `source_watermarks` TraderExportSourceWatermarks, required
            - `positions` TraderExportPositionWatermark, required
              - …
            - `pnl` TraderExportPnlWatermark, required
              - …
            - `categories` TraderExportCategoryWatermark, required
              - …
            - `trades` TraderExportTradeWatermark, required
              - …
        - `row_count` integer, required — Number of trade rows written.
        - `content_size_bytes` integer, required — Exact byte count of the decompressed content stream clients receive.
        - `content_sha256` string, required — Lowercase SHA-256 of the decompressed content bytes.
        - `compressed_size_bytes` integer, required — Exact byte count of the gzip-compressed bytes stored by the object provider.
        - `compressed_sha256` string, required — Lowercase SHA-256 of the stored gzip bytes; the multipart ETag is not used as this checksum.
  - `meta` ResponseMeta, required
    - `request_id` string, required — Unique request ID (req_ prefix). The same value as the X-Request-Id response header, the request's usage accounting row and its log lines.
    - `cached` boolean, required
    - `cache_age_s` integer — Cache age in seconds. Omitted when the response was not cached, and also when it was cached but its age cannot be established (an entry stored before its cache carried a computed instant). Never a placeholder: an unknown age is reported as no value rather than as the cache TTL.
    - `cost` integer, required — Advisory request weight (relative compute cost). 1 for simple reads; higher for heavier endpoints. Not a credit/price.
    - `ranking_generation` integer — Committed PostgreSQL-owned leaderboard generation for the returned rows and cursor. Present on GET /api/v1/leaderboard; omitted on endpoints that do not read this ranking.
    - `ranking_as_of` string, date-time — Authoritative RFC3339 timestamp from cache_generations.updated_at for ranking_generation. It is read in the same repeatable-read snapshot as the leaderboard rows and is not request time, cache write time, or row insertion order.
    - `directional_source` 'live' | 'degraded' — Which path produced the team-directional read on this response. Only present on endpoints that compute one (today: GET /api/v1/sports-edge-signals). "live" means the read RAN. "degraded" means it FAILED, so nothing was measured and the ranking fell back to raw conviction. The flag describes the READ, not its consequence: a read that ran and found nothing groupable also leaves the directional fields null, and that is honestly "live" -- the per-signal nulls already say "nothing to enrich here", so this snapshot-level flag carries only what they cannot, namely whether the read ran at all. A degraded response is cached on the shorter degraded TTL so it self-heals. Reported SEPARATELY from ranking_source because the two degradations are independent -- a sharp-money DB miss weakens the ranking DATA, a directional failure removes a ranking WEIGHT -- and a consumer down-weighting a degraded response needs to know which input it lost. Omitted on endpoints that compute no directional read.
    - `ranking_source` 'live' | 'db_only' — Which ranking-data path produced this response. Only present on endpoints that can degrade a ranking (today: GET /api/v1/sports-edge-signals). "live" is the normal path (the current holder pile from the provider batch); "db_only" is the degraded fallback (a truthful but weaker trader_markets ranking) served when the live sharp-money ranking batch is unavailable (a sharp-money DB read failure, not a Polymarket outage) and cached on a shorter TTL, so a consumer can down-weight or skip it. Omitted on endpoints that never degrade.
    - `category_skill_source` 'live' | 'partial' | 'degraded' | 'unavailable' — Whole filtered snapshot category-evidence status before pagination. Operational live always remains partial source coverage.
    - `category_skill_model_version` string
    - `category_skill_taxonomy_version` string
    - `category_skill_platform` 'polymarket'
    - `category_skill_scope` 'observed_goldsky_primary_taker_fill'
    - `category_skill_source_coverage` 'partial_whale_threshold_fills' | 'graded_wallet_fills'
    - `category_skill_observation_started_at` string, date-time
    - `category_skill_model_operationally_degraded` boolean — Whole-model operational readiness captured with the category model snapshot. Present on category-enriched responses even when the filtered signal list is empty. When true, category_skill_source is degraded and sports-edge-signals uses the shorter degraded cache TTL.
    - `category_skill_status_counts` object
      - `live` integer, required
      - `insufficient` integer, required
      - `stale` integer, required
      - `unknown` integer, required
      - `degraded` integer, required
    - `category_skill_base_payload_hash` string — SHA-256 of the funded signal membership/order/rank/cursor vector immediately before category-skill enrichment. Sports-edge-signals only.
    - `category_skill_enriched_base_payload_hash` string — Independent SHA-256 recomputation over the same base fields immediately after category-skill enrichment. Equality with category_skill_base_payload_hash proves shadow enrichment did not change funded inputs. Sports-edge-signals only.

## Other responses

- `400` — Invalid request parameter: job_id missing or not an integer, or a malformed trader path.
- `401` — Missing or invalid API key
- `402` — Active Pro subscription required. The key is valid but the account has no active Pro subscription; error.reason is subscription_inactive and error.message names the reactivation URL (https://0xinsider.com/billing). Permanent until a person reactivates: no Retry-After, never retry on a schedule.
- `403` — Account access denied
- `404` — Resource not found
- `408` — The handler did not answer inside the server's 30-second timeout. error.code is request_timeout. On GET and HEAD the response carries Retry-After and error.retry_at; on a mutation it carries neither, because the request may have completed on the server: check its state before repeating it, and reuse its Idempotency-Key.
- `423` — Account is locked
- `429` — Rate limit exceeded. Three independent budgets. (1) 100 requests/minute per user (sliding window), on every authenticated route. (2) On the BATCH routes only: 2500 batch item units/minute per user, reserved before any item is executed. A batch with N requested items costs N item units, including duplicate and invalid items. 2500 = 100 requests x 25 items per batch, which is the most item work a key can buy through the request limiter at all: a caller may spend their entire 100-request minute on full 25-item batches without the item budget being what stops them. The REQUEST budget is the effective ceiling, and batching is never the more expensive choice. The item budget can still deny at a sliding-window boundary (both counters carry the previous window forward with a floor, and the item counter runs 25x the request counter), so honor a 429 from either. Over-quota batches return 429 with Retry-After plus RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset before any item work is done. (3) The monthly quota: Pro includes 250,000 authenticated requests per UTC calendar month, whatever the billing cadence. Over 250,000: with pay as you go on, requests keep answering and the excess bills at USD 0.20 per 1,000 on a monthly invoice, up to 1,000,000 requests a month; without it, from October 1, 2026, the next request answers 429 rate_limited with error.reason monthly_quota_exceeded and a Retry-After to the month's reset, and from the same day a pay-as-you-go account answers the same past 1,000,000. A refused request is not counted. Every authenticated response carries X-Monthly-Quota-Limit, X-Monthly-Quota-Remaining, and X-Monthly-Quota-Reset (unix seconds, the first of next month). (4) The per-address budget: 1200 requests/minute per IP, shared by every caller behind one address and counted before authentication, on every route. A 429 from it carries error.reason ip_rate_limited and describes that bucket in RateLimit-*; a throttled address (sustained over-limit traffic) carries error.reason ip_throttled with a Retry-After of minutes to days, and a request before it does not shorten the cooldown. Every 429 is the standard error envelope with meta.request_id equal to X-Request-Id.
- `500` — Unexpected server error
- `503` — Redis-backed authenticated rate limiter unavailable; retry after the per-process outage cooldown

## Changes

- **2026-09-23** `ece7a25b7a44` — 10 warning, 10 info
  - added the new `freshness_ceiling_unsatisfied` enum value to the `error/reason` response property for the response status `400`
  - added the new `freshness_ceiling_unsatisfied` enum value to the `error/reason` response property for the response status `401`
  - added the new `freshness_ceiling_unsatisfied` enum value to the `error/reason` response property for the response status `402`
  - added the new `freshness_ceiling_unsatisfied` enum value to the `error/reason` response property for the response status `403`
  - …16 more
- **2026-09-23** `c6a3d3420dc5` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/0xinsider/apis/0xinsider-api/changes/api/v1/trader/:address/export/cancel/post.md)

---

[API](https://skmtc.dev/0xinsider/apis/0xinsider-api.md) · [All operations](https://skmtc.dev/0xinsider/apis/0xinsider-api/llms.txt) · [OpenAPI document](https://skmtc.dev/0xinsider/apis/0xinsider-api/revisions/2035b3316329?raw)
