Přeskočit na obsah

Dokumentace

Vše, co potřebujete k integraci BezBrany do svého e-shopu. Kompletní API referenci najdete ve Swagger dokumentaci.

Rychlý start

  1. 1

    Zaregistrujte se a vytvořte merchant účet

    Po přihlášení vás provede onboarding — vyplníte základní údaje a přidáte bankovní účet s Fio API tokenem.

  2. 2

    Vygenerujte si API klíč

    V administraci v sekci Nastavení → API klíče. Pro testování použijte test klíč — platby lze simulovat bez skutečných peněz.

  3. 3

    Vytvořte první platbu

    Zavolejte API s klíčem v hlavičce X-API-Key — odpověď obsahuje QR kód i platební kód pro widget.

REST API reference

MetodaEndpointPopis
POST/api/v1/paymentsVytvoření platby (API klíč)
GET/api/v1/payments/{paymentCode}Stav platby (API klíč)
POST/api/v1/payments/{paymentCode}/simulate-successSimulace úspěchu (jen test klíče)
POST/api/v1/widget/paymentsVytvoření platby z frontendu (veřejný pk_ klíč, hlavička X-Public-Key)
GET/api/v1/widget/payments/{paymentCode}Stav platby pro widget
GET/api/v1/merchants/me/paymentsSeznam plateb (Bearer token)
GET/api/v1/merchants/me/payments/exportCSV export plateb (Bearer token)

Příklad vytvoření platby:

create-payment.sh
curl -X POST https://api.bezbrany.cz/api/v1/payments \
  -H "X-API-Key: VAS_API_KLIC" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 100,
    "currency": "CZK",
    "orderNumber": "OBJ-2026-001",
    "payer": { "contact": { "firstName": "Jan", "lastName": "Novák", "email": "jan@example.cz" } },
    "items": [{ "name": "Tričko", "amount": 100, "quantity": 1 }]
  }'

Tarify a limity

Tarif obchodníka určuje, kolik plateb za měsíc se spáruje, kolik bankovních účtů lze připojit a zda se odesílají webhooky. Počítají se spárované (ne testovací) platby od začátku kalendářního měsíce. Podrobnosti a ceny najdete v ceníku.

TarifSpárované platby / měsícBlokace nových plateb odBankovní účtyWebhookyBranding
Free20221neano
Start3003302anone
Proneomezeně—10anone

Po dosažení měsíčního limitu máte ještě 10 % toleranci. Teprve potom vrátí vytvoření nové platby (POST /api/v1/payments, POST /api/v1/widget/payments i ruční platba z nástěnky) HTTP 402 s kódem PLAN_LIMIT_REACHED. Už vytvořené platby se spárují vždy — zákazník, který zaplatil, o nic nepřijde.

402-plan-limit.json
HTTP/1.1 402 Payment Required
Content-Type: application/json

{
  "error": "Tarif Free má limit 20 spárovaných plateb za měsíc. Přejděte na vyšší tarif pro další platby.",
  "code": "PLAN_LIMIT_REACHED",
  "details": {
    "limit": "matchedPayments",
    "current": 22,
    "max": 20,
    "plan": "free",
    "upgradeTo": "start"
  },
  "status": 402,
  "path": "/api/v1/payments",
  "timestamp": "2026-10-24T09:15:00.000Z"
}

V details je limit (který limit byl dosažen — matchedPayments nebo accounts), current (aktuální využití), max (limit tarifu), plan (aktuálně platný tarif) a upgradeTo (doporučený vyšší tarif, u Pro null). Stejnou chybu vrátí i přidání bankovního účtu nad limit tarifu (POST /api/v1/merchants/me/accounts).

Doporučené zpracování: zákazníkovi nezobrazujte technickou chybu — ukažte přívětivou zprávu a nabídněte náhradní způsob platby (např. ruční převod podle údajů v objednávce). Obchodníka upozorněte (e-mail, log, interní notifikace), ať může přejít na vyšší tarif v Nastavení → Tarif. Na 402 neopakujte request automaticky — dokud se tarif nezmění, skončí stejně.

handle-402.js
const res = await fetch('https://api.bezbrany.cz/api/v1/payments', { method: 'POST', headers, body });

if (res.status === 402) {
  const err = await res.json();
  if (err.code === 'PLAN_LIMIT_REACHED') {
    // 1) Zákazníkovi nezobrazujte technickou chybu — nabídněte náhradní platbu
    //    (ruční převod podle údajů z objednávky, dobírka…)
    showManualPaymentInstructions(order);
    // 2) Upozorněte obchodníka (e-mail, Slack, log) — err.details.upgradeTo
    notifyMerchant(`Limit tarifu ${err.details.plan} vyčerpán (${err.details.current}/${err.details.max})`);
    return;
  }
}

Widget integrace

Nejjednodušší způsob integrace — vložte skript a kontejner do HTML. Widget zobrazí QR kód, sleduje stav platby v reálném čase a po zaplacení zobrazí potvrzení.

index.html
<script src="https://api.bezbrany.cz/widget/v1.js"></script>
<div data-bezbrany-widget data-payment-code="VAS_PLATEBNI_KOD"></div>

Podporované data-* atributy:

  • data-bezbrany-widget — označí kontejner widgetu
  • data-payment-code — kód platby získaný z API

Alternativně lze widget inicializovat programaticky přes BezBranyWidget.init({ paymentCode, containerId, onPaymentSuccess }).

Odpověď GET /api/v1/widget/payments/{paymentCode} obsahuje pole branding (boolean). Na tarifu Free je true a widget i hostovaný checkout zobrazí v patičce nenápadný odkaz „Platby přes BezBrany“. Pokud vykreslujete platbu sami, můžete se podle pole řídit také.

Webhooky

Webhooky jsou dostupné v tarifech Start a Pro. Na tarifu Free se po spárování platby webhook neodešle (ani při simulaci testovací platby) — obchodník dostane jen e-mail o přijaté platbě. Stav platby pak ověříte přes GET /api/v1/payments/{paymentCode}.

Po dokončení platby odešleme POST request na vaši webhook URL (nastavíte v profilu merchanta nebo per platba přes callback.notificationUrl). Payload:

webhook-payload.json
{
  "id": "b7c3e1a2-...",
  "event": "payment.completed",
  "createdAt": "2026-07-24T10:12:30.000Z",
  "paymentId": "uuid",
  "paymentCode": "A1B2C3D4E5F6A7B8",
  "orderNumber": "OBJ-2026-001",
  "status": "completed",
  "amount": 100,
  "currency": "CZK",
  "metadata": {}
}

Pole id je unikátní pro každé doručení — použijte ho k deduplikaci (opakované doručení má stejné id). Podle event filtrujte typ události; ignorujte neznámé typy, ať vás nerozbijí budoucí události.

Každý webhook je podepsán HMAC SHA-256 pomocí vašeho webhook secretu. Ověření podpisu:

verify-webhook.js
// Hlavička: X-BezBrany-Signature: t=<timestamp>,v1=<podpis>
const crypto = require('crypto');

function verifyWebhook(rawBody, signatureHeader, secret) {
  const parts = Object.fromEntries(
    signatureHeader.split(',').map(p => p.split('='))
  );
  const signedPayload = `${parts.t}.${rawBody}`;
  const expected = crypto.createHmac('sha256', secret)
    .update(signedPayload)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(expected), Buffer.from(parts.v1)
  );
}

Při selhání doručení webhook opakujeme s exponenciálním rozestupem (1 min → 5 min → 30 min → 2 h).