Photos and a few words in, a finished listing in your own fields out.
Orbit turns what a seller says and the photos they take into a finished listing, written into your own listing fields (the facts a listing in your shop carries, such as storage, colour or mileage, set up on the Set up your listing fields page).
| Who | What Orbit does for them |
|---|---|
| Shops | The seller types a sentence and adds photos on the create listing page. Orbit fills your listing fields, asks the few things only the seller knows, and the seller checks the result instead of filling a long form. |
| Classifieds | A photo-first sell flow in any category. Orbit picks the category from your listing fields and writes the title and description in your house style. |
| Resale shops and refurbishers | Bulk listing: photograph each item at intake, start one listing per item and read them back as they finish. Staff answer the condition questions, and every listing reads the same way. |
| Car dealers | An advert from a few photos and the dealer's notes, in your own fields (make, model, mileage). Fields only the seller can answer, such as mileage and service history, are asked and never guessed. |
| Rental and property listings | A host photographs the place and writes a few lines. Orbit fills your fields from what the host says and what the photos show, and lists what it could not fill. |
| Insurance | An inventory or claim description of an item or asset from the owner's photos and notes, in the insurer's own fields. The sources and the unfilled list show what the owner said and what they could not say. Orbit does not value or authenticate the item. |
Orbit works in the background, so no call waits for the AI. Starting a listing answers at once with its runId (the listing's id, your ticket). You read the listing back with that id. A listing is kept for 30 minutes after its last change.
| status | What it means | What you do |
|---|---|---|
working | Orbit is working, or waiting its turn. | Read again every second while processing is true. |
questions | Orbit needs answers only the seller has. | Show the questions, then POST the answers. |
listing | The draft is ready. Optional checks may still be running. | Show item to the seller. Keep polling while processing is true and wait for Safeguard to pass before publishing when it is on. |
failed | The work failed. error says why and retry says how to try again. | Follow error.tryThis. A failed listing is not charged. |
cancelled | You cancelled it. | Nothing more happens. |
Use a test key (it spends no credits). The examples set it as $PCIFIC_TEST_KEY. Each step shows the real reply.
If a photo decoder stops unexpectedly, a successful upload can contain accepted images plus problems naming each failed photo, its original position and what to try next. Keep the returned image ids and upload only the failed photos again. If ordinary photo validation refuses the request with 422, none of that request's photos are saved; fix the listed problems and send all photos again.
PCIFIC cleans each uploaded fileName before storing or returning it: folder names, control characters and .. are removed. If nothing remains, it uses upload.jpg, upload.png or upload.webp according to the Content-Type.
Send the photos as a multipart form (a form that carries files). Use JPEG, PNG or WebP, up to 12 photos, 15 MB each and 60 MB in all. iPhone HEIC photos are refused: see iPhone photos (HEIC) below.
curl -X POST https://business.pcific.ai/api/v1/images \
-H "Authorization: Bearer $PCIFIC_TEST_KEY" \
-F "photo=@front.jpg" \
-F "photo=@back.jpg"{
"images": [
{
"id": "3f1c2a9e-5b7d-4e21-9c0a-6d8f4b1e7a52",
"width": 4032,
"height": 3024,
"preview": "https://photos.pcific.example/preview.webp?signature=...",
"listing": {
"url": "https://photos.pcific.example/listing.webp?signature=...",
"format": "webp"
},
"expiresAt": "2026-10-15T10:30:00Z",
"fileName": "front.jpg"
}
]
}The preview and listing links are signed links that stop working at expiresAt. Photos are kept for 30 minutes after upload and for 30 minutes after the listing that uses them finishes. Save the copy you want to keep.
PCIFIC accepts JPEG, PNG and WebP only. iPhones save photos as HEIC, and PCIFIC does not convert HEIC on its servers: decoding it takes a lot of memory and is expensive, so a HEIC photo is refused with PHOTOS_REFUSED.
// Turns a picked photo, HEIC included, into a JPEG of at most 2,500 pixels on its longest side.
// Resolves to null when this browser cannot read the file.
function toJpeg(file) {
return new Promise((resolve) => {
const url = URL.createObjectURL(file);
const image = new Image();
image.onload = () => {
const scale = Math.min(1, 2500 / Math.max(image.naturalWidth, image.naturalHeight));
const canvas = document.createElement("canvas");
canvas.width = Math.round(image.naturalWidth * scale);
canvas.height = Math.round(image.naturalHeight * scale);
canvas.getContext("2d").drawImage(image, 0, 0, canvas.width, canvas.height);
URL.revokeObjectURL(url);
canvas.toBlob((blob) => resolve(blob), "image/jpeg", 0.9);
};
image.onerror = () => {
URL.revokeObjectURL(url);
resolve(null);
};
image.src = url;
});
}These responses illustrate the Phones schema published in the listing-fields guide. Use the image ids returned by your upload in images, then use your returned runId in every read and follow-up call. Your ids, timestamps, wording and questions will differ.
curl -X POST https://business.pcific.ai/api/v1/listings \
-H "Authorization: Bearer $PCIFIC_TEST_KEY" \
-H "Content-Type: application/json" \
-d '{"notes":"iPhone 13, good condition, works fine. Selling my old phone. No box. Collection preferred. Asking £315.","details":{"price":{"amount":31500,"currency":"GBP"}},"images":["3f1c2a9e-5b7d-4e21-9c0a-6d8f4b1e7a52"]}'{
"status": "working",
"processing": true,
"deadlineAt": "2026-10-15T10:01:00Z",
"parts": {
"listing": "pending",
"price": "off",
"safeguard": "off",
"faq": "off"
},
"publishReady": false,
"runId": "8d0e5f12-7a3c-4b96-8e41-c2d9a6f03b75",
"tryThis": "Read where it is with GET /api/v1/listings/8d0e5f12-7a3c-4b96-8e41-c2d9a6f03b75 in a few seconds.",
"warnings": []
}Keys that are not Orbit fields are ignored and named in warnings. This call takes an Idempotency-Key header, so a request you send again after a dropped connection starts only one listing (see Errors, limits and retries).
curl https://business.pcific.ai/api/v1/listings/8d0e5f12-7a3c-4b96-8e41-c2d9a6f03b75 \
-H "Authorization: Bearer $PCIFIC_TEST_KEY"{
"status": "working",
"runId": "8d0e5f12-7a3c-4b96-8e41-c2d9a6f03b75",
"processing": true,
"deadlineAt": "2026-10-15T10:01:00Z",
"parts": {
"listing": "pending",
"price": "off",
"safeguard": "off",
"faq": "off"
},
"publishReady": false,
"tryThis": "Read this again in a few seconds."
}Read every second while processing is true. The draft returns as soon as it is written, with status listing even while optional checks continue. Every response includes parts.listing (pending, ready or failed), parts.price (off, pending, ready or failed), parts.safeguard (off, pending, passed, flagged or failed), parts.faq (off, pending, ready or failed), deadlineAt and publishReady. When Safeguard is on, show and edit the draft but wait to publish until parts.safeguard is passed and publishReady is true. Fill required fields in pcific.unfilled too. Queue wait, drafting, checks and worker recovery share one 3-minute total processing ceiling. A 30-second idle timer resets on each AI answer or completed step; a stuck run stops with ORBIT_TIMED_OUT. Human answer time is excluded from the total ceiling. Answers resume the remaining budget, and retries keep the same ceiling. Near the ceiling Orbit finishes with known facts and lists missing fields in pcific.unfilled, with pcific.complete false. Failed work is not charged. A listing can be read for 30 minutes after its last change; after that GET answers 404 NOT_FOUND.
If Orbit needs the storage or condition confirmed, the reply to the same call can be:
{
"status": "questions",
"processing": false,
"deadlineAt": null,
"parts": {
"listing": "pending",
"price": "off",
"safeguard": "off",
"faq": "off"
},
"publishReady": false,
"runId": "8d0e5f12-7a3c-4b96-8e41-c2d9a6f03b75",
"expiresAt": "2026-10-15T10:30:00Z",
"questions": [
{
"id": "q1",
"question": "How much storage does it have?",
"field": "/storage_gb",
"options": [
"64",
"128",
"256",
"512",
"1024"
]
},
{
"id": "q2",
"question": "What condition is it in?",
"field": "/condition",
"options": [
"New",
"Like new",
"Good",
"Fair",
"For parts"
]
}
],
"warnings": []
}curl -X POST https://business.pcific.ai/api/v1/listings/8d0e5f12-7a3c-4b96-8e41-c2d9a6f03b75/answers \
-H "Authorization: Bearer $PCIFIC_TEST_KEY" \
-H "Content-Type: application/json" \
-d '{"answers":[{"id":"q1","answer":"128"},{"id":"q2","answer":"Good"}]}'That answers 202 with the same body as step 2. Go back to step 3.
{
"status": "listing",
"processing": true,
"deadlineAt": "2026-10-15T10:01:00Z",
"parts": {
"listing": "ready",
"price": "pending",
"safeguard": "pending",
"faq": "off"
},
"publishReady": false,
"runId": "8d0e5f12-7a3c-4b96-8e41-c2d9a6f03b75",
"item": {
"title": "iPhone 13 128GB, good condition, works fine",
"description": "Selling my old phone. No box. Collection preferred.",
"brand": "Apple",
"model": "iPhone 13",
"storage_gb": 128,
"condition": "Good",
"price": {
"amount": 31500,
"currency": "GBP"
}
},
"pcific": {
"release": "2.0.0",
"category": "Phones",
"schemaVersion": 1,
"complete": true,
"unfilled": [],
"sources": {
"/title": {
"from": "ai"
},
"/storage_gb": {
"from": "seller"
},
"/description": {
"from": "ai"
},
"/brand": {
"from": "seller"
},
"/model": {
"from": "seller"
},
"/condition": {
"from": "seller",
"quote": "good condition"
},
"/price": {
"from": "seller"
}
},
"prices": {
"/price": {
"amount": 31500,
"currency": "GBP",
"display": "£315.00"
}
},
"images": [
{
"id": "3f1c2a9e-5b7d-4e21-9c0a-6d8f4b1e7a52",
"width": 4032,
"height": 3024,
"preview": "https://photos.pcific.example/preview.webp?signature=...",
"listing": {
"url": "https://photos.pcific.example/listing.webp?signature=...",
"format": "webp"
},
"expiresAt": "2026-10-15T10:30:00Z"
}
],
"warnings": [],
"price": {
"status": "pending"
},
"safeguard": {
"status": "pending"
}
}
}{
"status": "listing",
"processing": false,
"deadlineAt": "2026-10-15T10:01:00Z",
"parts": {
"listing": "ready",
"price": "off",
"safeguard": "off",
"faq": "off"
},
"publishReady": true,
"runId": "8d0e5f12-7a3c-4b96-8e41-c2d9a6f03b75",
"item": {
"title": "iPhone 13 128GB, good condition, works fine",
"description": "Selling my old phone. No box. Collection preferred.",
"brand": "Apple",
"model": "iPhone 13",
"storage_gb": 128,
"condition": "Good",
"price": {
"amount": 31500,
"currency": "GBP"
}
},
"pcific": {
"release": "2.0.0",
"category": "Phones",
"schemaVersion": 1,
"complete": true,
"unfilled": [],
"sources": {
"/title": {
"from": "ai"
},
"/storage_gb": {
"from": "seller"
},
"/description": {
"from": "ai"
},
"/brand": {
"from": "seller"
},
"/model": {
"from": "seller"
},
"/condition": {
"from": "seller",
"quote": "good condition"
},
"/price": {
"from": "seller"
}
},
"prices": {
"/price": {
"amount": 31500,
"currency": "GBP",
"display": "£315.00"
}
},
"images": [
{
"id": "3f1c2a9e-5b7d-4e21-9c0a-6d8f4b1e7a52",
"width": 4032,
"height": 3024,
"preview": "https://photos.pcific.example/preview.webp?signature=...",
"listing": {
"url": "https://photos.pcific.example/listing.webp?signature=...",
"format": "webp"
},
"expiresAt": "2026-10-15T10:30:00Z"
}
],
"warnings": []
}
}item is exactly your listing fields filled in, nothing added, so you can save it as it is. Everything PCIFIC adds is inside pcific. The listing can be read again for 30 minutes.
curl -X POST https://business.pcific.ai/api/v1/listings/8d0e5f12-7a3c-4b96-8e41-c2d9a6f03b75/outcome \
-H "Authorization: Bearer $PCIFIC_TEST_KEY" \
-H "Content-Type: application/json" \
-d '{"event":"published","changes":[{"field":"title","percentChanged":20}],"finalListing":{"title":"iPhone 13 128GB, good condition, collection preferred","description":"Selling my old phone. No box. Collection preferred.","brand":"Apple","model":"iPhone 13","storage_gb":128,"condition":"Good","price":{"amount":31500,"currency":"GBP"}}}'{
"recorded": true
}POST /api/v1/listings. The body is a JSON object (text in a fixed shape). At least one of notes, details or images is needed.
Send prices in details and finalListing as whole numbers in the smallest currency unit, such as 4500 pence for £45. Decimal points, exponents and text amounts are refused with 400 INVALID_FIELD.
| Field | Type | Required | What it is |
|---|---|---|---|
notes | string | No | The seller's own words about the item, up to 5,000 characters. The shop's notesMinLength and notesMaxLength apply even with details or images. With both unset, at least 4 characters are needed only without details or images. Their facts win over guesses. null is the same as leaving it out. |
details | object | No | Customer-defined: what your form already has from the seller, keyed by your own field names exactly as you send them, with any JSON values. Counts as the seller's words. null or {} is the same as leaving it out. |
images | string[] | No | Photo ids from POST /api/v1/images, at most 12. Photos are kept for 30 minutes. null is the same as leaving it out. |
category | string | No | The category's name in your newest published listing fields. Leave it out, or send null, and Orbit finds it. |
price | boolean | No | Leave it out, or send null, to follow the pricing setting. false skips the price check for this listing. true needs the pricing setting on (PRICING_OFF otherwise). |
safeguard | boolean | No | true has Safeguard review the finished listing. Leave it out, or send null, to follow Safeguard's orbitDefault setting. true needs Safeguard on (SAFEGUARD_OFF otherwise). |
faq | boolean | No | true has Safeguard write a buyer FAQ for the finished listing. Off unless asked for. Needs Safeguard on. null is the same as leaving it out. |
modelTier | string | No | standard (the default) or ultra-fast. Ultra Fast answers in about half a second instead of several, and a live use spends more credits: the Credits page in your dashboard shows how many. A use is charged as Ultra Fast only when Ultra Fast answered the whole request; otherwise Standard answers and it is charged as Standard. A business on its own AI key is answered by its own model. null is the same as leaving it out. |
All three answer 202 with the same body.
| Field | Type | Required | What it is |
|---|---|---|---|
status | string | Yes | working, or the current saved status on retry. Poll while processing is true. |
runId | string | Yes | The listing's id. Read it with GET /api/v1/listings/{runId}. |
processing | boolean | Yes | Keep polling while true, even with a ready draft. |
deadlineAt | string | Yes | UTC processing deadline; null while waiting for the seller. |
parts | object | Yes | Status of listing, price, Safeguard and FAQ. |
publishReady | boolean | Yes | Draft ready and Safeguard passed when enabled. Fill pcific.unfilled too. |
item | object | No | A kept draft on retry, in your listing fields. |
pcific | object | No | The kept draft's sources, price and checks on retry. |
tryThis | string | Yes | What to do next. |
warnings | string[] | Yes | One line for each key in the body that is not an Orbit field. Those keys were ignored. |
GET /api/v1/listings/{runId} always answers 200 for a listing that exists. Which fields are there depends on status.
| Field | Type | Required | What it is |
|---|---|---|---|
status | string | Yes | working, questions, listing, failed or cancelled. |
runId | string | Yes | The listing's id. |
processing | boolean | Yes | Keep polling while true, even when status is listing. |
deadlineAt | string | Yes | UTC processing deadline, including queue wait. Null while waiting for the seller. |
parts | object | Yes | listing: pending/ready/failed; price: off/pending/ready/failed; safeguard: off/pending/passed/flagged/failed; faq: off/pending/ready/failed. |
parts.listing | string | Yes | pending, ready or failed. |
parts.price | string | Yes | off, pending, ready or failed. |
parts.safeguard | string | Yes | off, pending, passed, flagged or failed. |
parts.faq | string | Yes | off, pending, ready or failed. |
publishReady | boolean | Yes | Draft ready and Safeguard passed when enabled. Fill pcific.unfilled before publishing. |
tryThis | string | No | With working: what to do next. |
expiresAt | string | No | With questions: when the listing stops waiting for answers (30 minutes after the questions). |
questions | object[] | No | With questions: [{id, question, field, options}]. field is the path of the field the answer fills, and options are that field's allowed values from your listing fields. Both are left out when there are none. |
warnings | string[] | No | With questions: the ignored keys of the request, as in the 202. |
item | object | No | With a ready draft, including a failed run with a kept draft: your listing fields filled in, nothing added, so it can be saved as it is. |
pcific | object | No | With listing: everything PCIFIC adds, see the next table. |
error | object | No | With failed: {error, code, tryThis} like any error body. |
retry | string | No | With failed: the call that tries again, written POST /api/v1/listings/{runId}/retry. |
| Field | Type | Required | What it is |
|---|---|---|---|
release | string | Yes | The Orbit release that wrote the listing. Only 2.0.0 exists. |
category | string | Yes | The category Orbit used. |
schemaVersion | integer | Yes | The version of your listing fields it used. |
complete | boolean | Yes | false when unfilled names required fields the seller could not give. The business must fill them before publishing. |
unfilled | object[] | Yes | [{field, reason}]: required fields left empty because the seller was asked and could not say. |
sources | object | Yes | Where each value came from, keyed by field path like /storage: {from: seller, photo, web or ai}. A seller-only field also has the seller's own words in quote. A web value has the page in link. |
prices | object | Yes | Each price field written out, keyed by field path: {amount, currency, display}. amount is a whole number in the smallest unit. |
price | object | No | When the price check is on: {status: pending, priced, no_price or not_available, ...}. See the price check table. |
images | object[] | Yes | The listing's photos, each as in the photo table. |
warnings | string[] | Yes | The ignored keys of the request. |
safeguard | object | No | Only when safeguard or faq was asked for: {status: pending} until its result is saved, then the review as GET /api/v1/safeguard/reviews/{reviewId} shows it, with its reviewId. If Safeguard failed, {status: failed, error, retry}; the listing still comes back. |
modelTier | object | No | Once the price check and any Safeguard review have finished, which count towards it. Which tier answered: {requested, handledBy, message}. |
modelTier.requested | string | Yes | standard or ultra-fast, as the request asked. |
modelTier.handledBy | string | Yes | The tier that answered the whole request: standard, ultra-fast, or byo when your own AI key answered. A use is charged as Ultra Fast only when this is ultra-fast. |
modelTier.message | string | Yes | Why handledBy differs from requested, else null. |
Prices are whole numbers in minor units (the smallest unit of a currency, so 31500 pence is 315 pounds), with the currency code. Fields can be added at any time; ignore what you do not use.
| Field | Type | Required | What it is |
|---|---|---|---|
status | string | Yes | pending, priced, no_price or not_available. Only priced has prices. |
currency | string | No | With priced: your currency. |
quickSale | integer | No | With priced: the price for a quick sale, in the smallest unit. |
recommended | integer | No | With priced: the recommended price. |
patient | integer | No | With priced: the price for a patient seller. quickSale is at most recommended, and recommended at most patient. |
sources | object[] | No | With priced: [{link, price, brand?, model?, reference?, variant?}], at least 2 different search result pages with prices in your currency. If a download fails, the search summary can supply the amount. Reported identifiers that differ from the listing's known fields never count. Missing listing identifiers are not inferred or compared. |
reason | string | No | With no_price or not_available: why there is no price. |
{
"status": "priced",
"currency": "GBP",
"quickSale": 29000,
"recommended": 31500,
"patient": 34000,
"sources": [
{
"link": "https://shop-one.example/iphone-13-128gb",
"price": 30500
},
{
"link": "https://shop-two.example/apple-iphone-13",
"price": 32500
}
]
}| Call | What it does | When it works |
|---|---|---|
POST /api/v1/listings/{runId}/answers | Sends the seller's answers: {answers: [{id, answer}]}. Up to 1,000 characters each. A question you leave out is recorded as no answer. An answer may be "I don't know". Answers 202. | Only while status is questions. Each question can be answered once. |
POST /api/v1/listings/{runId}/retry | Tries a failed listing again from where its last stretch of work started: the request, or the seller's answers (the seller is not asked again). Answers 202. | Only while status is failed. |
POST /api/v1/listings/{runId}/cancel | Free before AI work starts. Once AI work starts, cancellation charges the usual listing price, including the own-key rate when applicable, and counts towards spending limits. Stops the listing and its Safeguard review now, and deletes its photos unless another listing still going, or a Safeguard review, uses them. Answers {status: cancelled, runId}. | While status is working, questions or failed. |
POST /api/v1/listings/{runId}/outcome | Tells PCIFIC what the seller did: {event: published, changes, finalListing} or {event: abandoned}. Kept for 30 days, once per listing, and only when Orbit is on full monitoring. Otherwise it returns 409 MONITORING_OFF. An unknown runId returns 404. | For a listing Orbit finished. See Monitoring and privacy. |
GET /api/v1/images/{id} | One photo with fresh links. | While the photo is kept. |
DELETE /api/v1/images/{id} | Deletes a photo and its copies now. Answers 204. | While the photo is kept. |
GET and PUT /api/v1/orbit/settings | Reads or changes Orbit's settings. The table is on Shop configuration. | A test key with the settings permission changes them. |
The three calls that start work (start, answers, retry) count towards a test key's daily cap. Cancelling and photo uploads do not. Safeguard can review a finished Orbit listing by its runId (see the Safeguard page).
Every error is JSON with error (what went wrong), code (a fixed name to branch on), tryThis (the next step) and sometimes problems (the exact fields at fault, as paths like /images/0). A 4xx error means fix the request. A 5xx error is a problem on PCIFIC's side, so try again.
Most errors also have a docs link to their own section on Orbit errors, with the usual causes, how to fix it and a request that works. That page starts with the mistakes integrations make most often.
Orbit's errors appear in three places. Refused straight away: the call answers with an HTTP error and nothing starts. Failed later: the listing was accepted with 202, then fails, and you see it when you read the listing, where status is failed and error holds the same body. Photo errors: ordinary validation refuses the upload and saves no photos. A decoder worker failure can instead return accepted images and per-photo problems with a successful upload. The errors every address can return (UNAUTHORIZED, KEY_NOT_ALLOWED, RATE_LIMITED, OUT_OF_CREDITS and the rest) are on the Errors, limits and retries page.
| Code | HTTP | Why it happens | How to fix |
|---|---|---|---|
INVALID_JSON | 400 | The body is not a JSON object. | Send a JSON object with the header "Content-Type: application/json". |
MODEL_TIER_INVALID | 400 | modelTier is not standard or ultra-fast. | Send modelTier: standard (the default) or ultra-fast, or leave it out. |
ORBIT_TURNED_OFF | 403 | Orbit is switched off for this account. | Switch it on in the dashboard, or send {"enabled": true} to PUT /api/v1/orbit/settings with a test key that has the settings permission. |
ORBIT_NO_SCHEMA | 409 | This account has no published listing fields, so Orbit has no fields to fill. | Upload a file for each category with PUT /api/v1/schema-draft/categories/{category}, then publish with POST /api/v1/schema-versions. |
INVALID_FIELD | 400 | A field has the wrong type or is too long: notes over 5,000 characters or not text, details not an object, images not a list of photo ids (or more than 12), category not text, price, safeguard or faq not true or false, or a price amount in details written as text, a decimal or an exponent. problems names each one. | Fix the field the message names, then send the request again. Send images as the ids POST /api/v1/images gave you. Send price amounts as whole numbers in pence, such as 4500 for £45. |
PHOTOS_NOT_FOUND | 422 | A photo id in images is unknown, belongs to another business, or has expired. problems names each one at /images/{n}. | Photos are kept for 30 minutes after upload. Upload each photo listed again with POST /api/v1/images and use the new ids. |
NOTHING_TO_LIST | 400 | notes, details and images are all empty, so there is nothing to list. | Send at least the seller's words in notes, for example "iPhone 17 Pro", or photo ids in images. |
NOTES_TOO_SHORT | 400 | notes is shorter than the business notesMinLength, even with photos or details. With both notes limits unset, notes under 4 characters are refused only without details or images. problems names /notes and the limit. | Send enough notes to meet the limit in the error. With both limits unset, send at least 4 characters or add photos or details. |
NOTES_TOO_LONG | 400 | notes exceeds this business's notesMaxLength. The error names /notes, its length and the business's limit, even with photos or details. | Shorten notes to the business's notesMaxLength and send the request again. |
PRICING_OFF | 409 | The request has price: true, but the price check is switched off for this account. | Switch it on with {"pricing": true} to PUT /api/v1/orbit/settings, or leave price out. |
SAFEGUARD_OFF | 409 | The request has safeguard: true or faq: true, but Safeguard is switched off for this account. | Switch it on with {"enabled": true} to PUT /api/v1/safeguard/settings, or leave the field out. |
CATEGORY_NOT_FOUND | 422 | category is not a category in your newest published listing fields. | Check the name against GET /api/v1/schema-versions/{version}, or leave category out and Orbit will find it. |
CURRENCY_NOT_IN_SCHEMA | 422 | A price field in this category does not allow your business's currency. Prices are never converted, so no listing could fit. | Add your currency to that price field's currency options and publish your listing fields again, or change currency with PUT /api/v1/orbit/settings. |
TEST_DAILY_CAP_REACHED | 429 | A test key's AI requests reached today's daily cap. The count starts again at midnight UTC. | Wait until midnight UTC, or raise the daily cap for test keys on the dashboard API keys page. |
| Code | HTTP | Why it happens | How to fix |
|---|---|---|---|
ORBIT_PROCESSING_EXPIRED | 409 | This runId has reached deadlineAt, so it has no processing time left and cannot be retried. No credit is reserved for the refused retry. | Start a new listing with POST /api/v1/listings using the seller's notes, details and unexpired photo ids. |
INVALID_FIELD | 400 | Answers call: answers is missing or empty, an answer has no id or answer text, an answer is over 1,000 characters, or one question is answered twice. | Send {"answers": [{"id": "q1", "answer": "256GB"}]} with one entry per question. An answer may be "I don't know". |
INVALID_FIELD | 400 | Outcome call: event is not published or abandoned, changes is not a list of at most 500 {field, percentChanged} entries, finalListing is over 200 KB or sent with abandoned, or abandoned has changes. | Fix the field named in problems. Send changes and finalListing only with published. |
ORBIT_TURNED_OFF | 403 | Orbit is switched off for this account. | Switch it on in the dashboard, or send {"enabled": true} to PUT /api/v1/orbit/settings with a test key that has the settings permission. |
NOT_FOUND | 404 | There is no listing with this id. Listings are deleted 30 minutes after their last change, and a listing waiting for answers 30 minutes after its questions. | Start the listing again with POST /api/v1/listings, and use the runId it answers with. |
LISTING_NOT_READY | 409 | The call does not fit where the listing is. Answers need status questions, retry needs failed, and cancel needs working, questions or failed. Sending the same answers twice at once also lands here for the second one. | Read the listing with GET /api/v1/listings/{runId} and do what its status says. |
UNKNOWN_QUESTION | 422 | An answer's id is not one of the listing's open questions. problems names it at /answers/{n}/id. | Answer each question by the id it came with in the questions list. A question can be answered once. |
ORBIT_STOPPED | 500 | Work on this listing stopped partway 3 times, or its saved progress could not be read back. This is a problem on PCIFIC's side. | Retry with POST /api/v1/listings/{runId}/retry. If it stops again, or the listing cannot be retried, start a new one with POST /api/v1/listings and contact PCIFIC support with the runId. |
OUTCOME_ALREADY_REPORTED | 409 | This listing's outcome was already reported. | Report each listing's outcome once. Nothing more is needed for this one. |
MONITORING_OFF | 409 | Orbit full monitoring is off for this business, so the listing outcome cannot be recorded. | Choose full monitoring for Orbit on the dashboard Privacy page, then start a new listing and report its outcome. |
Orbit photo uploads and PixelTrace checks and camera uploads share a photo capacity limit per server: 16 requests and 128 MB of uploaded bytes, with at most 2 requests and 64 MB per business across its shops and keys. These limits include receiving and processing. Content-Length reserves bytes before the body is read; without it the call reserves its maximum body size. Actual streamed bytes are counted too. Uploads must arrive within 120 seconds and wait at most 20 seconds for a photo worker. Public demos use separate capacity: 2 requests, 16 MB and one photo worker. Demo traffic cannot take paid photo places. A busy refusal does not save photos. Wait Retry-After seconds before sending the same upload again.
| Code | HTTP | Why it happens | How to fix |
|---|---|---|---|
PHOTO_UPLOAD_BUSINESS_BUSY | 429 | Your business has reached its photo request or byte capacity across Orbit and PixelTrace. | Wait the 20 seconds in Retry-After, then send the photo upload again. Send fewer uploads at the same time. |
PHOTO_UPLOAD_BUSY | 503 | The server's photo capacity is full, or a photo worker was not available within 20 seconds. | Wait the 20 seconds in Retry-After, then send the photo upload again. |
PHOTO_UPLOAD_TIMEOUT | 408 | The photo upload body did not finish arriving within 120 seconds. | Check your connection, then send the photo upload again. Send fewer photos per upload if needed. |
ORBIT_TURNED_OFF | 403 | Orbit is switched off for this account. | Switch it on in the dashboard, or send {"enabled": true} to PUT /api/v1/orbit/settings with a test key that has the settings permission. |
NOT_A_FORM | 400 | The body is not multipart/form-data. | Send each photo as a file field of a multipart/form-data body, for example with curl -F "photo=@IMG_0001.jpg". Do not turn the photos into base64 text. |
NO_PHOTOS | 400 | The form has no photos in it. | Add at least one file field to the form. |
TOO_MANY_PHOTOS | 422 | The form has more than 12 photos. | Send the 12 photos that show the item best. Several uploads are fine. |
PHOTOS_TOO_LARGE | 413 | The photos together are over 60 MB, or the form was cut short. | Send fewer photos per upload, several uploads are fine, or send each photo as the phone took it rather than a RAW export. |
PHOTOS_REFUSED | 422 | No photo was saved, because at least one could not be used: it is over 15 MB, over 60 megapixels, not a JPEG, PNG or WebP (iPhone HEIC and AVIF are refused), or damaged. problems names each one at /images/{n}. | Fix or leave out each photo listed, then send them all again. |
PHOTO_STORAGE_FAILED | 502 | PCIFIC could not store the photos. This is a problem on PCIFIC's side. | Send the photos again in a moment. If it keeps happening, contact PCIFIC support. |
GET and DELETE /api/v1/images/{id} answer 404 NOT_FOUND for a photo that is unknown or has expired. Upload it again.
| Code | HTTP | Why it happens | How to fix |
|---|---|---|---|
SAFEGUARD_TIMED_OUT | 504 | The listing reached its total processing ceiling before its Safeguard check finished. The draft is returned with pcific.safeguard.status failed and must be checked before publishing. | Keep the draft and request POST /api/v1/safeguard/reviews with its orbitRunId, then read that review before publishing. |
ORBIT_TIMED_OUT | 504 | Orbit made no progress for 30 seconds, or could not start within its queue allowance. Incoming answer text, tool-call arguments and completed steps reset the idle timer. Provider keep-alive pings do not. Finished parts are kept. The separate 3-minute total processing ceiling returns a partial listing with missing-field fixes. Seller-answer waiting does not count; retry does not extend the ceiling. | Retry with POST /api/v1/listings/{runId}/retry while processing time remains. After deadlineAt, start a new listing. |
ORBIT_STOPPED | 500 | Work on this listing stopped partway 3 times, or its saved progress could not be read back. This is a problem on PCIFIC's side. | Retry with POST /api/v1/listings/{runId}/retry. If it stops again, or the listing cannot be retried, start a new one with POST /api/v1/listings and contact PCIFIC support with the runId. |
ORBIT_UNFINISHED | 422 | Orbit could not finish the listing within its 14 steps or 6 submissions, or reached its total processing ceiling without a usable category or a partial listing that fits your fields. | Retry with POST /api/v1/listings/{runId}/retry. If it fails again, check that the category's listing fields allow what sellers describe, or start a new listing with more detail in the notes, such as the exact model and condition. |
ORBIT_NO_CATEGORY | 422 | Orbit found no category for the item, or the seller confirmed an item your shop does not sell. The error names your main categories. | If the item belongs in one of your categories, start a new listing with category set to it. If it is not something you sell, tell the seller. |
ORBIT_PHOTOS_DONT_MATCH | 422 | The photos and notes still disagree after asking the seller. The error names the different items when known. | Check the photos are of the item described, or update the description, then send it again. |
ORBIT_MODEL_FAILED | 502 | None of the AI models that Orbit tries finished the answer. This is a problem on PCIFIC's side. | Send the request again in a moment with a new POST /api/v1/listings. If it keeps happening, contact PCIFIC support. |
AI_PROVIDERS_BLOCKED | 503 | Every AI model that could answer is from a provider PCIFIC has blocked for your business. | Contact PCIFIC support to allow another AI provider for your business, then send the request again. |
CURRENCY_NOT_IN_SCHEMA | 422 | The category Orbit chose has a price field that does not allow your business's currency. Prices are never converted. | Add your currency to that price field's currency options and publish your listing fields again, or change currency with PUT /api/v1/orbit/settings. |
{
"status": "failed",
"processing": false,
"deadlineAt": "2026-10-15T10:01:00Z",
"parts": {
"listing": "failed",
"price": "off",
"safeguard": "off",
"faq": "off"
},
"publishReady": false,
"runId": "8d0e5f12-7a3c-4b96-8e41-c2d9a6f03b75",
"error": {
"error": "Orbit made no progress for 30 seconds while writing or checking this listing and stopped. Finished parts are kept.",
"code": "ORBIT_TIMED_OUT",
"tryThis": "Try it again with POST /api/v1/listings/8d0e5f12-7a3c-4b96-8e41-c2d9a6f03b75/retry. If it keeps happening, contact PCIFIC support with the listing's runId."
},
"retry": "POST /api/v1/listings/8d0e5f12-7a3c-4b96-8e41-c2d9a6f03b75/retry"
}A listing that fails is not charged. A test key's daily count is given back when the failure was on PCIFIC's side. A business on Bring Your Own can also see the BYO errors on that page.
| What | Limit |
|---|---|
| Photos per upload and per listing | 12 |
| Size of one photo / all photos in one upload | 15 MB / 60 MB |
| Photo type and size in pixels | JPEG, PNG or WebP, up to 60 megapixels (a 48 megapixel phone photo fits) |
| How long photos are kept | 30 minutes after upload, and 30 minutes after the listing using them finishes. Never deleted while a listing that is still going uses them |
| notes | 5,000 characters |
| One answer | 1,000 characters |
| Questions in one round / rounds of questions | 6 / 2 |
| How long a listing waits for answers | 30 minutes |
| How long a listing can be read | 30 minutes after its last change |
| Total processing time, including queue wait and checks | 180 seconds total; seller-answer waiting is excluded. Retry cannot extend it. |
| Drafting / pricing / Safeguard | Drafting uses the two clocks; pricing 35 seconds and Safeguard 30 seconds, inside the total ceiling |
| Idle timer | 30 seconds without an AI answer or completed step, then ORBIT_TIMED_OUT |
| Stopped worker detection | 12-second claim renewed every 4 seconds |
| Silent AI model | Backup after 8 seconds without answer content |
| Web searches for one listing / for one price check | 4 / 3 |
| Tries to submit a listing that fits your fields | 6, then ORBIT_UNFINISHED |
| Web pages the price check needs | At least 2 different pages with a real price |
| A finished listing waiting for its price check | None. Poll for updates |
| Requests a minute, daily cap on test keys, spend limits | See Errors, limits and retries and API keys and permissions |
| Word | Meaning |
|---|---|
| Listing fields | The facts a listing in your shop carries, set up once as a schema (a description of the fields and their types). |
| listing | One Orbit run, from the start call until its finished reply. It is read with its runId. |
| item | The part of a finished reply that holds your listing fields, filled in. Save this part. |
| runId | The id of one listing, returned when you start it. |
| Polling | Asking again on a timer until the answer is ready. |
| Source | Where a value came from: seller, photo, web or ai (Orbit's own wording, such as a title). |
| Quote | The seller's own words, kept with a value that only the seller may give. |
| Minor units | The smallest unit of a currency, such as pence or cents, so 5500 GBP is 55 pounds. |
| Multipart form | A web form that carries files, which is how photos are uploaded. |
| Idempotency-Key | A header that makes a request safe to send again. |