waiting_capacityAccepted and waiting for per-merchant or global ingestion capacity. Continue polling.
This is the complete public integration contract for sending official store offers to PriceInfo.
The stable HTTP namespace remains /api/merchant/v1; V2 names the asynchronous ingestion pipeline,
so existing integrations do not need a breaking URL migration.
GET /account and confirm that the target country appears in data.markets.POST /offers/bulk with a stable Idempotency-Key.202, store data.id. A successful HTTP response does not mean rows are already published.GET /imports/{job} until a terminal status, then read /errors when needed.curl --request POST \
https://priceinfo.eu/api/merchant/v1/offers/bulk \
--header "Authorization: Bearer pi_live_xxx" \
--header "Idempotency-Key: catalog-cz-2026-08-08-001" \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--data '{
"country": "CZ",
"items": [
{
"name": "Apple iPhone 15 128GB Black",
"url": "https://merchant.example/iphone-15-black",
"price": 18490,
"currency": "CZK",
"brand": "Apple",
"model": "iPhone 15 128GB",
"gtin": "195949036545",
"mpn": "MTP03ZD/A",
"availability": "in stock",
"delivery_price": 79,
"delivery_time": "1-2 days"
}
]
}' | Method | Path | Purpose |
|---|---|---|
GET | /account | Verify the API key and read the merchant, enabled markets, default currencies, and counters. |
GET | /feeds | List hosted feed configurations. Supports page and per_page. |
POST | /feeds | Create a pending hosted XML, CSV, or JSON feed configuration. |
GET | /feeds/{feed} | Read one merchant-owned feed configuration. |
PATCH | /feeds/{feed} | Update a feed URL, format, mapping, schedule, market, or status. |
POST | /feeds/{feed}/import | Queue a hosted feed import. |
POST | /offers | Queue one offer update through async ingestion V2. |
POST | /offers/bulk | Queue 1–100 offer updates through async ingestion V2. |
GET | /imports | List import jobs. Supports page and per_page. |
GET | /imports/{job} | Poll a merchant-owned import job and its counters. |
GET | /imports/{job}/errors | List row-level validation or import errors. |
All {feed} and {job} lookups are merchant-scoped. A record owned by another merchant returns 404.
POST /offers accepts one item with country on the item. POST /offers/bulk
accepts country once at request level and an items array containing 1–100 items.
| Field | Type | Location | Rule |
|---|---|---|---|
country | string(2) | Bulk request or single item | Required. ISO 3166-1 alpha-2 market enabled for the merchant. |
action | upsert | offline | Item | Optional; defaults to upsert. Offline still requires the item identity fields. |
name | string ≤ 500 | Item | Required. Store-facing product name. |
url | URL ≤ 2048 | Item | Required. Public product page in the merchant store. |
price | number ≥ 0 | Item | Required. Current price including tax where applicable. |
currency | string(3) | Item | Optional ISO 4217 code; the market currency is used when omitted. |
old_price | number ≥ 0 | Item | Optional previous or reference price. |
category | string ≤ 500 | Item | Optional merchant category path. |
brand | string ≤ 255 | Item | Strongly recommended for matching. |
model | string ≤ 255 | Item | Recommended model name. |
gtin | string ≤ 32 | Item | Strongly recommended EAN/UPC/GTIN identifier. |
mpn | string ≤ 255 | Item | Recommended manufacturer part number. |
image_url | URL ≤ 2048 | Item | Optional public product image URL. |
availability | string ≤ 120 | Item | Optional readable value such as in stock, out of stock, preorder, or unknown. |
delivery_price | number ≥ 0 | Item | Optional delivery price. |
delivery_time | string ≤ 120 | Item | Optional readable estimate such as 1-2 days. |
_meta | object | Item | Optional integration metadata. cms, opencart_product_id, and country are accepted. |
A valid offer is not automatically a new public product. Exact identifiers are matched first; uncertain identities increment
review_records and remain unavailable for publication until reviewed.
202, idempotency, and polling
Direct pushes return 202 Accepted. Generate one stable idempotency key for each logical batch and retain it until
the request result is known. Repeating the same merchant request with the same key returns the original job and sets
meta.idempotency_replay to true instead of inserting the batch twice.
Poll direct jobs every 2–10 seconds with exponential backoff. Poll hosted feed jobs every 10–30 seconds. Stop at
completed, completed_with_errors, or failed. Treat review_records as waiting for
PriceInfo review, not as a transport error.
HTTP/1.1 202 Accepted
Content-Type: application/json
{
"data": {
"id": 9002,
"type": "merchant_direct_api",
"source": "direct_api",
"status": "running",
"pipeline_version": "v2",
"counters": {
"total_records": 1,
"processed_records": 0,
"created_records": 0,
"updated_records": 0,
"review_records": 0,
"rejected_records": 0,
"error_count": 0
}
},
"meta": {
"accepted": true,
"idempotency_replay": false
}
} waiting_capacityAccepted and waiting for per-merchant or global ingestion capacity. Continue polling.
queuedAccepted and queued for preparation. Continue polling.
preparingThe hosted source is being downloaded, verified, and split into bounded chunks.
runningOne or more chunks are being processed.
completedTerminal success. All accepted rows were processed without rejected rows.
completed_with_errorsTerminal result. Read counters and /errors; successful rows remain applied.
failedTerminal failure. Inspect the job, correct the source or request, and submit a new logical batch.
Job counters are total_records, processed_records, created_records,
updated_records, review_records, rejected_records, and error_count.
Create a feed with name, two-letter country, format, and a public HTTPS
feed_url. Optional fields are mapping_preset, field_mapping_json, and
schedule_cron. New feeds always start as pending; they can become active after a completed validation import.
Supported presets are priceinfo, salidzini_like, heureka_like,
ceneo_like, and approved custom mappings. Use Heureka-like for common CZ/SK exports and Ceneo-like for common PL exports.
POST /feeds
{
"name": "Main CZ Heureka XML feed",
"country": "CZ",
"format": "xml",
"feed_url": "https://merchant.example/heureka.xml",
"mapping_preset": "heureka_like",
"schedule_cron": "0 * * * *"
} | Status | Meaning and client action |
|---|---|
200 | Read succeeded. |
201 | Hosted feed configuration created. |
202 | Import accepted. Save data.id and poll the job. |
401 | Bearer token is missing, inactive, expired, or belongs to an inactive merchant. |
404 | The feed or job does not exist or belongs to another merchant. |
409 | The hosted feed already has an active import; poll the returned job. |
422 | Validation failed or the merchant is not enabled for the requested market. |
429 | Quota exceeded. Wait for the Retry-After duration before retrying. |
500 | Unexpected server error. Retry later with exponential backoff. |
Laravel validation responses contain message and an errors object keyed by field. Import row errors contain
severity, record_reference, error_code, message, and raw_payload.
Do not retry unchanged 422 rows. For 429, obey the Retry-After response header.
| Scope | Per minute | Per hour | Items per day | Max items/request |
|---|---|---|---|---|
feeds.import | 3 requests | 20 requests | — | — |
offers.store | 60 requests | 1,000 requests | 5,000 | 1 |
offers.bulk | 20 requests | 200 requests | 25,000 | 100 |
These are contract defaults and may be adjusted for an approved merchant plan. A 429 response reports the exceeded scope, limit, reset time, and retry delay.