API reference
Base URL: https://pyfyjiaqw2.execute-api.us-east-1.amazonaws.com/api.
Every path below is under it, over HTTPS only.
Authentication: every request carries your workspace's API key:
Authorization: Bearer um_live_...
Keys are stored by Unimode only as hashes. A missing, unknown or revoked key
gets 401. Requests are rate limited; sustained bursts get 429 or 403.
Endpoints
| Method and path | Purpose |
|---|---|
GET /v1/me |
Your workspace: status, profiles, spend limit per run, next setup step |
GET /v1/integration |
External ID, registered role and folders |
GET /v1/integration/template |
CloudFormation template that creates the access role |
PUT /v1/integration |
Register (and verify) the role and its folders |
POST /v1/integration/rotate-external-id |
Issue a new external ID |
POST /v1/runs |
Start a run on a feed |
GET /v1/runs |
Your recent runs |
GET /v1/runs/{run_id} |
One run's status, counts and cost |
Starting a run
POST /v1/runs
{"input": "s3://acme-feeds/unimode/2026-10/feed.jsonl",
"output": "s3://acme-results/unimode-results/",
"profile": "acme.apparel",
"max_usd": 20}
input: a JSON Lines feed under your registered input folder (at most 200 MB).output: under your registered output folder; results go to<output>/<run_id>/.profile(optional): one of your workspace's profiles (GET /v1/me); your default otherwise.max_usd(optional): a spend cap for this run, at most your workspace'smax_run_usd(GET /v1/me), which is also the cap when you leave it out. A higher value is refused (400,detail.code = max_usd_above_limit). A run that reaches its cap stops with statusbudget_exceeded.
Any other field is rejected. Before starting, Unimode checks that the feed is readable and the output writable.
Runs
GET /v1/runs/{run_id} and GET /v1/runs return:
{"run_id": "20261022-...", "status": "running", "profile": "acme.apparel",
"input": "s3://acme-feeds/unimode/2026-10/feed.jsonl",
"output": "s3://acme-results/unimode-results/20261022-.../",
"created_at": "...", "started_at": "...", "finished_at": null,
"cost_usd": 0.12, "accepted": 950, "rejected": 50, "delivered": null, "error": null}
status is queued, running, succeeded, failed, cancelled,
budget_exceeded, or expired (30 days after the run finished, when
Unimode has deleted its copies; only run_id, created_at and expired_at
remain). cost_usd is the spend so far and updates while the run is in
progress.
What a run delivers
Under <output>/<run_id>/:
| File | Contents |
|---|---|
items.jsonl |
One record per enriched product: id, publishable, needs_review_reasons, subcategory, attributes (each with its value and where it came from), extra_details, qa (buyer questions and answers). |
errors.jsonl |
Feed lines that were rejected: line (1-based; empty for a repeated id), id, message; then products that failed enrichment: line empty, id, message, stage. |
run.json |
Status, counts (accepted, rejected, delivered, failed), cost_usd, timestamps. Written last: when it exists, the delivery is complete. |
A feed with no valid products fails the run; errors.jsonl and run.json are
still delivered. If the output stops being writable mid-run (for example, the
role was deleted), the run fails, and Unimode keeps the results so they can be
delivered again. You are charged only for listings delivered in
items.jsonl.
Errors
| Status | When |
|---|---|
400 |
Input or output outside your registered folders; unknown profile; max_usd above your workspace's limit (detail.code = max_usd_above_limit); a role in another account or not named UnimodeEnrichmentAccess*. |
401 |
Missing, unknown or revoked API key. |
403 |
Workspace not active (setup not finished, or suspended). |
404 |
Run not found. |
413 |
Feed larger than the limit (detail.code = input_too_large). |
422 |
Malformed request, including fields that are not allowed. |
424 |
Access to your account failed: detail.code is role_assume_failed, input_unreadable or output_unwritable. |