Přeskočit na obsah
API dokumentace

Recept: opuštěný košík

Cíl: zákazníkovi, který si něco vložil do košíku a do 2 hodin neobjednal, poslat připomenutí. Když košík mezitím vyprázdní nebo objedná, e-mail neodejde.

Potřebujete: klíč s rolí marketing_manager nebo account_admin (moduly content a campaigns plný přístup, contacts pro kontakty), ověřeného odesílatele e-shopu, ID e-shopu (GET /shops).

Jak to funguje

Graf
[kosik] trigger_event cart_updated (reentry restart)
   └─ next → [pockat] wait 2 hours
                └─ next → [stale-v-kosiku] condition: košík není prázdný A neobjednal od vstupu
                             ├─ yes → [email] send_email (šablona Opuštěný košík)
                             └─ no  → (konec, kontakt scénář opustí)
  • Každá změna košíku (POST /contact-events typ cart) je událost cart_updated. Díky reentry: "restart" další změna košíku ukončí rozběhnutý běh a čekání začne znovu, takže zákazník dostane jedno připomenutí až 2 hodiny po poslední změně.
  • Podmínka cart_items_count čte poslední stav košíku: prázdný košík (nebo košík, který se od objednávky nezměnil) má 0 položek.
  • ordered_since_entry: no vyloučí kontakty, které od vstupu do scénáře objednaly.

1. Šablona e-mailu

V e-mailu automatizace jsou data události, která běh spustila, v metadata.event.attributes (u košíku itemCount, total, currency, shopId):

Požadavek: POST /api/v1/tenants/{tenant}/templates
curl -sS -X POST "https://www.postarna.cz/api/v1/tenants/$TENANT/templates" \
  -H "Authorization: Bearer $POSTARNA_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @- <<'JSON'
{
  "name": "Opuštěný košík",
  "subject": "{{df_name|default('Dobrý den', true)}}, něco jste nechali v košíku",
  "preheader": "Váš košík na vás počká ještě pár dní",
  "content": {
    "editor": "html",
    "design": null,
    "html": "<!doctype html><html><body><p>Dobrý den, {{df_salution|default('vážený zákazníku', true)}},</p><p>ve vašem košíku zůstalo {{ metadata.event.attributes.itemCount }} ks zboží za {{ metadata.event.attributes.total }} {{ metadata.event.attributes.currency }}.</p><p><a href=\"https://www.example.cz/kosik/\">Dokončit objednávku</a></p><p style=\"font-size:12px\">{{cl_company}}, {{cl_address}}. <a href=\"{{unsubscribe}}\">Odhlásit odběr</a></p></body></html>"
  }
}
JSON
Odpověď: 201 Created
{
  "id": "301",
  "name": "Opuštěný košík",
  "subject": "{{df_name|default('Dobrý den', true)}}, něco jste nechali v košíku",
  "preheader": "Váš košík na vás počká ještě pár dní",
  "editor": "html",
  "createdAt": "2026-10-01T08:00:00.000Z",
  "updatedAt": "2026-10-01T08:00:00.000Z",
  "tags": [],
  "size": 465,
  "archived": false,
  "archivedAt": null,
  "readOnly": false,
  "usage": {
    "campaigns": 0,
    "automations": 0
  },
  "lastUsedAt": null,
  "check": {
    "errors": [],
    "warnings": [
      "subject_long"
    ],
    "checkedAt": "2026-10-01T08:00:00.000Z"
  },
  "content": {
    "editor": "html",
    "html": "<!doctype html><html><body><p>Dobrý den, {{df_salution|default('vážený zákazníku', true)}},</p><p>ve vašem košíku zůstalo {{ metadata.event.attributes.itemCount }} ks zboží za {{ metadata.event.attributes.total }} {{ metadata.event.attributes.currency }}.</p><p><a href=\"https://www.example.cz/kosik/\">Dokončit objednávku</a></p><p style=\"font-size:12px\">{{cl_company}}, {{cl_address}}. <a href=\"{{unsubscribe}}\">Odhlásit odběr</a></p></body></html>",
    "design": null,
    "version": 1,
    "updatedAt": "2026-10-01T08:00:00.000Z"
  },
  "settings": {
    "linkParams": [],
    "headers": [],
    "unsubscribePageId": null,
    "footerId": null
  },
  "draft": {
    "pending": false,
    "savedAt": null,
    "publishedAt": null
  },
  "activeUses": {
    "automations": 0,
    "emails": 0,
    "campaigns": 0
  },
  "publicUrl": "https://links.example.cz/template/1/72cf576a-85b2-474e-86e2-bfdbd1f4d38f"
}

2. Kontrola grafu bez uložení

POST /automations/validate ukáže chyby (errors, graf nejde uložit) a neúplná nastavení (incomplete, nejde zapnout). Tady chybí šablona e-mailu:

Požadavek: POST /api/v1/tenants/{tenant}/automations/validate
curl -sS -X POST "https://www.postarna.cz/api/v1/tenants/$TENANT/automations/validate" \
  -H "Authorization: Bearer $POSTARNA_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @- <<'JSON'
{
  "shopId": "1",
  "graph": {
    "nodes": [
      {
        "id": "kosik",
        "type": "trigger_event",
        "config": {
          "event": "cart_updated",
          "shopId": "1",
          "reentry": "restart"
        }
      },
      {
        "id": "pockat",
        "type": "wait",
        "config": {
          "mode": "duration",
          "value": 2,
          "unit": "hours"
        }
      },
      {
        "id": "email",
        "type": "send_email",
        "config": {}
      }
    ],
    "edges": [
      {
        "source": "kosik",
        "target": "pockat"
      },
      {
        "source": "pockat",
        "target": "email"
      }
    ]
  }
}
JSON
Odpověď: 200 OK
{
  "errors": [],
  "incomplete": [
    {
      "node": "email",
      "field": "templateId",
      "code": "required"
    }
  ]
}

3. Založení automatizace

Požadavek: POST /api/v1/tenants/{tenant}/automations
curl -sS -X POST "https://www.postarna.cz/api/v1/tenants/$TENANT/automations" \
  -H "Authorization: Bearer $POSTARNA_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @- <<'JSON'
{
  "name": "Opuštěný košík",
  "shopId": "1",
  "description": "Připomenutí košíku po 2 hodinách",
  "tags": [
    "e-shop"
  ],
  "graph": {
    "nodes": [
      {
        "id": "kosik",
        "type": "trigger_event",
        "name": "Změna košíku",
        "position": {
          "x": 0,
          "y": 0
        },
        "config": {
          "event": "cart_updated",
          "shopId": "1",
          "reentry": "restart"
        }
      },
      {
        "id": "pockat",
        "type": "wait",
        "name": "Počkat 2 hodiny",
        "position": {
          "x": 0,
          "y": 150
        },
        "config": {
          "mode": "duration",
          "value": 2,
          "unit": "hours"
        }
      },
      {
        "id": "stale-v-kosiku",
        "type": "condition",
        "name": "Košík stále plný a bez objednávky",
        "position": {
          "x": 0,
          "y": 300
        },
        "config": {
          "definition": {
            "type": "group",
            "match": "all",
            "rules": [
              {
                "type": "cart_items_count",
                "operator": "gt",
                "value": 0,
                "shopId": "1"
              },
              {
                "type": "ordered_since_entry",
                "operator": "no",
                "shopId": "1"
              }
            ]
          }
        }
      },
      {
        "id": "email",
        "type": "send_email",
        "name": "Připomenutí",
        "position": {
          "x": 0,
          "y": 450
        },
        "config": {
          "templateId": "301",
          "trackOpens": true,
          "trackClicks": true
        }
      }
    ],
    "edges": [
      {
        "source": "kosik",
        "target": "pockat",
        "branch": "next"
      },
      {
        "source": "pockat",
        "target": "stale-v-kosiku",
        "branch": "next"
      },
      {
        "source": "stale-v-kosiku",
        "target": "email",
        "branch": "yes"
      }
    ]
  }
}
JSON
Odpověď: 201 Created
{
  "id": "81",
  "name": "Opuštěný košík",
  "shopId": "1",
  "status": "draft",
  "version": 1,
  "activeSince": null,
  "firstActivatedAt": null,
  "pausedReason": null,
  "tags": [
    "e-shop"
  ],
  "createdAt": "2026-10-01T08:00:00.000Z",
  "updatedAt": "2026-10-01T08:00:00.000Z",
  "stats": {
    "entered": 0,
    "active": 0,
    "sent": 0
  },
  "description": "Připomenutí košíku po 2 hodinách",
  "graph": {
    "nodes": [
      {
        "id": "kosik",
        "type": "trigger_event",
        "name": "Změna košíku",
        "note": "",
        "position": {
          "x": 0,
          "y": 0
        },
        "config": {
          "event": "cart_updated",
          "shopId": "1",
          "reentry": "restart"
        }
      },
      {
        "id": "pockat",
        "type": "wait",
        "name": "Počkat 2 hodiny",
        "note": "",
        "position": {
          "x": 0,
          "y": 150
        },
        "config": {
          "mode": "duration",
          "unit": "hours",
          "value": 2
        }
      },
      {
        "id": "stale-v-kosiku",
        "type": "condition",
        "name": "Košík stále plný a bez objednávky",
        "note": "",
        "position": {
          "x": 0,
          "y": 300
        },
        "config": {
          "definition": {
            "type": "group",
            "match": "all",
            "rules": [
              {
                "type": "cart_items_count",
                "value": 0,
                "shopId": "1",
                "operator": "gt"
              },
              {
                "type": "ordered_since_entry",
                "shopId": "1",
                "operator": "no"
              }
            ]
          }
        }
      },
      {
        "id": "email",
        "type": "send_email",
        "name": "Připomenutí",
        "note": "",
        "position": {
          "x": 0,
          "y": 450
        },
        "config": {
          "templateId": "301",
          "trackOpens": true,
          "trackClicks": true
        }
      }
    ],
    "edges": [
      {
        "source": "kosik",
        "target": "pockat",
        "branch": "next"
      },
      {
        "source": "pockat",
        "target": "stale-v-kosiku",
        "branch": "next"
      },
      {
        "source": "stale-v-kosiku",
        "target": "email",
        "branch": "yes"
      }
    ]
  },
  "issues": [],
  "triggers": {}
}

Automatizace vznikne jako koncept (status: "draft", verze 1). Odpověď má v issues vše, co brání zapnutí; tady je prázdné.

4. Zapnutí

Požadavek: POST /api/v1/tenants/{tenant}/automations/81/activate
curl -sS -X POST "https://www.postarna.cz/api/v1/tenants/$TENANT/automations/81/activate" \
  -H "Authorization: Bearer $POSTARNA_API_KEY"
Odpověď: 200 OK
{
  "id": "81",
  "name": "Opuštěný košík",
  "shopId": "1",
  "status": "active",
  "version": 1,
  "activeSince": "2026-10-01T08:00:00.000Z",
  "firstActivatedAt": "2026-10-01T08:00:00.000Z",
  "pausedReason": null,
  "tags": [
    "e-shop"
  ],
  "createdAt": "2026-10-01T08:00:00.000Z",
  "updatedAt": "2026-10-01T08:00:00.000Z",
  "stats": {
    "entered": 0,
    "active": 0,
    "sent": 0
  },
  "description": "Připomenutí košíku po 2 hodinách",
  "graph": {
    "nodes": [
      {
        "id": "kosik",
        "type": "trigger_event",
        "name": "Změna košíku",
        "note": "",
        "position": {
          "x": 0,
          "y": 0
        },
        "config": {
          "event": "cart_updated",
          "shopId": "1",
          "reentry": "restart"
        }
      },
      {
        "id": "pockat",
        "type": "wait",
        "name": "Počkat 2 hodiny",
        "note": "",
        "position": {
          "x": 0,
          "y": 150
        },
        "config": {
          "mode": "duration",
          "unit": "hours",
          "value": 2
        }
      },
      {
        "id": "stale-v-kosiku",
        "type": "condition",
        "name": "Košík stále plný a bez objednávky",
        "note": "",
        "position": {
          "x": 0,
          "y": 300
        },
        "config": {
          "definition": {
            "type": "group",
            "match": "all",
            "rules": [
              {
                "type": "cart_items_count",
                "value": 0,
                "shopId": "1",
                "operator": "gt"
              },
              {
                "type": "ordered_since_entry",
                "shopId": "1",
                "operator": "no"
              }
            ]
          }
        }
      },
      {
        "id": "email",
        "type": "send_email",
        "name": "Připomenutí",
        "note": "",
        "position": {
          "x": 0,
          "y": 450
        },
        "config": {
          "templateId": "301",
          "trackOpens": true,
          "trackClicks": true
        }
      }
    ],
    "edges": [
      {
        "source": "kosik",
        "target": "pockat",
        "branch": "next"
      },
      {
        "source": "pockat",
        "target": "stale-v-kosiku",
        "branch": "next"
      },
      {
        "source": "stale-v-kosiku",
        "target": "email",
        "branch": "yes"
      }
    ]
  },
  "issues": [],
  "triggers": {}
}

Když něco chybí (neověřený odesílatel, chyba v obsahu šablony, neúplný uzel), server vrátí 400 validation / graph s params.issues.

5. Události košíku z e-shopu

Při každé změně košíku přihlášeného zákazníka pošlete aktuální obsah. Kontakt najde Poštárna podle email nebo contactId; událost nikdy nezaloží nový kontakt (neznámý kontakt = 404).

Požadavek: POST /api/v1/tenants/{tenant}/contacts
curl -sS -X POST "https://www.postarna.cz/api/v1/tenants/$TENANT/contacts" \
  -H "Authorization: Bearer $POSTARNA_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @- <<'JSON'
{
  "email": "lucie.mala@example.cz",
  "shopId": "1",
  "purposeId": "1",
  "consentConfirmed": true,
  "firstName": "Lucie",
  "vocativeFirstName": "Lucie"
}
JSON
Odpověď: 201 Created
{
  "id": "1201",
  "email": "lucie.mala@example.cz",
  "firstName": "Lucie",
  "lastName": "",
  "status": "subscribed",
  "engagement": "N",
  "excluded": false,
  "shopId": "1",
  "suppressionReason": null,
  "blacklisted": false,
  "blacklistedAt": null,
  "state": null,
  "createdAt": "2026-10-01T08:00:00.000Z",
  "phone": "",
  "mobile": "",
  "titleBefore": "",
  "titleAfter": "",
  "salutation": "",
  "salutationFormal": "",
  "vocativeFirstName": "Lucie",
  "vocativeLastName": "",
  "gender": null,
  "language": "cs",
  "company": "",
  "companyId": "",
  "street": "",
  "city": "",
  "postalCode": "",
  "note": "",
  "affiliateId": "",
  "country": null,
  "birthday": null,
  "nameDay": null,
  "source": "manual",
  "consentBasis": "imported",
  "statusAt": "2026-10-01T08:00:00.000Z",
  "consentAt": "2026-10-01T08:00:00.000Z",
  "consentWeak": false,
  "softBounces": 0,
  "lastSentAt": null,
  "lastOpenAt": null,
  "lastClickAt": null,
  "suppressedAt": null,
  "engagementAt": null,
  "suppressionNote": null,
  "customFields": {},
  "updatedAt": "2026-10-01T08:00:00.000Z",
  "stats90d": {
    "received": 0,
    "opened": 0,
    "clicked": 0,
    "bestHour": null
  },
  "lists": [],
  "recentActivities": [
    {
      "id": "consent-1",
      "type": "status_change",
      "at": "2026-10-01T08:00:00.000Z",
      "title": "purpose_assigned"
    }
  ],
  "orders": [],
  "orderTotals": [],
  "editedFields": [],
  "sources": []
}
Požadavek: POST /api/v1/tenants/{tenant}/contact-events
curl -sS -X POST "https://www.postarna.cz/api/v1/tenants/$TENANT/contact-events" \
  -H "Authorization: Bearer $POSTARNA_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @- <<'JSON'
{
  "type": "cart",
  "email": "lucie.mala@example.cz",
  "shopId": "1",
  "currency": "CZK",
  "total": "589.00",
  "items": [
    {
      "code": "KAVA-250",
      "name": "Káva Brazílie 250 g",
      "quantity": 2,
      "price": "249.00",
      "url": "https://www.example.cz/kava-brazilie"
    },
    {
      "code": "FILTR-02",
      "name": "Papírové filtry",
      "quantity": 1,
      "price": "91.00"
    }
  ]
}
JSON
Odpověď: 201 Created
{
  "id": "9004"
}

Vyprázdněný košík (nebo dokončená objednávka) pošlete jako prázdné items:

Požadavek: POST /api/v1/tenants/{tenant}/contact-events
curl -sS -X POST "https://www.postarna.cz/api/v1/tenants/$TENANT/contact-events" \
  -H "Authorization: Bearer $POSTARNA_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @- <<'JSON'
{
  "type": "cart",
  "contactId": "1201",
  "shopId": "1",
  "items": []
}
JSON
Odpověď: 201 Created
{
  "id": "9005"
}
  • Nejvýš 60 událostí jednoho kontaktu za 10 minut (429 rate_limited). Posílejte stav košíku po změně, ne při každém zobrazení stránky.
  • Objednávku zapište přes POST /orders; podmínka ordered_since_entry ji uvidí.

6. Sledování

Počty po uzlech (waiting = kontakty, které právě čekají):

Požadavek: GET /api/v1/tenants/{tenant}/automations/81/counts
curl -sS -X GET "https://www.postarna.cz/api/v1/tenants/$TENANT/automations/81/counts" \
  -H "Authorization: Bearer $POSTARNA_API_KEY"
Odpověď: 200 OK
{
  "nodes": {},
  "runs": {
    "active": 0,
    "completed": 0,
    "exited": 0
  }
}

Historie jednoho kontaktu: GET /automations/{id}/runs?contactId=1201. Průchod kontaktu bez odeslání: POST /automations/{id}/trace s {"contactId": "1201"}.

7. Úprava běžící automatizace

Běžící scénář jde uložit jen s "confirmRunning": true, jinak 409 confirm:

Požadavek: PUT /api/v1/tenants/{tenant}/automations/81/graph
curl -sS -X PUT "https://www.postarna.cz/api/v1/tenants/$TENANT/automations/81/graph" \
  -H "Authorization: Bearer $POSTARNA_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @- <<'JSON'
{
  "baseVersion": 1,
  "graph": {
    "nodes": [],
    "edges": []
  }
}
JSON
Odpověď: 409 Conflict
{
  "error": {
    "code": "conflict",
    "message": "confirm"
  }
}

Varianty

  • Dvě připomenutí: za e-mail přidejte wait (1 den), znovu stejnou podmínku a druhý send_email, třeba se slevou ({{ data.promoCode('Košík') }}).
  • Jen stálí zákazníci: do podmínky přidejte pravidlo segmentu order_count ("operator": "gte", "value": "1"), nebo filtr na vlastní pole kontaktu.
  • Cíl scénáře: uzel goal s pravidlem ordered_since_entry: yes ukončí běh, jakmile zákazník objedná, ať je kdekoli.