Recept: import kontaktů z CSV
Cíl: nahrát kontakty z CSV souboru se souhlasem, který máte doložený, a ověřit výsledek.
Potřebujete: klíč s modulem contacts na úrovni full.
1. Nahrání souboru
Dvě možnosti:
multipart/form-datas polemfile(soubor do 64 MB a 300 000 řádků, kódování UTF-8, UTF-16 nebo windows-1250 se pozná samo) a volitelnědelimiter,quote,hasHeader,encoding.- JSON
{"text": "...", "delimiter", "quote", "hasHeader"}s obsahem do 5 MB.
curl -sS -X POST "https://www.postarna.cz/api/v1/tenants/$TENANT/imports/files" \
-H "Authorization: Bearer $POSTARNA_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @- <<'JSON'
{
"text": "email;jmeno;prijmeni;mesto\nmarie.dvorakova@example.cz;Marie;Dvořáková;Praha\ntomas.cerny@example.cz;Tomáš;Černý;Ostrava\nchybna-adresa;Jan;Bez;Plzeň\n",
"delimiter": ";",
"quote": "\"",
"hasHeader": true
}
JSON{
"fileId": "71",
"fileName": "vlozeny-text.csv",
"size": 155,
"delimiter": ";",
"quote": "\"",
"hasHeader": true,
"encoding": "utf-8",
"columns": [
"email",
"jmeno",
"prijmeni",
"mesto"
],
"rowCount": 3,
"sample": [
[
"marie.dvorakova@example.cz",
"Marie",
"Dvořáková",
"Praha"
],
[
"tomas.cerny@example.cz",
"Tomáš",
"Černý",
"Ostrava"
],
[
"chybna-adresa",
"Jan",
"Bez",
"Plzeň"
]
],
"suggestedKind": "csv",
"suggestedMapping": [
"email",
"firstName",
"lastName",
"city"
]
}Odpověď má fileId, rozpoznané sloupce, ukázku řádků a suggestedMapping (návrh, které pole je ve kterém sloupci). Soubor se drží 24 hodin.
2. Náhled
mapping má jednu položku na sloupec souboru, v pořadí: název pole, nebo null (sloupec přeskočit). Právě jeden sloupec musí být email. Pole: email, firstName, lastName, fullName, titleBefore, titleAfter, phone, mobile, company, companyId, street, city, postalCode, country, language, gender, birthday, note, newsletterConsent, newsletterConsentAt, registeredAt a vlastní pole.
curl -sS -X POST "https://www.postarna.cz/api/v1/tenants/$TENANT/imports/preview" \
-H "Authorization: Bearer $POSTARNA_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @- <<'JSON'
{
"fileId": "71",
"mapping": [
"email",
"firstName",
"lastName",
"city"
],
"mode": "upsert",
"shopId": "9",
"listIds": []
}
JSON{
"counts": {
"rows": 3,
"create": 2,
"update": 0,
"skipSuppressed": 0,
"skipMissing": 0,
"invalid": 1,
"duplicate": 0,
"unsubscribe": 0,
"remove": 0,
"blacklist": 0
},
"rows": [
{
"row": 2,
"email": "marie.dvorakova@example.cz",
"action": "create",
"error": null,
"field": null,
"values": {
"email": "marie.dvorakova@example.cz",
"firstName": "Marie",
"lastName": "Dvořáková",
"city": "Praha"
},
"consent": true
},
{
"row": 3,
"email": "tomas.cerny@example.cz",
"action": "create",
"error": null,
"field": null,
"values": {
"email": "tomas.cerny@example.cz",
"firstName": "Tomáš",
"lastName": "Černý",
"city": "Ostrava"
},
"consent": true
},
{
"row": 4,
"email": "chybna-adresa",
"action": "invalid",
"error": "email_invalid",
"field": "email",
"values": {
"email": "chybna-adresa",
"firstName": "Jan",
"lastName": "Bez",
"city": "Plzeň"
},
"consent": null
}
],
"report": {
"consent": {
"optIn": 2,
"none": 0,
"keptUnsubscribed": 0
},
"merge": {
"existing": 0,
"fromSources": {},
"fieldsUpdated": 0,
"fieldsKeptEdited": 0
},
"dropped": {}
}
}counts říká, kolik řádků se založí, aktualizuje, přeskočí (potlačené adresy, chyby) a proč; rows ukazuje první řádky s jejich výsledkem.
3. Spuštění
mode:upsert(založit i aktualizovat),update_only, nebo hromadné odhlášeníunsubscribe, odebráníremove, blacklistblacklist.purposeIdaconsentConfirmed: true: potvrzujete, že ke všem kontaktům máte doložený souhlas s tímto účelem (uunsubscribe,removeablacklistsouhlas potřeba není).listIds: ruční seznamy, do kterých kontakty přibudou.runAutomations: výchozífalse= import nespustí žádnou automatizaci (ani „nový kontakt“ či „přidání do seznamu“). Zapněte jen vědomě.kind:csv, nebo exporty Shoptetushoptet_customersashoptet_newsletter.
curl -sS -X POST "https://www.postarna.cz/api/v1/tenants/$TENANT/imports" \
-H "Authorization: Bearer $POSTARNA_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @- <<'JSON'
{
"name": "Kontakty z veletrhu",
"source": "csv",
"fileId": "71",
"mapping": [
"email",
"firstName",
"lastName",
"city"
],
"mode": "upsert",
"shopId": "9",
"listIds": [],
"purposeId": "5",
"consentConfirmed": true
}
JSON{
"id": "61",
"name": "Kontakty z veletrhu",
"status": "finished",
"kind": "csv",
"fileName": "vlozeny-text.csv",
"shopId": "9",
"mode": "upsert",
"listIds": [],
"createdAt": "2026-10-01T08:00:00.000Z",
"startedAt": "2026-10-01T08:00:00.000Z",
"finishedAt": "2026-10-01T08:00:00.000Z",
"progress": {
"processed": 3,
"total": 3
},
"counts": {
"rows": 3,
"create": 2,
"remove": 0,
"update": 0,
"invalid": 1,
"blacklist": 0,
"duplicate": 0,
"skipMissing": 0,
"unsubscribe": 0,
"skipSuppressed": 0
},
"source": "csv",
"purposeId": "5",
"addedToLists": 0,
"errors": [
{
"row": 4,
"error": "email_invalid",
"field": "email"
}
],
"runAutomations": false,
"options": {},
"report": {
"consent": {
"none": 0,
"optIn": 2,
"keptUnsubscribed": 0
},
"merge": {
"existing": 0,
"fromSources": {},
"fieldsUpdated": 0,
"fieldsKeptEdited": 0
},
"dropped": {}
}
}Do 1 000 řádků proběhne import hned (status: "finished"); větší jde do fronty (queued, running s průběhem progress) a dokončí ho worker.
4. Výsledek
curl -sS -X GET "https://www.postarna.cz/api/v1/tenants/$TENANT/imports/61" \
-H "Authorization: Bearer $POSTARNA_API_KEY"{
"id": "61",
"name": "Kontakty z veletrhu",
"status": "finished",
"kind": "csv",
"fileName": "vlozeny-text.csv",
"shopId": "9",
"mode": "upsert",
"listIds": [],
"createdAt": "2026-10-01T08:00:00.000Z",
"startedAt": "2026-10-01T08:00:00.000Z",
"finishedAt": "2026-10-01T08:00:00.000Z",
"progress": {
"processed": 3,
"total": 3
},
"counts": {
"rows": 3,
"create": 2,
"remove": 0,
"update": 0,
"invalid": 1,
"blacklist": 0,
"duplicate": 0,
"skipMissing": 0,
"unsubscribe": 0,
"skipSuppressed": 0
},
"source": "csv",
"purposeId": "5",
"addedToLists": 0,
"errors": [
{
"row": 4,
"error": "email_invalid",
"field": "email"
}
],
"runAutomations": false,
"options": {},
"report": {
"consent": {
"none": 0,
"optIn": 2,
"keptUnsubscribed": 0
},
"merge": {
"existing": 0,
"fromSources": {},
"fieldsUpdated": 0,
"fieldsKeptEdited": 0
},
"dropped": {}
}
}errors uvádí řádky, které neprošly (tady neplatná adresa na řádku 4).
Pravidla, na která pozor
- Potlačená adresa (odhlášená, nedoručitelná, stížnost) se importem nikdy znovu nepřihlásí.
- Pole, která v aplikaci upravil člověk, import nepřepíše.
- Adresa vymazaná na žádost (GDPR) se importem znovu nezaloží.
- Import zákazníků bez souhlasu (
shoptet_customersbez sloupce souhlasu) založí kontaktycustomer, kterým se nepíše.