{"openapi":"3.1.0","jsonSchemaDialect":"https://spec.openapis.org/oas/3.1/dialect/base","info":{"title":"Poštárna API","version":"1.0.0","description":"Poštárna is a multi-tenant e-mail marketing platform with statistics for companies and e-shops (Czech and Slovak). This document describes every\nroute an integration can call. Guides in Czech and Slovak: https://www.postarna.cz/docs/api (index for AI agents:\nhttps://www.postarna.cz/llms.txt, everything in one Markdown file: https://www.postarna.cz/llms-full.txt).\n\n## Three APIs\n* **API v1** (`/api/v1/tenants/{tenant}/...`): the full API, the same one the Poštárna web app uses. JSON in UTF-8.\n* **SmartEmailing compatible API v3** (`/api/v3/...`) and its CSV statistics (`/api/csv/...`): the same paths,\n  envelopes and errors as SmartEmailing's REST API v3, so an existing SE integration only changes the address, the\n  user name and the key. Read operations plus account webhooks.\n* **MCP server** (`POST /mcp`): Model Context Protocol for AI assistants (ChatGPT, Claude, Cursor ...), OAuth 2.1 or an\n  API key.\n\n## Authentication\nCreate an API key in the app: Nastavení › Datové zdroje › API klíče (Settings › Data sources › API keys). The key\n(`pst_` + 43 characters) is shown once. Send it as `Authorization: Bearer pst_...`, or as HTTP Basic with the e-mail\nof an active member of the company as the user name and the key as the password (both work on v1 and v3). A key\nworks only in its own company (tenant), with the roles it was given (never more than its creator has), and with\nscope `full` (read and write) or `read` (only routes whose permission level is read). Keys never reach the members,\ninvitations, API keys and connected apps (those need a signed-in person: 403 `forbidden` / `api_key`).\n\n`{tenant}` in v1 paths is the company's public id (a UUID). Find it with `GET /api/v3/account-info` (`data.guid`) or\nin the app on the API keys page.\n\n## Conventions (API v1)\n* IDs are strings. Times are ISO 8601 in UTC with milliseconds (`2026-09-30T08:00:00.000Z`); local calendar days of\n  the company are `YYYY-MM-DD`; automation settings use local `YYYY-MM-DDTHH:MM` and `HH:MM`.\n* Money is a decimal string next to its `currency` (`\"1290.00\"`, `\"CZK\"`). CZK and EUR are never added up or\n  converted: every sum is per currency.\n* Lists are paged: `page` from 1, `pageSize` 1 to 100 (default 25); the answer is `{items, total, page, pageSize}`.\n  Some grids take `sort` (`name,-createdAt`, at most 3 fields, `-` = descending).\n* Request bodies of POST, PUT and PATCH are `application/json` (415 `validation` / `contentType` otherwise); CSV\n  import and file upload also take `multipart/form-data`. Unknown body fields are ignored.\n* Errors: `{\"error\": {\"code\": \"...\", \"message\": \"<field or detail>\", \"params\": {...}}}`. `code` is stable and\n  machine readable, `message` names the field or the reason, `params` carries details (for example the issues of an\n  automation graph). The API never sends texts for people.\n* No idempotency keys: retry only requests that are safe to repeat (GET, PUT of a whole object, DELETE). For POST,\n  read the state first (for example list the contacts by e-mail) before you retry after a timeout. Concurrent\n  edits of content and automation graphs are guarded by versions (`baseVersion`, 409 `conflict` / `version`).\n\n## Limits\nPer company (all keys together): a bucket of 2 500 requests refilled with 4 requests a second, and 100 000 requests a\nday (refilled continuously). Every answer to a key carries `X-RateLimit-Limit`, `X-RateLimit-Remaining` and\n`X-RateLimit-Reset` (unix time when the bucket is full again) of the bucket nearest to running out. Over the limit:\n429 `rate_limited` with `Retry-After` (seconds). Some actions have their own limits (test e-mails 10 per day per\ncampaign or template, contact events 60 per contact in 10 minutes, MCP 300 messages a minute).\n\n## Consent and sending\nPoštárna never e-mails a contact who unsubscribed, bounced, complained or is suppressed, and campaigns only reach\ncontacts with a valid marketing consent. Sending to real recipients (approving a campaign, activating an automation)\nis irreversible: check the audience first (`POST .../campaigns/audience`, `POST .../automations/{id}/test`). Test\ne-mails go only to the company's test addresses (`GET .../test-recipients`).\n","contact":{"name":"deriverge s.r.o.","url":"https://www.postarna.cz/docs/api"},"x-guides":{"cs":"https://www.postarna.cz/docs/api","sk":"https://www.postarna.sk/docs/api","llms":"https://www.postarna.cz/llms.txt","llmsFull":"https://www.postarna.cz/llms-full.txt"}},"servers":[{"url":"https://www.postarna.cz","description":"Production (the same API answers on www.postarna.sk)"}],"security":[{"bearerAuth":[]},{"basicAuth":[]}],"tags":[{"name":"Orders and feeds","x-displayName":"Orders, feeds and coupons","description":"Orders of the e-shops (they drive purchase triggers and conditions), order states, product and customer feeds, coupon stacks."}],"x-error-codes":{"conflict":{"meaning":"The change would break the state of the object. `message`: `name` (name taken), `locked` (a list bound to an e-shop), `status` (wrong state, e.g. editing a sent campaign), `recipients` (the audience changed more than 5 % since you counted it, `params.expected` and `params.actual`), `version` (stale `baseVersion`, `params.current`), `confirm` (saving a running automation needs `confirmRunning: true`), `waiting` (contacts wait in a node you remove, `params.nodes`), `runs` (deleting an automation that ran), `trigger` (no manual trigger), `limit` (too many objects).","fix":"Read the object again, then repeat with current data; for `recipients` count the audience again and send the new `expectedRecipients`."},"count_mismatch":{"meaning":"`expectedRecipients` does not match the audience.","fix":"Count again with `POST /campaigns/audience` and send the new number."},"csrf":{"meaning":"Browser session request without the CSRF header (never with an API key).","fix":"Send the API key in `Authorization` instead of cookies."},"empty_segment":{"meaning":"The campaign audience has no recipient.","fix":"Change the audience."},"expired":{"meaning":"The object is no longer available (an export file older than its retention).","fix":"Create it again (POST /exports)."},"forbidden":{"meaning":"The credentials are valid but not allowed here. `message`: `tenant` (another company in the path), `scope` (a read-only key on a write route), `api_key` (members, invitations and keys need a signed-in person), a module name (`contacts`, `campaigns`, `content`, `settings`, `billing`: the key's roles lack the level), `read_only` (support view).","fix":"Use the tenant id of the key (`GET /api/v3/account-info`), a key with scope `full`, or a key whose roles include the module (for example marketing_manager)."},"method_not_allowed":{"meaning":"The path exists but not with this HTTP method.","fix":"Check the method in this document."},"not_found":{"meaning":"The object does not exist in this company (objects of other companies answer the same).","fix":"Check the id; list the objects first."},"not_implemented":{"meaning":"The feature is not available yet.","fix":"Do not rely on it."},"rate_limited":{"meaning":"Too many requests: the company's API limit, or the limit of one action (test e-mails, contact events, sign-in attempts). `Retry-After` says after how many seconds to retry.","fix":"Wait `Retry-After` seconds; spread requests (4 a second sustained)."},"recently_sent":{"meaning":"HTTP 423: the contact cannot be deleted yet, a campaign e-mail to it is queued or went out in the last 24 hours (SmartEmailing answers the same).","fix":"Delete it after 24 hours. A request to be forgotten (GDPR) uses POST /contacts/{id}/erase, which is never refused."},"server":{"meaning":"Unexpected server error.","fix":"Retry later; the request may be repeated if it is safe to repeat."},"suppression_locked":{"meaning":"The address is suppressed for another reason (bounce, complaint, unsubscribe), so the blacklist cannot be added or removed; `params.reason` names it.","fix":"Leave it: such suppressions protect the sender and are removed only one by one (DELETE /suppressions/{email}) when the reason is gone."},"unauthorized":{"meaning":"No valid credentials: the API key is unknown, revoked, expired, idle for 180 days, its creator left the company, or the HTTP Basic user name is not an active member.","fix":"Check the key and the header (`Authorization: Bearer pst_...`). Create a new key in Nastavení › Datové zdroje › API klíče."},"unavailable":{"meaning":"A service the action needs is not available (`mail`: the mail backend refused a test e-mail, `data_key`: encryption key for webhook passwords missing).","fix":"Retry later; tell support when it persists."},"upstream":{"meaning":"An outside service failed (downloading a file by URL, the stock photo service); `params.reason` says why.","fix":"Check the URL or retry later."},"validation":{"meaning":"A parameter or body field is missing, has the wrong type or an invalid value. `message` names it (`email`, `definition.1.0.listId`, `graph` ...), `params` may carry details such as `params.issues` of an automation graph or `params.reason`.","fix":"Fix the named field. For 415 `contentType` send `Content-Type: application/json`; for `body` send a JSON object."}},"paths":{"/api/v1/tenants/{tenant}/coupon-stacks":{"get":{"operationId":"coupon_stacks_list","summary":"List coupon stacks","tags":["Orders and feeds"],"description":"Coupon code stacks with free, assigned and used counts.","parameters":[{"$ref":"#/components/parameters/tenant"}],"x-postarna-permission":{"module":"settings","level":"read","keyScope":"read or full"},"x-mcp-tool":"list_coupon_stacks","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/CouponStack"}}},"required":["items"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"coupon_stacks_create","summary":"Create a coupon stack","tags":["Orders and feeds"],"parameters":[{"$ref":"#/components/parameters/tenant"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CouponStackInput"},"examples":{"name-days-stack":{"summary":"docs/api-examples/name-days.json stack","value":{"name":"Svátek","shopId":"11","mergeKey":"svatek","note":"Sleva 15 % k svátku"}}}}}},"x-postarna-permission":{"module":"settings","level":"full","keyScope":"full"},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CouponStack"},"examples":{"name-days-stack":{"summary":"docs/api-examples/name-days.json stack","value":{"id":"11","name":"Svátek","shopId":"11","mergeKey":"svatek","tag":"{{coupon_svatek}}","note":"Sleva 15 % k svátku","counts":{"total":0,"free":0,"assigned":0,"used":0},"createdAt":"2026-10-01T08:00:00.000Z","updatedAt":"2026-10-01T08:00:00.000Z"}}}}}},"400":{"description":"`validation`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/tenants/{tenant}/coupon-stacks/{stack_id}":{"delete":{"operationId":"coupon_stacks_delete","summary":"Delete a coupon stack","tags":["Orders and feeds"],"parameters":[{"$ref":"#/components/parameters/tenant"},{"name":"stack_id","in":"path","required":true,"description":"Id of the stack (string of digits).","schema":{"type":"string"}}],"x-postarna-permission":{"module":"settings","level":"full","keyScope":"full"},"x-mcp-confirm":"delete","responses":{"204":{"description":"No content"},"400":{"description":"`validation`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"coupon_stacks_show","summary":"Get a coupon stack","tags":["Orders and feeds"],"parameters":[{"$ref":"#/components/parameters/tenant"},{"name":"stack_id","in":"path","required":true,"description":"Id of the stack (string of digits).","schema":{"type":"string"}}],"x-postarna-permission":{"module":"settings","level":"read","keyScope":"read or full"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"shopId":{"type":"string"},"mergeKey":{"type":"string"},"tag":{"type":"string","description":"Merge tag of the stack: {{coupon_<mergeKey>}}"},"note":{"type":"string"},"counts":{"type":"object","properties":{"total":{"type":"integer"},"free":{"type":"integer"},"assigned":{"type":"integer"},"used":{"type":"integer"}}},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"description":"routes_coupons.stack_json"},"examples":{"name-days-stack-show":{"summary":"docs/api-examples/name-days.json stack-show","value":{"id":"11","name":"Svátek","shopId":"11","mergeKey":"svatek","tag":"{{coupon_svatek}}","note":"Sleva 15 % k svátku","counts":{"total":3,"free":3,"assigned":0,"used":0},"createdAt":"2026-10-01T08:00:00.000Z","updatedAt":"2026-10-01T08:00:00.000Z"}}}}}},"400":{"description":"`validation`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/tenants/{tenant}/coupon-stacks/{stack_id}/assign":{"post":{"operationId":"coupon_stacks_assign","summary":"Give a coupon of a stack to a contact","tags":["Orders and feeds"],"description":"A new code of the stack for the contact, by hand (PZ-05: every assignment is a new code): 201, 409 empty.","parameters":[{"$ref":"#/components/parameters/tenant"},{"name":"stack_id","in":"path","required":true,"description":"Id of the stack (string of digits).","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"contactId":{}},"required":["contactId"]}}}},"x-postarna-permission":{"module":"contacts","level":"full","keyScope":"full"},"responses":{"201":{"description":"Created (200 when it already existed or nothing changed)","content":{"application/json":{"schema":{"type":"object","properties":{"change":{"type":"string","enum":["assigned","existing"]},"coupon":{"type":"object","properties":{"id":{"type":"string"},"code":{"type":"string"},"status":{"type":"string"},"assignedAt":{"type":["string","null"]},"usedAt":{"type":["string","null"]}}}}}}}},"200":{"description":"OK: it already existed or nothing changed","content":{"application/json":{"schema":{"type":"object","properties":{"change":{"type":"string","enum":["assigned","existing"]},"coupon":{"type":"object","properties":{"id":{"type":"string"},"code":{"type":"string"},"status":{"type":"string"},"assignedAt":{"type":["string","null"]},"usedAt":{"type":["string","null"]}}}}}}}},"400":{"description":"`validation` (message: contactId)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"`conflict` (message: empty)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/tenants/{tenant}/coupon-stacks/{stack_id}/codes":{"post":{"operationId":"coupon_stacks_import","summary":"Add coupon codes to a stack","tags":["Orders and feeds"],"description":"Adds codes ({codes: [...]} or {text: \"...\"}) to the stack: {counts, stack}.","parameters":[{"$ref":"#/components/parameters/tenant"},{"name":"stack_id","in":"path","required":true,"description":"Id of the stack (string of digits).","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string"}},"required":["text"]},"examples":{"name-days-codes":{"summary":"docs/api-examples/name-days.json codes","value":{"text":"SVATEK-7Q2K\nSVATEK-9P4M\nSVATEK-3X8D\n"}}}}}},"x-postarna-permission":{"module":"settings","level":"full","keyScope":"full"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CouponImportResult"},"examples":{"name-days-codes":{"summary":"docs/api-examples/name-days.json codes","value":{"counts":{"added":3,"duplicate":0,"invalid":0,"total":3},"stack":{"id":"11","name":"Svátek","shopId":"11","mergeKey":"svatek","tag":"{{coupon_svatek}}","note":"Sleva 15 % k svátku","counts":{"total":3,"free":3,"assigned":0,"used":0},"createdAt":"2026-10-01T08:00:00.000Z","updatedAt":"2026-10-01T08:00:00.000Z"}}}}}}},"400":{"description":"`validation` (message: codes)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/tenants/{tenant}/coupon-stacks/{stack_id}/coupons":{"get":{"operationId":"coupon_stacks_assigned","summary":"List coupons of a stack","tags":["Orders and feeds"],"description":"Codes of the stack handed out in a period, newest first (SmartEmailing: the magnifier of a stack, data.promo.assigned): ?from= and ?to= (YYYY-MM-DD, the tenant's calendar days, both included), ?status=assigned (not used yet) | used, ?q= (a code or an address), paging. Every item names the contact and the e-mail.","parameters":[{"$ref":"#/components/parameters/tenant"},{"name":"stack_id","in":"path","required":true,"description":"Id of the stack (string of digits).","schema":{"type":"string"}},{"name":"from","in":"query","required":false,"schema":{"type":"string"},"description":"Start of the period (YYYY-MM-DD local day, or ISO time where noted)."},{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/pageSize"},{"$ref":"#/components/parameters/q"},{"name":"status","in":"query","required":false,"schema":{"type":"string"},"description":"Status filter."},{"name":"to","in":"query","required":false,"schema":{"type":"string"},"description":"End of the period (YYYY-MM-DD local day, or ISO time where noted)."}],"x-postarna-permission":{"module":"contacts","level":"read","keyScope":"read or full"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/StackCoupon"}},"total":{"type":"number"},"page":{"type":"number"},"pageSize":{"type":"number"}},"required":["items","total","page","pageSize"]}}}},"400":{"description":"`validation` (message: q, status, to)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/tenants/{tenant}/coupon-stacks/{stack_id}/used":{"post":{"operationId":"coupon_stacks_used","summary":"Mark coupons as used","tags":["Orders and feeds"],"description":"Marks codes the shop reports used: {marked, already, unknown, stack}.","parameters":[{"$ref":"#/components/parameters/tenant"},{"name":"stack_id","in":"path","required":true,"description":"Id of the stack (string of digits).","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string"}},"required":["text"]}}}},"x-postarna-permission":{"module":"settings","level":"full","keyScope":"full"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CouponUsedResult"}}}},"400":{"description":"`validation` (message: codes)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/tenants/{tenant}/feed-articles":{"get":{"operationId":"feed_articles_search","summary":"Search articles of the article feeds","tags":["Orders and feeds"],"description":"Articles of the article feeds (kind articles, migration 0130) for the editor's element Články FEED: ?shopId=, ?feedId=, ?q= (title or perex contains, accents ignored), ?ids= (comma separated article ids, at most 100, also articles no longer in their feed), ?limit= 1 to 60 (default 24), ?offset=. {items, total, feeds}.\n\nContract notes (cs):\n\nVýběr článků pro prvek Články FEED Magic editoru: články článkových feedů (`kind` `articles`, RSS 2.0 nebo Atom 1.0, migrace 0130; feed se zakládá v Nastavení › Feedy jako ostatní a stahuje se stejně). `shopId`, `feedId` (jen článkový feed tenanta, jinak 400), `q` (název nebo perex, bez diakritiky), `ids` (přesná id článků, i ty, které už ve feedu nejsou), `limit` 1 až 60, `offset` → `{ \"items\": [ { \"id\", \"feedId\", \"shopId\", \"itemId\", \"title\", \"url\", \"perex\", \"imageUrl\", \"publishedAt\", \"inFeed\" } ], \"total\", \"feeds\" }`. `itemId` = `guid` / `id` článku, jinak odkaz; `perex` = prostý text popisu (nejvýš 500 znaků), `imageUrl` = obrázek z `enclosure`, `media:content` / `media:thumbnail` nebo první `<img>` popisu. Do produktového výběru (`feed-products`) se články nikdy nedostanou.","parameters":[{"$ref":"#/components/parameters/tenant"},{"name":"feedId","in":"query","required":false,"schema":{"type":"string"}},{"name":"ids","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"string"}},{"name":"offset","in":"query","required":false,"schema":{"type":"string"}},{"$ref":"#/components/parameters/q"},{"name":"shopId","in":"query","required":false,"schema":{"type":"string"}}],"x-postarna-permission":{"module":"content","level":"read","keyScope":"read or full"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedArticleList"}}}},"400":{"description":"`validation` (message: feedId, ids, q)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/tenants/{tenant}/feed-products":{"get":{"operationId":"feed_products_search","summary":"Search products of the product feeds","tags":["Orders and feeds"],"description":"?shopId= (optional), ?q= (title, g:id, code or brand contains, case and accents ignored), ?ids= (comma separated g:id values, at most 100: exact matches including products no longer in their feed), ?limit= 1 to 60 (default 24), ?offset=. Answers {items, total, feeds}.\n\nContract notes (cs):\n\nVýběr produktů v Magic editoru (blok Feed a produkty). Hledá v produktech produktových feedů tenanta (`google_products`).\n• Parametry: `shopId` (nepovinně, jen feedy e-shopu; e-shop jiného tenanta 400 `shopId`), `q` (část názvu `title`, `g:id`, kódu nebo značky `g:brand`, bez ohledu na velká písmena a českou a slovenskou diakritiku; do 200 znaků), `ids` (až 100 hodnot `g:id` oddělených čárkou: přesná shoda, vrátí i produkty, které už ve feedu nejsou, `inFeed` false, aby editor obnovil vložené produkty; prázdné nebo víc než 100 = 400 `ids`), `limit` 1 až 60 (výchozí 24), `offset` (od 0). Bez `ids` jen produkty, které ve feedu jsou. Řazení: produkty ve feedu první, pak podle feedu a pořadí ve feedu.\n• Odpověď `{ \"items\": [FeedProduct], \"total\", \"feeds\": [ { \"id\", \"name\", \"shopId\", \"currency\", \"itemCount\", \"refreshedAt\", \"importedAt\", \"refreshError\" } ] }`; `feeds` = všechny produktové feedy tenanta (s `shopId` jen toho e-shopu), protože uživatel obsahu nastavení feedů nečte.\n• `FeedProduct` = `{ \"id\", \"feedId\", \"shopId\", \"itemId\", \"code\", \"name\", \"url\", \"imageUrl\", \"price\", \"regularPrice\", \"currency\", \"priceText\", \"priceCurrencyMismatch\", \"availability\", \"brand\", \"shortDescription\", \"values\", \"inFeed\", \"updatedAt\" }`: `itemId` = `g:id`, `code` = kód podle párování `se-id`, `name` = `title`, `url` = `link`, `imageUrl` = první `g:image_link`, jinak první `g:additional_image_link`, `brand` = `g:brand`, `priceText` = text `g:price`, jak je ve feedu, `shortDescription` = krátký prostý text popisu, `values` = spárované parametry feedu po formátování (Párování feedu, např. `se-product`, `se-price-vat`, vlastní názvy; chybějící pole = `''`, hodnota nejvýš 1 000 znaků): část položky feedu v editoru může ukázat kterýkoli z nich (Párovat feed, ED-19). Celý popis ani jiná velká pole se nevrací.\n• Ceny: `price` a `regularPrice` jsou čísla (nejvýš 2 desetinná místa) v měně e-shopu (`currency`, CZK nebo EUR, nikdy se nepřevádí). Je-li `g:sale_price` a dá se přečíst, `price` = akční cena a `regularPrice` = `g:price`, jinak `price` = `g:price` a `regularPrice` = `null`. Čte se „515 CZK“, „515.00 CZK“, „12,90 EUR“, „1 299 CZK“: čárka nebo tečka s 1 až 2 číslicemi na konci je desetinná, jinak oddělují tisíce (samotná tečka se 3 číslicemi je podle Google desetinná). Text bez čísla = `null`. Má-li text jinou měnu než e-shop, číslo se vrátí a `priceCurrencyMismatch` je `true`.\n• `availability`: `in_stock`, `out_of_stock`, `preorder`, `backorder` (z Google `in stock`, `out of stock`, `preorder`, `backorder` i zápisů s podtržítkem), jinak `''`.","parameters":[{"$ref":"#/components/parameters/tenant"},{"name":"ids","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"string"}},{"name":"offset","in":"query","required":false,"schema":{"type":"string"}},{"$ref":"#/components/parameters/q"},{"name":"shopId","in":"query","required":false,"schema":{"type":"string"}}],"x-postarna-permission":{"module":"content","level":"read","keyScope":"read or full"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedProductList"}}}},"400":{"description":"`validation` (message: ids, q)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/tenants/{tenant}/feeds":{"get":{"operationId":"feeds_list","summary":"List feeds","tags":["Orders and feeds"],"parameters":[{"$ref":"#/components/parameters/tenant"}],"x-postarna-permission":{"module":"settings","level":"read","keyScope":"read or full"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedList"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"feeds_create","summary":"Create a feed","tags":["Orders and feeds"],"description":"Contract notes (cs):\n\n• `GET` vrací `{items: Feed[], defaultPairing}`.\n• `POST {name, shopId, kind?, url?, autoRefresh?, pairing?}` vrací 201 `Feed`. Duplicitní název končí 409 `conflict`.\n• `kind` (migrace 0091): `google_products` (výchozí, produktový feed Google Merchant XML, nejvýš 20 MB) nebo `shop_customers` (export zákazníků e-shopu, CSV nebo XML ze Shoptetu, nejvýš 100 MB). Druh se po založení nemění. Feed zákazníků nemá párování (`pairing` = `[]`, poslané párování = 400 `pairing` s `reason` `not_applicable`) ani náhled.\n• `Feed` má navíc `refreshReason` (kód chyby posledního stažení, `''` = bez chyby), `refreshDetected` (co dokument připomínal, `''` = nevíme) a `maxBytes` (limit druhu). Texty pro lidi skládá UI z kódů.\n• `format` (migrace 0241, jen `kind` `google_products`): `google` (výchozí, Google Merchant XML), `heureka` (Heureka.cz XML) nebo `zbozi` (Zboží.cz XML). Po založení se nemění, `Feed` ho vrací vždy (ostatní druhy `google`). Položky Heureka a Zboží si nechají své prvky a dostanou i názvy Google (`g:id` z `ITEM_ID`, `title` z `PRODUCTNAME` nebo `PRODUCT`, `link` z `URL`, `g:image_link`, `g:additional_image_link`, `g:brand`, `g:product_type`, `g:gtin`, `g:item_group_id`, `g:mpn`, `g:price` z `PRICE_VAT` s měnou e-shopu, `g:availability` z `DELIVERY_DATE`), takže párování, výběr produktů i objednávky fungují stejně. Dokument jiného formátu vrací 400 `xml` s `reason` `not_shop_xml` a `detected`. Jiný `format` = 400 `format` (`invalid`), formát u jiného druhu = 400 `format` (`not_applicable`).\n• `PATCH {name?, url?, autoRefresh?, pairing?}`. Párování musí obsahovat `se-id`. Jméno parametru jsou malá písmena, číslice a pomlčky, pole feedu `g:id`, `title` a podobně. Chyba vrací 400 s `params.reason` (`se_id_required`, `name`, `field`, `duplicate`).\n• `url` (`http://` nebo `https://`): se zapnutým `autoRefresh` ho worker stáhne jednou za 24 h a naimportuje; poslední pokus a jeho chyba jsou v `refreshedAt` a `refreshError` (`''` = naimportováno). `refreshError` má tvar `<kód>` nebo `<pole>: <kód>[: <zjištěný formát>]`, např. `too_large`, `http_404`, `xml: wrong_kind: customers_csv`.\n• Kódy (`refreshReason`, `params.reason`): `wrong_kind` (dokument je druhý druh feedu), `not_google_products`, `not_customers`, `unsupported_format` (HTML, JSON, Excel, ZIP, PDF, binární data), `too_large`, `too_many_items`, `required`, `doctype`, `invalid`, `scheme`, `address`, `dns`, `network`, `http_<status>`. Zjištěný formát (`refreshDetected`, `params.detected`): `customers_csv`, `customers_xml`, `google_products`, `heureka_xml`, `products_csv`, `orders_csv`, `orders_xml`, `csv`, `xml`, `text`, `html`, `json`, `xlsx`, `xls`, `zip`, `gzip`, `pdf`, `binary`.\n• Stažení přes limit druhu: když prvních 64 kB ukáže druhý druh feedu nebo nepodporovaný formát, uloží se tento kód místo `too_large`.\n• Změny (`POST`, `PATCH`, `DELETE`, import) zapisují audit `feed_created`, `feed_changed`, `feed_deleted`, `feed_imported` (jen id, druh, názvy polí a počty, nikdy adresa ani data). API klíč s plným přístupem smí jako dosud, klíč jen ke čtení jen `GET`.\n\n• `kind` `shop_orders` (migrace 0097): export objednávek e-shopu (Shoptet orders.csv, jeden řádek na položku), nejvýš jeden na e-shop (druhý = 409 `conflict`, `message` `shopId`), nejvýš 200 MB, bez párování a náhledu, stahuje se každou hodinu. První import je historie a nespustí žádnou automatizaci, potom jen objednávky nejvýš 2 dny staré (docs/api.md, Feed objednávek). `Feed` má `historyAt` (konec prvního importu, `null` = další import je historie) a `lastCounts` (`created`, `updated`, `unchanged`, `skipped`, `invalid`, `wrongCurrency`, `events`, `total`, `history`; `{}` před prvním). Kód chyby navíc `not_orders`.\n• `url` se v odpovědích vrací s maskovanými tajnými parametry (`hash=********9f3a`); `PATCH` s maskovanou hodnotou adresu nemění.","parameters":[{"$ref":"#/components/parameters/tenant"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedInput"}}}},"x-postarna-permission":{"module":"settings","level":"full","keyScope":"full"},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Feed"}}}},"400":{"description":"`validation`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/tenants/{tenant}/feeds/{feed_id}":{"delete":{"operationId":"feeds_delete","summary":"Delete a feed","tags":["Orders and feeds"],"description":"Contract notes (cs):\n\n• `GET` vrací `{items: Feed[], defaultPairing}`.\n• `POST {name, shopId, kind?, url?, autoRefresh?, pairing?}` vrací 201 `Feed`. Duplicitní název končí 409 `conflict`.\n• `kind` (migrace 0091): `google_products` (výchozí, produktový feed Google Merchant XML, nejvýš 20 MB) nebo `shop_customers` (export zákazníků e-shopu, CSV nebo XML ze Shoptetu, nejvýš 100 MB). Druh se po založení nemění. Feed zákazníků nemá párování (`pairing` = `[]`, poslané párování = 400 `pairing` s `reason` `not_applicable`) ani náhled.\n• `Feed` má navíc `refreshReason` (kód chyby posledního stažení, `''` = bez chyby), `refreshDetected` (co dokument připomínal, `''` = nevíme) a `maxBytes` (limit druhu). Texty pro lidi skládá UI z kódů.\n• `format` (migrace 0241, jen `kind` `google_products`): `google` (výchozí, Google Merchant XML), `heureka` (Heureka.cz XML) nebo `zbozi` (Zboží.cz XML). Po založení se nemění, `Feed` ho vrací vždy (ostatní druhy `google`). Položky Heureka a Zboží si nechají své prvky a dostanou i názvy Google (`g:id` z `ITEM_ID`, `title` z `PRODUCTNAME` nebo `PRODUCT`, `link` z `URL`, `g:image_link`, `g:additional_image_link`, `g:brand`, `g:product_type`, `g:gtin`, `g:item_group_id`, `g:mpn`, `g:price` z `PRICE_VAT` s měnou e-shopu, `g:availability` z `DELIVERY_DATE`), takže párování, výběr produktů i objednávky fungují stejně. Dokument jiného formátu vrací 400 `xml` s `reason` `not_shop_xml` a `detected`. Jiný `format` = 400 `format` (`invalid`), formát u jiného druhu = 400 `format` (`not_applicable`).\n• `PATCH {name?, url?, autoRefresh?, pairing?}`. Párování musí obsahovat `se-id`. Jméno parametru jsou malá písmena, číslice a pomlčky, pole feedu `g:id`, `title` a podobně. Chyba vrací 400 s `params.reason` (`se_id_required`, `name`, `field`, `duplicate`).\n• `url` (`http://` nebo `https://`): se zapnutým `autoRefresh` ho worker stáhne jednou za 24 h a naimportuje; poslední pokus a jeho chyba jsou v `refreshedAt` a `refreshError` (`''` = naimportováno). `refreshError` má tvar `<kód>` nebo `<pole>: <kód>[: <zjištěný formát>]`, např. `too_large`, `http_404`, `xml: wrong_kind: customers_csv`.\n• Kódy (`refreshReason`, `params.reason`): `wrong_kind` (dokument je druhý druh feedu), `not_google_products`, `not_customers`, `unsupported_format` (HTML, JSON, Excel, ZIP, PDF, binární data), `too_large`, `too_many_items`, `required`, `doctype`, `invalid`, `scheme`, `address`, `dns`, `network`, `http_<status>`. Zjištěný formát (`refreshDetected`, `params.detected`): `customers_csv`, `customers_xml`, `google_products`, `heureka_xml`, `products_csv`, `orders_csv`, `orders_xml`, `csv`, `xml`, `text`, `html`, `json`, `xlsx`, `xls`, `zip`, `gzip`, `pdf`, `binary`.\n• Stažení přes limit druhu: když prvních 64 kB ukáže druhý druh feedu nebo nepodporovaný formát, uloží se tento kód místo `too_large`.\n• Změny (`POST`, `PATCH`, `DELETE`, import) zapisují audit `feed_created`, `feed_changed`, `feed_deleted`, `feed_imported` (jen id, druh, názvy polí a počty, nikdy adresa ani data). API klíč s plným přístupem smí jako dosud, klíč jen ke čtení jen `GET`.\n\n• `kind` `shop_orders` (migrace 0097): export objednávek e-shopu (Shoptet orders.csv, jeden řádek na položku), nejvýš jeden na e-shop (druhý = 409 `conflict`, `message` `shopId`), nejvýš 200 MB, bez párování a náhledu, stahuje se každou hodinu. První import je historie a nespustí žádnou automatizaci, potom jen objednávky nejvýš 2 dny staré (docs/api.md, Feed objednávek). `Feed` má `historyAt` (konec prvního importu, `null` = další import je historie) a `lastCounts` (`created`, `updated`, `unchanged`, `skipped`, `invalid`, `wrongCurrency`, `events`, `total`, `history`; `{}` před prvním). Kód chyby navíc `not_orders`.\n• `url` se v odpovědích vrací s maskovanými tajnými parametry (`hash=********9f3a`); `PATCH` s maskovanou hodnotou adresu nemění.","parameters":[{"$ref":"#/components/parameters/tenant"},{"name":"feed_id","in":"path","required":true,"description":"Id of the feed (string of digits).","schema":{"type":"string"}}],"x-postarna-permission":{"module":"settings","level":"full","keyScope":"full"},"x-mcp-confirm":"delete","responses":{"204":{"description":"No content"},"400":{"description":"`validation`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"feeds_show","summary":"Get a feed","tags":["Orders and feeds"],"parameters":[{"$ref":"#/components/parameters/tenant"},{"name":"feed_id","in":"path","required":true,"description":"Id of the feed (string of digits).","schema":{"type":"string"}}],"x-postarna-permission":{"module":"settings","level":"read","keyScope":"read or full"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Feed"}}}},"400":{"description":"`validation`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"patch":{"operationId":"feeds_update","summary":"Update a feed","tags":["Orders and feeds"],"parameters":[{"$ref":"#/components/parameters/tenant"},{"name":"feed_id","in":"path","required":true,"description":"Id of the feed (string of digits).","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"kind":{"type":"string","enum":["google_products","shop_customers","shop_orders","articles"]},"format":{"type":"string","enum":["google","heureka","zbozi"],"description":"Only with kind google_products; fixed once the feed exists."},"url":{"type":"string"},"autoRefresh":{"type":"boolean"},"pairing":{"type":"array","items":{"$ref":"#/components/schemas/FeedPairing"}}}}}}},"x-postarna-permission":{"module":"settings","level":"full","keyScope":"full"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Feed"}}}},"400":{"description":"`validation`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/tenants/{tenant}/feeds/{feed_id}/import":{"post":{"operationId":"feeds_import","summary":"Import a feed file by upload","tags":["Orders and feeds"],"description":"Imports the document in exactly one of {\"xml\": text}, {\"content\": text} or {\"contentBase64\": base64 of the file's bytes}; a refused document changes nothing (400 with the reason and the detected format).\n\nContract notes (cs):\n\nPrávě jedno z `{xml}` (text), `{content}` (text) nebo `{contentBase64}` (bajty souboru v base64, aby server poznal kódování CSV), vše do 5 MB těla požadavku → `{counts: {created, updated, unchanged, removed, skipped, total}, feed}`. Před importem se obsah očichá: dokument jiného druhu nebo formátu vrací 400 s `message` = `xml` (produktový feed) nebo `file` (feed zákazníků) a `params: {reason, detected?}`, např. `{reason: wrong_kind, detected: customers_csv}`. Dokument s DOCTYPE nebo ENTITY a rozbité XML vrací 400 (`params.reason`) a nic nemění. Produkty, které z feedu zmizely, zůstávají pro staré objednávky.\n• Feed zákazníků: záznamy se uloží do zákazníků e-shopu stejně jako z konektoru (`customers.save_customer`, podle e-shopu a externího id; opakovaný import nic nezapíše). Nikdy nevznikne kontakt, souhlas ani potlačení. Sloupce, které export nemá, si zachovají uloženou hodnotu, stejně jako příznak smazání z konektoru. `removed` je vždy 0 (export nemá náhrobky). `skipped` = záznam bez id i platné adresy nebo opakované id.","parameters":[{"$ref":"#/components/parameters/tenant"},{"name":"feed_id","in":"path","required":true,"description":"Id of the feed (string of digits).","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"xml":{"type":"string"}},"required":["xml"]}}}},"x-postarna-permission":{"module":"settings","level":"full","keyScope":"full"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedImportResult"}}}},"400":{"description":"`validation` (message: content, contentBase64)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/tenants/{tenant}/feeds/{feed_id}/items":{"get":{"operationId":"feeds_items","summary":"List items of a feed","tags":["Orders and feeds"],"description":"Položky feedu (SE's product-item-list): the items of a product or article feed still in it, in feed order, ?q= (item id, code or any value, accents ignored), ?page=, ?pageSize= (at most 100). Customer and order feeds keep no items (400 validation kind). {items: [{id, itemId, code, data, values, updatedAt}], total, page, pageSize}; values are the paired parameters after their formatters (product feeds).\n\nContract notes (cs):\n\nPoložky feedu (SE product-item-list): produkty produktového feedu nebo články článkového feedu, které ve feedu jsou, v pořadí feedu. `q` (id položky, kód nebo jakákoli hodnota, bez diakritiky, do 200 znaků), `page`, `pageSize` (nejvýš 100) → `Page<{id, itemId, code, data, values, updatedAt}>`; `values` = hodnoty párování po formátovačích (u článků `{}`), `updatedAt` = poslední import položky. Feed zákazníků a objednávek položky nemá: 400 `kind` s `reason` `not_applicable`.","parameters":[{"$ref":"#/components/parameters/tenant"},{"name":"feed_id","in":"path","required":true,"description":"Id of the feed (string of digits).","schema":{"type":"string"}},{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/pageSize"},{"$ref":"#/components/parameters/q"}],"x-postarna-permission":{"module":"settings","level":"read","keyScope":"read or full"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/FeedItem"}},"total":{"type":"number"},"page":{"type":"number"},"pageSize":{"type":"number"}},"required":["items","total","page","pageSize"]}}}},"400":{"description":"`validation` (message: kind, q)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/tenants/{tenant}/feeds/{feed_id}/preview":{"get":{"operationId":"feeds_preview","summary":"Preview a feed (first items, detected fields)","tags":["Orders and feeds"],"description":"One product of the feed (?index=, from 0) with its paired values and the field names of the feed.\n\nContract notes (cs):\n\nJen produktový feed (feed zákazníků vrací 400 `kind` s `reason` `not_applicable`). `index` (od 0) → `{index, total, item, values, fields}` pro obrazovku Párování: syrový produkt, hodnoty podle párování (po formátovačích, měna `feed` = měna e-shopu feedu) a názvy polí feedu.","parameters":[{"$ref":"#/components/parameters/tenant"},{"name":"feed_id","in":"path","required":true,"description":"Id of the feed (string of digits).","schema":{"type":"string"}},{"name":"index","in":"query","required":false,"schema":{"type":"string"}}],"x-postarna-permission":{"module":"settings","level":"read","keyScope":"read or full"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedPreview"}}}},"400":{"description":"`validation` (message: kind)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/tenants/{tenant}/feeds/{feed_id}/refresh":{"post":{"operationId":"feeds_refresh","summary":"Download and process a feed now","tags":["Orders and feeds"],"description":"Queues a download of the feed's URL now (the worker runs it): {\"state\": \"queued\" | \"running\", \"feed\": ...}; 400 validation url when the feed has no URL.\n\nContract notes (cs):\n\nNačíst teď: zařadí stažení adresy feedu hned (úloha workeru; už zařazené stažení posune na teď). 202 `{state: queued | running, feed}`, feed bez adresy 400 `validation` `url` (`reason` `required`). Audit `feed_refresh_queued`. Modul nastavení, plný přístup.","parameters":[{"$ref":"#/components/parameters/tenant"},{"name":"feed_id","in":"path","required":true,"description":"Id of the feed (string of digits).","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"}}}},"x-postarna-permission":{"module":"settings","level":"full","keyScope":"full"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedRefreshResult"}}}},"400":{"description":"`validation` (message: url)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/tenants/{tenant}/order-states":{"get":{"operationId":"order_states_show","summary":"Get the order state mapping","tags":["Orders and feeds"],"description":"Contract notes (cs):\n\n`GET` vrací `{states, items: [{sourceStatus, match: exact | prefix, state}], seen: [{sourceStatus, shopId, orders, state, origin: map | shop | none | invalid}]}`. `PUT {items}` pravidla nahradí, přemapuje uložené objednávky a vrátí totéž plus `changed`. Pravidla nerozlišují velikost písmen a mezery a názvy mají nejvýš 80 znaků. Delší název stavu v objednávce je chyba synchronizace: stav `other` a záznam v logu.","parameters":[{"$ref":"#/components/parameters/tenant"}],"x-postarna-permission":{"module":"settings","level":"read","keyScope":"read or full"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"states":{"type":"array","items":{"type":"string"},"description":"Canonical states: new, unpaid, paid, processing, shipped, pickup, delivered, cancelled, returned, other (unknown)."},"items":{"type":"array","items":{"$ref":"#/components/schemas/OrderStateRule"}},"seen":{"type":"array","description":"State names seen in orders with their effective state.","items":{"type":"object","properties":{"sourceStatus":{"type":"string"},"shopId":{"type":"string"},"orders":{"type":"integer"},"state":{"type":"string"},"origin":{"type":"string","enum":["map","shop","none","invalid"]}}}}},"description":"routes_orders.state_map_json"},"examples":{"post-purchase-order-states":{"summary":"docs/api-examples/post-purchase.json order-states","value":{"states":["new","unpaid","paid","processing","shipped","delivered","cancelled","returned","other"],"items":[],"seen":[]}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"put":{"operationId":"order_states_replace","summary":"Replace the order state mapping","tags":["Orders and feeds"],"description":"Replaces the rules and re-maps the stored orders (no order events).\n\nContract notes (cs):\n\n`GET` vrací `{states, items: [{sourceStatus, match: exact | prefix, state}], seen: [{sourceStatus, shopId, orders, state, origin: map | shop | none | invalid}]}`. `PUT {items}` pravidla nahradí, přemapuje uložené objednávky a vrátí totéž plus `changed`. Pravidla nerozlišují velikost písmen a mezery a názvy mají nejvýš 80 znaků. Delší název stavu v objednávce je chyba synchronizace: stav `other` a záznam v logu.","parameters":[{"$ref":"#/components/parameters/tenant"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","maxItems":500,"items":{"$ref":"#/components/schemas/OrderStateRule"},"description":"The new rules (replace all)."}},"required":["items"]}}},"description":"Required by the server: items."},"x-postarna-permission":{"module":"settings","level":"full","keyScope":"full"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"states":{"type":"array","items":{"type":"string"},"description":"Canonical states: new, unpaid, paid, processing, shipped, pickup, delivered, cancelled, returned, other (unknown)."},"items":{"type":"array","items":{"$ref":"#/components/schemas/OrderStateRule"}},"seen":{"type":"array","description":"State names seen in orders with their effective state.","items":{"type":"object","properties":{"sourceStatus":{"type":"string"},"shopId":{"type":"string"},"orders":{"type":"integer"},"state":{"type":"string"},"origin":{"type":"string","enum":["map","shop","none","invalid"]}}}},"changed":{"type":"integer"}},"description":"routes_orders.state_map_json"}}}},"400":{"description":"`validation`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/tenants/{tenant}/orders":{"get":{"operationId":"orders_list","summary":"List orders","tags":["Orders and feeds"],"description":"Orders, filtered by contact, shop, state or text. Money per currency, never summed across currencies.\n\nContract notes (cs):\n\n`contactId`, `shop`, `state`, `q` (kód objednávky, id nebo e-mail), `page`, `pageSize` → `Page<Order>` bez smazaných objednávek, nejnovější první, u každé jen první 3 položky. Cizí nebo neznámý `contactId` vrací 400.","parameters":[{"$ref":"#/components/parameters/tenant"},{"name":"contactId","in":"query","required":false,"schema":{"type":"string"},"description":"Contact id."},{"$ref":"#/components/parameters/page"},{"$ref":"#/components/parameters/pageSize"},{"name":"q","in":"query","required":false,"schema":{"type":"string","maxLength":200},"description":"Search text."},{"name":"shop","in":"query","required":false,"schema":{"type":"string"},"description":"Shop id filter."},{"name":"state","in":"query","required":false,"schema":{"type":"string"},"description":"Order state."}],"x-postarna-permission":{"module":"contacts","level":"read","keyScope":"read or full"},"x-mcp-tool":"list_contact_orders","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Order"}},"total":{"type":"number"},"page":{"type":"number"},"pageSize":{"type":"number"}},"required":["items","total","page","pageSize"]}}}},"400":{"description":"`validation` (message: contactId, q, state)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"orders_save","summary":"Create or update an order","tags":["Orders and feeds"],"description":"Creates or updates one order by (shop, id): 201 created, 200 updated or unchanged.\n\nContract notes (cs):\n\nSchéma Orders API SE: `{id, shopId, createdAt, paidAt?, email? | contactId?, status, eshopCode?, orderUrl?, currency?, totalWithVat?, totalWithoutVat?, companyId?, deleted?, seller?, orderDelivery?, items: [{id, name, description?, price: {withVat?, withoutVat?, currency?}, quantity?, unit?, url?, imageUrl?, attributes?}]}`. `status` je název stavu v e-shopu. Odpověď je `{change, order}`: 201 `created`, nebo 200 `updated` / `unchanged` (opakované doručení nic nezapíše). Kupující bez kontaktu dostane kontakt ve stavu `customer`. Chyby: 400 `validation` s `message` = pole (`order` s `params.reason`, `items`, `shopId`, `contactId` nebo neznámý klíč).","parameters":[{"$ref":"#/components/parameters/tenant"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":["string","integer"],"description":"Order id in the e-shop (1 to 100 characters). The order is created or updated by (shopId, id)."},"shopId":{"type":"string","description":"Shop of the order."},"createdAt":{"type":"string","description":"ISO 8601 with a time zone, e.g. 2026-10-12T09:30:00+02:00."},"paidAt":{"type":["string","null"]},"email":{"type":"string","description":"Buyer e-mail (or contactId). A buyer without a contact gets one without marketing consent (status customer, never e-mailed)."},"contactId":{"type":"string","description":"Existing contact (its e-mail must match email when both)."},"status":{"type":"string","description":"State name of the e-shop (at most 200), mapped to a canonical state by GET/PUT /order-states. Unmapped names are other (never a purchase)."},"eshopCode":{"type":"string"},"orderUrl":{"type":"string"},"companyId":{"type":"string"},"currency":{"type":"string","description":"Default and only allowed value: the shop currency."},"totalWithVat":{"type":["string","number"]},"totalWithoutVat":{"type":["string","number"]},"seller":{"type":"object"},"orderDelivery":{"type":"object"},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":["string","integer"],"description":"Product code (SKU) of the item."},"name":{"type":"string","description":"Required, at most 500 characters."},"description":{"type":"string"},"quantity":{"type":["number","string"],"description":"Default 1."},"unit":{"type":"string"},"price":{"type":"object","properties":{"withVat":{"type":["string","number"]},"withoutVat":{"type":["string","number"]},"currency":{"type":"string","description":"Must be the shop currency."}}},"url":{"type":"string"},"imageUrl":{"type":"string"},"attributes":{"type":"object","description":"Feed attributes (Category, Brand ...), at most 50."}},"required":["name"]},"maxItems":1000},"deleted":{"type":"boolean","description":"true = the order is deleted (ends post-purchase runs)."}},"required":["id","shopId","createdAt","status"]},"examples":{"post-purchase-order":{"summary":"docs/api-examples/post-purchase.json order","value":{"id":"2026001234","shopId":"13","createdAt":"2026-10-01T09:30:00+02:00","paidAt":"2026-10-01T09:31:00+02:00","email":"karel.vesely@example.cz","status":"Zaplaceno","eshopCode":"2026001234","orderUrl":"https://www.example.cz/objednavka/2026001234","currency":"CZK","totalWithVat":"1290.00","totalWithoutVat":"1066.12","items":[{"id":"KAVA-1KG","name":"Káva Kolumbie 1 kg","quantity":1,"unit":"ks","price":{"withVat":"1290.00","withoutVat":"1066.12","currency":"CZK"},"url":"https://www.example.cz/kava-kolumbie","attributes":{"Category":"Káva","Brand":"Example"}}]}}}}}},"x-postarna-permission":{"module":"contacts","level":"full","keyScope":"full"},"x-mcp-confirm":"trigger","responses":{"201":{"description":"Created (200 when it already existed or nothing changed)","content":{"application/json":{"schema":{"type":"object","properties":{"change":{"type":"string","enum":["created","updated","unchanged"]},"order":{"$ref":"#/components/schemas/Order"}},"required":["change","order"]},"examples":{"post-purchase-order":{"summary":"docs/api-examples/post-purchase.json order","value":{"change":"created","order":{"id":"5001","externalId":"2026001234","eshopCode":"2026001234","eshopName":"Example.cz","shopId":"13","createdAt":"2026-10-01T07:30:00.000Z","paidAt":"2026-10-01T07:31:00.000Z","email":"karel.vesely@example.cz","contactId":"1205","state":"paid","status":"completed","sourceStatus":"Zaplaceno","orderUrl":"https://www.example.cz/objednavka/2026001234","currency":"CZK","totalWithVat":"1290.00","totalWithoutVat":"1066.12","itemCount":1,"items":[{"id":"1","productCode":"KAVA-1KG","name":"Káva Kolumbie 1 kg","description":"","price":{"withVat":"1290.00","withoutVat":"1066.12","currency":"CZK"},"quantity":1,"unit":"ks","url":"https://www.example.cz/kava-kolumbie","imageUrl":"","attributes":{"Brand":"Example","Category":"Káva"},"paired":false}],"conversion":null,"deleted":false,"receivedAt":"2026-10-01T08:00:00.000Z","updatedAt":"2026-10-01T08:00:00.000Z","seller":{},"orderDelivery":{}}}}}}}},"200":{"description":"OK: it already existed or nothing changed","content":{"application/json":{"schema":{"type":"object","properties":{"change":{"type":"string","enum":["created","updated","unchanged"]},"order":{"$ref":"#/components/schemas/Order"}},"required":["change","order"]},"examples":{"post-purchase-order":{"summary":"docs/api-examples/post-purchase.json order","value":{"change":"created","order":{"id":"5001","externalId":"2026001234","eshopCode":"2026001234","eshopName":"Example.cz","shopId":"13","createdAt":"2026-10-01T07:30:00.000Z","paidAt":"2026-10-01T07:31:00.000Z","email":"karel.vesely@example.cz","contactId":"1205","state":"paid","status":"completed","sourceStatus":"Zaplaceno","orderUrl":"https://www.example.cz/objednavka/2026001234","currency":"CZK","totalWithVat":"1290.00","totalWithoutVat":"1066.12","itemCount":1,"items":[{"id":"1","productCode":"KAVA-1KG","name":"Káva Kolumbie 1 kg","description":"","price":{"withVat":"1290.00","withoutVat":"1066.12","currency":"CZK"},"quantity":1,"unit":"ks","url":"https://www.example.cz/kava-kolumbie","imageUrl":"","attributes":{"Brand":"Example","Category":"Káva"},"paired":false}],"conversion":null,"deleted":false,"receivedAt":"2026-10-01T08:00:00.000Z","updatedAt":"2026-10-01T08:00:00.000Z","seller":{},"orderDelivery":{}}}}}}}},"400":{"description":"`validation` (message: contactId, items, order)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/tenants/{tenant}/orders/paid-at":{"post":{"operationId":"maintenance_orders_paid_at","summary":"Maintenance: fill empty dates of payment of orders (SmartEmailing data)","tags":["Orders and feeds"],"description":"ES-01 (core/orders.set_paid_at): the dates of payment SmartEmailing kept, for orders whose e-shop export has none. Body {items: [{shop: shop code, code: the e-shop's order number, paidAt: ISO time with an offset or Z, or \"YYYY-MM-DD HH:MM[:SS]\" in the tenant's local time}] (1 to 5 000), dryRun: bool (required)}. Sets orders.paid_at only where it is empty, never overwrites one, writes no order event. 200 {updated, alreadySet, notFound, dryRun}.","parameters":[{"$ref":"#/components/parameters/tenant"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"dryRun":{},"items":{}},"required":["dryRun","items"]}}}},"x-postarna-permission":{"module":"contacts","level":"full","keyScope":"full"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"updated":{"type":"integer"},"alreadySet":{"type":"integer"},"notFound":{"type":"integer"},"dryRun":{"type":"boolean"}},"required":["updated","alreadySet","notFound","dryRun"]}}}},"400":{"description":"`validation` (message: dryRun, items)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/tenants/{tenant}/orders/{order_id}":{"get":{"operationId":"orders_show","summary":"Get an order","tags":["Orders and feeds"],"description":"Contract notes (cs):\n\nDetail `Order` se všemi položkami.","parameters":[{"$ref":"#/components/parameters/tenant"},{"name":"order_id","in":"path","required":true,"description":"Id of the order (string of digits).","schema":{"type":"string"}}],"x-postarna-permission":{"module":"contacts","level":"read","keyScope":"read or full"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"},"examples":{"post-purchase-order-show":{"summary":"docs/api-examples/post-purchase.json order-show","value":{"id":"5001","externalId":"2026001234","eshopCode":"2026001234","eshopName":"Example.cz","shopId":"13","createdAt":"2026-10-01T07:30:00.000Z","paidAt":"2026-10-01T07:31:00.000Z","email":"karel.vesely@example.cz","contactId":"1205","state":"paid","status":"completed","sourceStatus":"Předáno zákazníkovi","orderUrl":"","currency":"CZK","totalWithVat":"1290.00","totalWithoutVat":null,"itemCount":1,"items":[{"id":"2","productCode":"KAVA-1KG","name":"Káva Kolumbie 1 kg","description":"","price":{"withVat":"1290.00","withoutVat":null,"currency":"CZK"},"quantity":1,"unit":"","url":"","imageUrl":"","attributes":{},"paired":false}],"conversion":null,"deleted":false,"receivedAt":"2026-10-01T08:00:00.000Z","updatedAt":"2026-10-01T08:00:00.000Z","seller":{},"orderDelivery":{}}}}}}},"400":{"description":"`validation`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"pst_ API key","description":"An API key of the company: Authorization: Bearer pst_... (Nastavení › Datové zdroje › API klíče). Scope read or full, roles of the key."},"basicAuth":{"type":"http","scheme":"basic","description":"HTTP Basic as SmartEmailing: user name = e-mail of an active member of the company, password = the API key."},"oauth2":{"type":"oauth2","description":"OAuth 2.1 for MCP clients (AI assistants) only: authorization code with PKCE S256, dynamic registration.","flows":{"authorizationCode":{"authorizationUrl":"https://www.postarna.cz/oauth/authorize","tokenUrl":"https://www.postarna.cz/oauth/token","refreshUrl":"https://www.postarna.cz/oauth/token","scopes":{"read":"Read only (routes whose permission level is read).","full":"Everything the member's roles allow."}}}}},"parameters":{"tenant":{"name":"tenant","in":"path","required":true,"description":"Public id of the company (tenant), a UUID: GET /api/v3/account-info answers it as data.guid; the app shows it on the API keys page.","schema":{"type":"string","format":"uuid"}},"page":{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1},"description":"Page number, from 1."},"pageSize":{"name":"pageSize","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Items per page, 1 to 100."},"q":{"name":"q","in":"query","required":false,"schema":{"type":"string","maxLength":200},"description":"Search text (case and diacritics insensitive)."}},"headers":{"X-RateLimit-Limit":{"description":"Size of the bucket nearest to running out (2 500 per second bucket or 100 000 daily).","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in that bucket.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix time when that bucket is full again.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"responses":{"Unauthorized":{"description":"401 unauthorized: missing, unknown, revoked, expired or idle API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unauthorized","message":"api_key"}}}}},"Forbidden":{"description":"403 forbidden: message tenant (another company), scope (read-only key), api_key (person only), or the module the key's roles lack.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"forbidden","message":"scope"}}}}},"RateLimited":{"description":"429 rate_limited: wait Retry-After seconds.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"rate_limited","message":"per-second"}}}}}},"schemas":{"CouponCounts":{"type":"object","properties":{"total":{"type":"number"},"free":{"type":"number"},"assigned":{"type":"number"},"used":{"type":"number"}},"required":["total","free","assigned","used"]},"CouponImportResult":{"type":"object","properties":{"counts":{"type":"object","properties":{"added":{"type":"number"},"duplicate":{"type":"number"},"invalid":{"type":"number"},"total":{"type":"number"}},"required":["added","duplicate","invalid","total"]},"stack":{"$ref":"#/components/schemas/CouponStack"}},"required":["counts","stack"]},"CouponStack":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"shopId":{"type":"string"},"mergeKey":{"type":"string"},"tag":{"type":"string"},"note":{"type":"string"},"counts":{"$ref":"#/components/schemas/CouponCounts"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","name","shopId","mergeKey","tag","note","counts","createdAt","updatedAt"],"description":"A stack of discount codes of one e-shop (se-spec 06 §4.6); tag is the e-mail merge tag {{coupon_<mergeKey>}}."},"CouponStackInput":{"type":"object","properties":{"name":{"type":"string"},"shopId":{"type":"string"},"mergeKey":{"type":"string"},"note":{"type":"string"}},"required":["name","shopId","mergeKey"]},"CouponStatus":{"type":"string","enum":["free","assigned","used"]},"CouponUsedResult":{"type":"object","properties":{"marked":{"type":"number"},"already":{"type":"number"},"unknown":{"type":"number"},"stack":{"$ref":"#/components/schemas/CouponStack"}},"required":["marked","already","unknown","stack"]},"Currency":{"type":"string","enum":["CZK","EUR"]},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","enum":["conflict","count_mismatch","csrf","empty_segment","expired","forbidden","method_not_allowed","not_found","not_implemented","rate_limited","recently_sent","server","suppression_locked","unauthorized","unavailable","upstream","validation"],"description":"Stable machine readable code (see the error catalog in the guides)."},"message":{"type":"string","description":"The field or the reason (technical, not for people), e.g. \"email\", \"definition.1.0.listId\", \"name\"."},"params":{"type":"object","additionalProperties":true,"description":"Details: issues of a graph, expected and actual counts, retryAfter ..."}}}},"examples":[{"error":{"code":"validation","message":"email"}},{"error":{"code":"conflict","message":"version","params":{"current":4}}}]},"Feed":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"shopId":{"type":"string"},"kind":{"$ref":"#/components/schemas/FeedKind"},"format":{"$ref":"#/components/schemas/FeedFormat"},"currency":{"allOf":[{"$ref":"#/components/schemas/Currency"}],"description":"The shop's currency, read only."},"url":{"type":"string"},"autoRefresh":{"type":"boolean"},"pairing":{"type":"array","items":{"$ref":"#/components/schemas/FeedPairing"}},"itemCount":{"type":"number"},"version":{"type":"number"},"importedAt":{"type":["string","null"]},"refreshedAt":{"type":["string","null"],"description":"Last scheduled download (auto refresh) and its failure ('' = imported)."},"refreshError":{"type":"string"},"refreshReason":{"type":"string","description":"refreshError as a code for the UI (too_large, wrong_kind, not_google_products, not_customers,\nunsupported_format, invalid, doctype, http_404, network ...; '' = none) and what the document looked like."},"refreshDetected":{"type":"string"},"maxBytes":{"type":"number","description":"Largest document the feed accepts (20 MB products, 100 MB customers, 200 MB orders)."},"historyAt":{"type":["string","null"],"description":"Order feeds (migration 0097): when the first import (the order history, which starts no automation) finished;\nnull = not yet, the next import is the history. Other kinds: null."},"lastCounts":{"type":"object","properties":{"created":{"type":"number"},"updated":{"type":"number"},"unchanged":{"type":"number"},"removed":{"type":"number"},"skipped":{"type":"number"},"total":{"type":"number"},"invalid":{"type":"number"},"wrongCurrency":{"type":"number"},"events":{"type":"number"},"history":{"type":"boolean"},"partial":{"type":"boolean","description":"An order feed's recent download (the last days only, between two whole downloads)."}},"description":"Counts of the last import ({} before the first one)."},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","name","shopId","kind","format","currency","url","autoRefresh","pairing","itemCount","version","importedAt","refreshedAt","refreshError","refreshReason","refreshDetected","maxBytes","historyAt","lastCounts","createdAt","updatedAt"]},"FeedArticle":{"type":"object","properties":{"id":{"type":"string"},"feedId":{"type":"string"},"shopId":{"type":"string"},"itemId":{"type":"string","description":"guid / id of the article, else its link: what the editor stores to refresh it."},"title":{"type":"string"},"url":{"type":"string"},"perex":{"type":"string","description":"Plain text, at most 500 characters."},"imageUrl":{"type":"string"},"publishedAt":{"type":["string","null"]},"inFeed":{"type":"boolean"}},"required":["id","feedId","shopId","itemId","title","url","perex","imageUrl","publishedAt","inFeed"],"description":"An article of an article feed (GET /feed-articles, Články FEED of the Magic editor)."},"FeedArticleList":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/FeedArticle"}},"total":{"type":"number"},"feeds":{"type":"array","items":{"$ref":"#/components/schemas/FeedProductFeed"}}},"required":["items","total","feeds"]},"FeedFormat":{"type":"string","enum":["google","heureka","zbozi"]},"FeedFormatter":{"type":"object","properties":{"type":{"$ref":"#/components/schemas/FeedFormatterType"},"text":{"type":"string","description":"append, prepend"},"separator":{"type":"string","description":"split_join: split by separator, the parts from offset (negative from the end) to offset + length (0 = all)"},"offset":{"type":"number"},"length":{"type":"number"},"format":{"type":"string","description":"date: PHP-style format (d j m n Y y H G i s D N w)"},"decimals":{"type":"number","description":"number (0 to 6)"},"decimalSeparator":{"type":"string"},"thousandsSeparator":{"type":"string"},"currency":{"type":"string","enum":["CZK","EUR","feed","USD"],"description":"currency: 'feed' = the feed's shop currency"},"search":{"type":"string","description":"replace"},"replace":{"type":"string"}},"required":["type"]},"FeedFormatterType":{"type":"string","enum":["number","currency","date","append","prepend","strip_tags","split_join","replace","lower","upper"]},"FeedImportResult":{"type":"object","properties":{"counts":{"type":"object","properties":{"skipped":{"type":"number"},"created":{"type":"number"},"updated":{"type":"number"},"unchanged":{"type":"number"},"total":{"type":"number"},"removed":{"type":"number"},"invalid":{"type":"number"},"wrongCurrency":{"type":"number"},"events":{"type":"number"},"history":{"type":"boolean"},"partial":{"type":"boolean","description":"An order feed's recent download (the last days only, between two whole downloads)."}},"required":["skipped","created","updated","unchanged","total"]},"feed":{"$ref":"#/components/schemas/Feed"}},"required":["counts","feed"]},"FeedInput":{"type":"object","properties":{"name":{"type":"string"},"shopId":{"type":"string"},"kind":{"type":"string","enum":["google_products","shop_customers","shop_orders","articles"]},"format":{"type":"string","enum":["google","heureka","zbozi"],"description":"Only with kind google_products; fixed once the feed exists."},"url":{"type":"string"},"autoRefresh":{"type":"boolean"},"pairing":{"type":"array","items":{"$ref":"#/components/schemas/FeedPairing"}}},"required":["name","shopId"]},"FeedItem":{"type":"object","properties":{"id":{"type":"string"},"itemId":{"type":"string"},"code":{"type":"string"},"data":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/FeedValue"}},"values":{"type":"object","additionalProperties":{"type":"string"},"description":"Paired parameters after their formatters (product feeds)."},"updatedAt":{"type":"string"}},"required":["id","itemId","code","data","values","updatedAt"],"description":"An item of a product or article feed (GET .../feeds/{id}/items, Položky feedu)."},"FeedKind":{"type":"string","enum":["google_products","shop_customers","shop_orders","articles"]},"FeedList":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Feed"}},"defaultPairing":{"type":"array","items":{"$ref":"#/components/schemas/FeedPairing"}}},"required":["items","defaultPairing"]},"FeedPairing":{"type":"object","properties":{"name":{"type":"string","description":"Own parameter name (se-id, se-product ...); se-id pairs order items by product code."},"field":{"type":"string","description":"Field of the feed item (g:id, title ...)."},"format":{"type":"array","items":{"$ref":"#/components/schemas/FeedFormatter"},"description":"Formatters applied in order to the value (core/feed_format.py); absent = none. Never change the product code."}},"required":["name","field"]},"FeedPreview":{"type":"object","properties":{"index":{"type":"number"},"total":{"type":"number"},"item":{"type":["object","null"],"additionalProperties":{"$ref":"#/components/schemas/FeedValue"}},"values":{"type":"object","additionalProperties":{"type":"string"},"description":"Paired values of the item by parameter name."},"fields":{"type":"array","items":{"type":"string"}}},"required":["index","total","item","values","fields"]},"FeedProduct":{"type":"object","properties":{"id":{"type":"string"},"feedId":{"type":"string"},"shopId":{"type":"string"},"itemId":{"type":"string","description":"g:id: the id the editor stores to refresh the product later (Párovat feed)."},"code":{"type":"string"},"name":{"type":"string"},"url":{"type":"string"},"imageUrl":{"type":"string"},"price":{"type":["number","null"],"description":"With VAT, in the shop's currency (never converted); sale price when the feed has one."},"regularPrice":{"type":["number","null"],"description":"The price before the sale; null without a sale."},"currency":{"$ref":"#/components/schemas/Currency"},"priceText":{"type":"string"},"priceCurrencyMismatch":{"type":"boolean"},"availability":{"type":"string","enum":["","in_stock","out_of_stock","preorder","backorder"]},"brand":{"type":"string"},"shortDescription":{"type":"string","description":"The feed description as a short plain text (about 160 characters) for the product's text in an e-mail."},"values":{"type":"object","additionalProperties":{"type":"string"},"description":"The feed's paired parameters of the product after their formatters (Párování feedu: se-title, se-price, own\nnames); a part of a feed item may show one of them (ED-19)."},"inFeed":{"type":"boolean"},"updatedAt":{"type":"string"}},"required":["id","feedId","shopId","itemId","code","name","url","imageUrl","price","regularPrice","currency","priceText","availability","brand","inFeed","updatedAt"],"description":"A product of a shop's product feed for the editor's product picker (GET .../feed-products)."},"FeedProductFeed":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"shopId":{"type":"string"},"currency":{"$ref":"#/components/schemas/Currency"},"itemCount":{"type":"number"},"refreshedAt":{"type":["string","null"]},"importedAt":{"type":["string","null"]},"refreshError":{"type":"string"}},"required":["id","name","shopId","currency","itemCount","refreshedAt","importedAt","refreshError"]},"FeedProductList":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/FeedProduct"}},"total":{"type":"number"},"feeds":{"type":"array","items":{"$ref":"#/components/schemas/FeedProductFeed"}}},"required":["items","total","feeds"]},"FeedRefreshResult":{"type":"object","properties":{"state":{"type":"string","enum":["queued","running"]},"feed":{"$ref":"#/components/schemas/Feed"}},"required":["state","feed"],"description":"POST .../feeds/{id}/refresh: a download queued now, or one already running."},"FeedValue":{"anyOf":[{"type":"string"},{"type":"array","items":{"$ref":"#/components/schemas/FeedValue"}},{"type":"object","additionalProperties":{"$ref":"#/components/schemas/FeedValue"}}]},"Order":{"type":"object","properties":{"id":{"type":"string"},"externalId":{"type":"string"},"eshopCode":{"type":"string"},"eshopName":{"type":"string"},"shopId":{"type":"string"},"createdAt":{"type":"string"},"paidAt":{"type":["string","null"]},"email":{"type":["string","null"]},"contactId":{"type":["string","null"]},"state":{"type":"string","enum":["cancelled","unpaid","new","other","paid","processing","shipped","pickup","delivered","returned"]},"status":{"$ref":"#/components/schemas/OrderStatus"},"sourceStatus":{"type":"string"},"orderUrl":{"type":"string"},"currency":{"$ref":"#/components/schemas/Currency"},"totalWithVat":{"type":["string","null"]},"totalWithoutVat":{"type":["string","null"]},"itemCount":{"type":"number"},"items":{"type":"array","items":{"$ref":"#/components/schemas/OrderItem"},"description":"The list has the first three items, the detail all of them."},"conversion":{"anyOf":[{"$ref":"#/components/schemas/OrderConversion"},{"type":"null"}]}},"required":["id","externalId","eshopCode","eshopName","shopId","createdAt","paidAt","email","contactId","state","status","sourceStatus","orderUrl","currency","totalWithVat","totalWithoutVat","itemCount","items","conversion"]},"OrderConversion":{"type":"object","properties":{"kind":{"type":"string","enum":["direct","assisted"]},"campaignId":{"type":["string","null"]},"automationId":{"type":["string","null"]},"clickedAt":{"type":"string"}},"required":["kind","campaignId","automationId","clickedAt"]},"OrderItem":{"type":"object","properties":{"id":{"type":"string"},"productCode":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"price":{"$ref":"#/components/schemas/OrderItemPrice"},"quantity":{"type":"number"},"unit":{"type":"string"},"url":{"type":"string"},"imageUrl":{"type":"string"},"attributes":{"type":"object","additionalProperties":{"anyOf":[{"type":"boolean"},{"type":"string"},{"type":"number"},{"type":"null"}]},"description":"ItemType, Brand, Category, g:condition, g:availability, g:brand of the paired feed product under the item's own."},"paired":{"type":"boolean","description":"True when the item met a product of the shop's feeds by its code."}},"required":["id","productCode","name","description","price","quantity","unit","url","imageUrl","attributes","paired"]},"OrderItemPrice":{"type":"object","properties":{"withVat":{"type":["string","null"],"description":"Unit prices as decimal strings in the order currency."},"withoutVat":{"type":["string","null"]},"currency":{"$ref":"#/components/schemas/Currency"}},"required":["withVat","withoutVat","currency"]},"OrderStateRule":{"type":"object","properties":{"sourceStatus":{"type":"string","description":"State name of the e-shop, at most 80 characters."},"match":{"type":"string","enum":["exact","prefix"],"default":"exact"},"state":{"type":"string","enum":["new","unpaid","paid","processing","shipped","pickup","delivered","cancelled","returned","other"]}},"required":["sourceStatus","state"],"description":"orders.check_state_map: one rule of the state map"},"OrderStatus":{"type":"string","enum":["cancelled","other","pending","completed"]},"StackCoupon":{"type":"object","properties":{"id":{"type":"string"},"code":{"type":"string"},"status":{"$ref":"#/components/schemas/CouponStatus"},"assignedAt":{"type":["string","null"]},"usedAt":{"type":["string","null"]},"contact":{"type":["object","null"],"properties":{"id":{"type":"string"},"email":{"type":"string"}},"required":["id","email"],"description":"null after the contact was erased."},"email":{"type":["object","null"],"properties":{"kind":{"type":"string","enum":["campaign","automation"]},"campaignId":{"type":["string","null"]},"automationId":{"type":["string","null"]},"nodeKey":{"type":["string","null"]}},"required":["kind","campaignId","automationId","nodeKey"],"description":"The e-mail the code went out with; null = handed out by hand, or before every e-mail took its own code."}},"required":["id","code","status","assignedAt","usedAt","contact","email"],"description":"A code of a stack handed out (PZ-05, GET /coupon-stacks/{id}/coupons): to whom and with which e-mail."}}}}