Přehled REST API

Všechny MCP nástroje odpovídají 1:1 REST endpointům. REST API použijte přímo pro CI/CD pipeline, integrace bez MCP, obsluhu webhooků, automatizaci na serveru nebo z jakéhokoli HTTP klienta.

Základní adresa: https://api.briefgate.dev

Požadavky i odpovědi jsou v JSON (Content-Type: application/json). Všechna časová razítka jsou v ISO 8601 a v UTC.


Autentizace

API klíč posílejte v každém požadavku jako Bearer token:

Authorization: Bearer bg_live_xxxxx

Správa API klíčů

POST   /v1/keys         Vytvořit nový klíč
GET    /v1/keys         Vypsat všechny klíče
DELETE /v1/keys/:id     Zneplatnit klíč
DELETE /v1/keys/current Odvolá klíč, kterým je požadavek podepsaný (volá to logout v MCP balíčku)

Vytvoření klíče:

bash
curl -X POST https://api.briefgate.dev/v1/keys \
  -H "Authorization: Bearer bg_live_xxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "CI/CD pipeline",
    "mode": "live",
    "scopes": ["intakes:read", "intakes:write"]
  }'

Režimy klíčů. mode je live (výchozí) nebo test. Testovací klíč (bg_test_…) vidí jen sběry podkladů, které sám vytvořil, a ty nikdy nepošlou klientovi e-mail ani SMS — pozvánky a upomínky se zapíší jako skipped, vše ostatní (portál, webhooky, výsledky) funguje normálně. Hodí se pro CI a zkoušení; samostatná schránka neexistuje, sběr zkontrolujete v dashboardu.

Dostupné scopy: admin, intakes:read, intakes:write, secrets:read. Scope admin zahrnuje všechny ostatní. Správa klíčů samotná je jen pro session: POST /v1/keys, GET /v1/keys i DELETE /v1/keys/:id vyžadují přihlášeného uživatele v dashboardu — API klíč nemůže vytvořit ani vypsat jiné klíče. Jedinou výjimkou je DELETE /v1/keys/current, protože ten odvolává přímo klíč, kterým je požadavek podepsaný.


Formát chyb

Všechny chyby vracejí JSON:

json
{
  "error": "not_found",
  "message": "Intake in_8f3k not found or does not belong to this account.",
  "request_id": "req_abc123"
}

Některé chyby nesou navíc: stabilní slug reason a strojově čitelné params, nebo — u požadavku, který neprošel validací polí — pole details s dvojicemi { path, message }, jedna na každé chybné pole:

json
{
  "error": "unprocessable",
  "message": "items.0.constraints: min_count must not exceed max_count",
  "reason": "validation_failed",
  "params": { "field": "items.0.constraints" },
  "details": [
    { "path": "items.0.constraints", "message": "min_count must not exceed max_count" }
  ],
  "request_id": "req_abc123"
}

Když se obracíte na podporu, přiložte request_id.

Chybové kódy

HTTP stav Hodnota error Význam
400 invalid_request Vadný JSON, nebo požadavek, který je formálně v pořádku, ale je neplatný vzhledem k aktuálnímu stavu zdroje (třeba odvolání už odvolaného klíče). Podrobnosti jsou v message.
401 unauthorized Chybějící nebo neplatný API klíč.
403 forbidden Klíč nemá pro tuhle operaci potřebný scope.
404 not_found Zdroj neexistuje nebo patří jinému účtu.
409 conflict Zdroj se stejným identifikátorem už existuje (třeba duplicitní idempotency_key v době platnosti). Vrátí stávající zdroj.
410 gone Jednorázová hodnota vypršela a byla smazána — třeba vyplněný secret po uplynutí lhůty na odhalení. Opětovné čtení už odhaleného tajemství tohle NENÍ: to vrátí HTTP 200 s already_revealed: true.
413 payload_too_large Rezervováno pro budoucí použití — žádný endpoint ho nevrací pro příliš velké tělo požadavku. Příliš velký nahraný soubor se odmítne jako 422 unprocessable s nálezem file.too_large.
413 download_too_large Sběr podkladů překračuje limit velikosti pro stažení ZIP (GET /v1/intakes/:id/download) — pro vyzvednutí velkého sběru po jednotlivých položkách viz Stažení všeho v ZIPu.
422 unprocessable Požadavek neprošel validací: chybějící nebo špatně zadané povinné pole, hodnota mimo povolený rozsah, nebo požadavek, který je strukturálně v pořádku, ale významově ne (třeba min_count větší než max_count). Tohle vrací i chybějící povinné pole, ne 400 — které pole, ukazuje details.
429 rate_limited Příliš mnoho požadavků. Před dalším pokusem se řiďte hlavičkou Retry-After (v sekundách).
402 quota_exceeded Vyčerpaná měsíční kvóta na sběry podkladů nebo úložiště.
402 plan_required Funkce není v aktuálním tarifu k dispozici.
500 internal_error Neočekávaná chyba serveru. Je bezpečné to zkusit znovu s rostoucí prodlevou.
503 service_unavailable Databáze je dočasně nedostupná. Řiďte se hlavičkou Retry-After (v sekundách) a zkuste to znovu.

Intakes

POST /v1/intakes

Založí nový sběr podkladů a pošle klientovi odkaz na jeho portál.

Hlavičky požadavku

Hlavička Popis
Idempotency-Key Nepovinná. Jedinečný řetězec (doporučujeme UUID). Když už s tímhle klíčem sběr podkladů vznikl, vrátí se původní (HTTP 200) místo vytvoření duplikátu.

Hlavní pole požadavku

Pole Typ Povinné Popis
project_name string Ano Název projektu srozumitelný člověku.
client.email string Ano E-mailová adresa klienta.
client.name string Ano Jméno klienta pro oslovení — každá pozvánka jím začíná, takže nemůže být prázdné.
client.language string Ne cs, sk, pl, de, es, en. Když chybí, použije se default_language účtu, pak angličtina.
client.phone string Ne Formát E.164, např. +420601123456. Rezervováno pro SMS upomínky (chase_schedule s kanálem sms, viz Rozvrhy upomínek).
client.timezone string Ne Časové pásmo IANA, např. Europe/Prague. Podle něj se řídí respect_quiet_hours a chase_at_time. Výchozí Europe/Prague.
client.also_notify array Ne Až 4 další lidé ({ email, name? }), kteří dostanou stejný odkaz na portál a stejné upomínky jako primární klient. Přidat nebo odebrat je jde i po založení přes POST/DELETE /v1/intakes/:id/recipients (viz Příjemci).
email_copy object Ne Přebije předmět a úvodní text pro tenhle sběr podkladů. Viz chase.md.
client_brief string Ne Informace a kontext pro klienta — zobrazí se v horní části portálu, před požadovanými položkami, jako „Informace od <vaše jméno>". Max 5000 znaků; oříznuté; prázdný řetězec se uloží jako null. Soubory přiložíte přes POST /v1/intakes/:id/brief/files, až sběr podkladů existuje — viz Brief pro klienta.
items array Ano Definice položek. Viz item-types.md. Povinné (min. 1) i když je vyplněné template.
template string Ne Slug uložené šablony (templates.md). Položky šablony se s items slučují podle key. Každé další pole, které nastavuje settings šablony, se použije jako výchozí hodnota — jen tam, kde ho tenhle požadavek sám nevyplní.
chase_schedule string Ne default, gentle, aggressive, custom nebo off.
chase_interval integer Ne Jak často upomínat, jen s chase_schedule: "custom". Používá se spolu s chase_interval_unit. Výchozí: každé 3 dny. S jiným rozvrhem vrátí 422.
chase_interval_unit string Ne minutes, hours nebo days (výchozí days). Výsledný interval musí být aspoň 5 minut a nejvýš 90 dní.
respect_quiet_hours boolean Ne Držet upomínky v okně 8:00–19:00 podle klienta. Výchozí true.
max_reminders integer | string Ne Počet upomínek, než se sběr podkladů označí za zaseknutý (1–1000, výchozí 3, nebo "unlimited").
chase_at_time string Ne Místní denní hodina upomínky ve formátu HH:MM. Vyžaduje chase_schedule: "custom" s intervalem v celých dnech.
due_date string Ne Datum v ISO 8601, které uvidí klient.
send boolean Ne false založí koncept bez odeslání. Odeslat později můžete přes POST /v1/intakes/:id/send. Výchozí true.
retention object Ne Jak dlouho držet data po dokončení. { mode: "days"|"on_delivery", days?: number, anonymize?: boolean }. Výchozí: smazat 90 dní po intake.completed. U sběru podkladů s přístupy použijte mode: "on_delivery" — obsah zmizí zhruba 24 hodin po vyzvednutí výsledků.
folder_id string Ne Zařadí sběr podkladů do téhle složky — id z GET /v1/folders. Když chybí, sběr podkladů zůstane nezařazený. Musí patřit na váš vlastní účet, jinak 400 invalid_request (reason validation_error).

Rozvrhy upomínek

Rozvrh Upomínky
default za 2, 5 a 9 dní, pak jednou týdně
gentle za 3 a 8 dní, pak jednou za dva týdny (o víkendech nic nepošle, posune na pondělí 8:00)
aggressive za 1, 3 a 5 dní, pak obden
custom Každých chase_interval chase_interval_unit (výchozí každé 3 dny), první jeden interval po pozvánce
off Žádné automatické upomínky

Odpověď (HTTP 201)

json
{
  "intake_id": "in_8f3kQmR2",
  "portal_url": "https://p.briefgate.dev/8f3kqmr2",
  "status": "sent",
  "items": [
    { "key": "logo",       "status": "pending" },
    { "key": "hero_copy",  "status": "pending" }
  ],
  "follow_up": {
    "recommended": "schedule",
    "reason": "No active webhook endpoints are registered on this account.",
    "webhook": {
      "active_endpoints": 0,
      "events": ["item.submitted", "intake.completed"],
      "register_with": "manage_webhook"
    },
    "schedule": {
      "check_with": "get_intake_status",
      "every_hours": 24,
      "until": "2024-03-29T10:22:00Z"
    }
  }
}

follow_up je vždy přítomné a napovídá, jak sledovat postup bez slepého pollování. recommended je "webhook", pokud už aktivní endpoint pokrývá relevantní eventy, nebo "schedule", pokud ne — v tom případě volejte GET /v1/intakes/:id/status každých follow_up.schedule.every_hours hodin až do follow_up.schedule.until, nebo si místo toho zaregistrujte webhook (POST /v1/webhooks, viz Webhooks).

Kompletní příklad s curl

bash
curl -X POST https://api.briefgate.dev/v1/intakes \
  -H "Authorization: Bearer bg_live_xxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: bella-napoli-website-2024" \
  -d '{
    "project_name": "Bella Napoli — Website",
    "client": {
      "email": "owner@bellanapoli.com",
      "name": "Marco Esposito",
      "language": "en"
    },
    "items": [
      {
        "key": "logo",
        "label": "Restaurant logo",
        "help": "SVG or PNG, transparent background, minimum 512px.",
        "type": "image",
        "required": true,
        "constraints": {
          "formats": ["svg", "png"],
          "min_width": 512,
          "transparent_background": true
        }
      },
      {
        "key": "hero_copy",
        "label": "Hero section tagline",
        "type": "longtext",
        "required": true,
        "constraints": { "max_chars": 400 }
      },
      {
        "key": "opening_hours",
        "label": "Opening hours",
        "type": "structured",
        "required": true,
        "schema": {
          "type": "object",
          "required": ["mon_fri", "sat", "sun"],
          "properties": {
            "mon_fri": { "type": "string" },
            "sat":     { "type": "string" },
            "sun":     { "type": "string" }
          }
        }
      },
      {
        "key": "photos",
        "label": "Food and interior photos",
        "type": "file_list",
        "required": true,
        "constraints": {
          "formats": ["jpg", "png", "heic"],
          "min_count": 5,
          "max_count": 15
        }
      }
    ],
    "chase_schedule": "default",
    "due_date": "2024-04-01"
  }'

GET /v1/intakes

Vypíše sběry podkladů s volitelnými filtry.

Parametry dotazu

Parametr Popis
status Filtr podle stavu: draft, sent, in_progress, completed, archived.
client_email Filtr na konkrétního klienta.
folder_id Filtr na jednu složku — id z GET /v1/folders, nebo doslovné none pro sběry podkladů bez složky.
q Hledání podřetězce bez ohledu na velikost písmen v project_name, client.name a client.email (1–100 znaků). Kombinuje se s ostatními filtry.
limit Počet výsledků na stránku (výchozí 20, maximum 100).
offset Posun pro stránkování (výchozí 0).

Odpověď

json
{
  "intakes": [
    {
      "intake_id": "in_8f3kQmR2",
      "project_name": "Bella Napoli — Website",
      "status": "in_progress",
      "client": {
        "email": "owner@bellanapoli.com",
        "name": "Marco Esposito"
      },
      "portal_url": "https://p.briefgate.dev/8f3kqmr2",
      "created_at": "2024-03-15T10:22:00Z",
      "progress": { "submitted": 3, "total": 7 }
    }
  ],
  "total": 47,
  "limit": 20,
  "offset": 0
}

Poznámka: Každý sběr podkladů odpovídá stejnému snake_case tvaru, jaký se používá všude jinde v tomhle API, navíc s přehledem progress za daný sběr podkladů — kompletní popis polí najdete u GET /v1/intakes/:id a GET /v1/intakes/:id/status.


GET /v1/intakes/:id

Vrátí kompletní definici sběru podkladů včetně všech definic položek a metadat.

Odpověď

json
{
  "intake": {
    "intake_id": "in_8f3kQmR2",
    "project_name": "Bella Napoli — Website",
    "status": "in_progress",
    "mode": "live",
    "portal_url": "https://p.briefgate.dev/8f3kqmr2",
    "client": {
      "email": "owner@bellanapoli.com",
      "name": "Marco Esposito",
      "phone": null,
      "language": "en",
      "timezone": "Europe/Rome",
      "also_notify": [
        { "email": "chef@bellanapoli.com", "name": "Giulia", "bounced_at": null }
      ],
      "client_bounced_at": null
    },
    "branding": null,
    "folder_id": null,
    "chase_schedule": "default",
    "chase_interval_minutes": null,
    "respect_quiet_hours": true,
    "max_reminders": 3,
    "chase_at_time": null,
    "due_date": "2024-04-01",
    "retention": { "mode": "days", "days": 90, "anonymize": true },
    "created_at": "2024-03-15T10:22:00Z",
    "sent_at": "2024-03-15T10:22:05Z",
    "completed_at": null,
    "delivered_at": null,
    "anonymized_at": null,
    "client_last_seen": "2024-03-16T14:05:33Z",
    "stalled_at": null,
    "purge_at": null,
    "client_note": null,
    "owner_note": null,
    "client_brief": null,
    "brief_files": []
  },
  "items": [
    {
      "key": "hero_copy",
      "type": "longtext",
      "assignee": "client",
      "label": "Hero section tagline",
      "help": null,
      "required": true,
      "status": "approved",
      "value": "Real Napoli-style pizza, right in your neighbourhood.",
      "constraints": { "max_chars": 400 },
      "options": null,
      "pattern": null,
      "submitted_at": "2024-03-16T11:00:00Z",
      "approved_at": "2024-03-16T11:05:00Z",
      "revision_note": null,
      "revision_count": 0,
      "waiver": { "state": "none", "reason": null, "requested_by": null, "requested_at": null, "decided_at": null },
      "client_note": null,
      "owner_note": null
    }
  ],
  "progress": { "submitted": 2, "total": 4, "outstanding": 2, "percent": 50 },
  "owner_tasks": { "done": 0, "total": 0 }
}

chase_interval_minutes je normalizovaná hodnota chase_interval/chase_interval_unit; je null, dokud chase_schedule není "custom". Položka typu file, file_list nebo image nese navíc pole files (id, filename, mime, size, width/height, av_status, checksum_sha256) místo smysluplné value — podepsaná adresa se tu nevytváří; stáhněte ji přes GET /v1/intakes/:id/items/:key/files/:fileId (níže) nebo GET /v1/intakes/:id/results. Vlastníkova položka typu select/multiselect ("rozhodnutí") nese navíc objekt decision: { decided_by: "agent"|"owner", value, proposed_value, proposed_rationale }.

brief_files — přílohy k client_brief — je jen v téhle podrobné odpovědi, ne v GET /v1/intakes (dotaz na každý řádek při každém zobrazení seznamu by běžel pro každý sběr podkladů, přitom naprostá většina brief nemá). Každá položka je { id, filename, mime, size, av_status, created_at }, se stejným pravidlem dostupnosti jako u souboru položky (av_status rozhoduje, jestli stažení vůbec půjde). Text i soubory brief spravujete přes Brief pro klienta níže.


PATCH /v1/intakes/:id

Upraví existující sběr podkladů místo jeho mazání a zakládání nového — což dřív bylo jediné možné řešení a klientovi to poslalo novou pozvánku. Všechna pole jsou nepovinná, ale aspoň jedno musí být zadané (jinak 400 invalid_request). null smaže owner_note, client_brief, due_date a chase_at_time; vynechané pole vždy zůstává beze změny.

Pole Typ Poznámky
owner_note string | null Klientovi se nikdy nezobrazí.
client_brief string | null Informace pro klienta, zobrazí se v horní části portálu — viz client_brief u POST /v1/intakes. null ho smaže; prázdný řetězec se také uloží jako null.
project_name string
due_date string | null YYYY-MM-DD.
chase_schedule string default, gentle, aggressive, custom, off.
chase_interval / chase_interval_unit integer / string Stejná pravidla jako u POST /v1/intakes — má smysl jen s chase_schedule: "custom".
chase_at_time string | null HH:MM, vyžaduje interval v celých dnech.
max_reminders integer | "unlimited"
respect_quiet_hours boolean
client.name, .phone, .language, .timezone Bez client.email. Odkaz do portálu a magic token jsou navázané na hlavní adresu — její změna by tady klientův stávající odkaz odřízla. Adresy přidávejte, odebírejte nebo obnovujte přes endpointy pro příjemce.
folder_id string | null Přesune sběr podkladů do téhle složky, nebo null pro přesun mezi nezařazené. Musí patřit na váš vlastní účet (jinak 400 invalid_request, reason validation_error). Nikdy neovlivní status, upomínky ani nic dalšího.

Změna rytmu u živého sběru podkladů. U sběru podkladů ve stavu sent, in_progress nebo zaseknutého změna kteréhokoli z polí chase_schedule, chase_interval, chase_interval_unit, chase_at_time, max_reminders, respect_quiet_hours, client.timezone nebo due_date zruší všechny ještě naplánované upomínky a naplánuje je znovu podle nového nastavení. Upomínky, které už odešly, se pořád počítají do max_reminders — číslování pokusů se neresetuje.

Odblokování zaseknutého sběru podkladů. Sběru podkladů, kterému došel max_reminders, se upomínání zastaví a nastaví se mu stalled_at (viz Strop upomínek). Zvýšení max_reminders (nebo nastavení na "unlimited") nad počet už odeslaných upomínek stalled_at zruší a automatické upomínání se obnoví. Změna ostatních polí u pořád zaseknutého sběru podkladů uložené nastavení aktualizuje, ale sama o sobě upomínání neobnoví.

U archivovaného sběru podkladů vrátí 409 conflict (reason intake_archived).

Požadavek

json
{
  "chase_schedule": "custom",
  "chase_interval": 6,
  "chase_interval_unit": "hours",
  "max_reminders": 12
}

Odpověď je { "intake": { ... } }, stejný tvar jako objekt intake u GET /v1/intakes/:id.


GET /v1/intakes/:id/items/:key/files/:fileId

Stáhne nebo zobrazí náhled jednoho souboru, který nahrál klient. Odpoví HTTP přesměrováním 302 na podepsanou adresu (platnost 24 hodin) místo JSON — použijte ji přímo jako <a href>/<img src>. Vrátí 422 unprocessable, pokud soubor ještě čeká na antivirovou kontrolu nebo byl označen jako infikovaný.


POST /v1/intakes/:id/brief/files

Přiloží soubor k briefu pro klienta — texty a dokumenty, které klientovi předáváte, zobrazí se v horní části portálu před požadovanými položkami (viz client_brief u POST /v1/intakes). multipart/form-data s jedním polem file. Jde přes stejný proces jako klientovo vlastní nahrání: skutečný typ obsahu se rozpoznává, ne jen věří deklarovanému, HEIC se konvertuje na JPEG a antivirová kontrola proběhne dřív, než se soubor uloží — infikovaný soubor se odmítne rovnou (422 unprocessable), ne že by se uložil a skryl.

Brief unese nejvýš 10 souborů; jedenáctý vrátí 422 unprocessable. Počítá se do stejné kvóty úložiště jako všechno ostatní na účtu. U archivovaného sběru podkladů vrátí 409 conflict (reason intake_archived).

Odpověď (HTTP 201)

json
{
  "file": {
    "id": "bff_9k2mQ7xR",
    "filename": "contract-offer.pdf",
    "mime": "application/pdf",
    "size": 184320,
    "av_status": "clean",
    "created_at": "2024-03-15T10:20:00Z"
  }
}

DELETE /v1/intakes/:id/brief/files/:fileId

Odstraní jednu přílohu briefu a uvolní její bajty z kvóty úložiště. Vrátí 204 No Content. U archivovaného sběru podkladů vrátí 409 conflict (reason intake_archived).


GET /v1/intakes/:id/brief/files/:fileId/url

Stáhne nebo zobrazí náhled jedné přílohy briefu. Stejná konvence jako GET /v1/intakes/:id/items/:key/files/:fileId výše: HTTP přesměrování 302 na podepsanou adresu a 422 unprocessable, dokud soubor čeká na antivirovou kontrolu nebo je označen jako infikovaný.


GET /v1/intakes/:id/status

Lehký stavový endpoint. Vrátí stavy položek, historii upomínek a postup, bez obsahu souborů a podepsaných adres.

Odpověď

progress.total počítá jen to, na co se čeká: prominutá položka i nevyplněná volitelná položka jsou mimo jmenovatel. Díky tomu je percent rovno 100 přesně ve chvíli, kdy se status změní na completed.

json
{
  "status": "in_progress",
  "due_date": "2024-04-01",
  "client_last_seen": "2024-03-16T14:05:33Z",
  "progress": {
    "submitted": 2,
    "total": 4,
    "outstanding": 2,
    "percent": 50
  },
  "items": [
    { "key": "logo",          "status": "approved",       "submitted_at": "2024-03-16T10:00:00Z", "label": "Restaurant logo",         "assignee": "client", "required": true },
    { "key": "hero_copy",     "status": "needs_revision", "submitted_at": "2024-03-16T11:00:00Z", "label": "Hero section tagline",     "assignee": "client", "required": true },
    { "key": "opening_hours", "status": "pending",        "submitted_at": null,                   "label": "Opening hours",            "assignee": "client", "required": true },
    { "key": "photos",        "status": "submitted",      "submitted_at": "2024-03-16T12:00:00Z", "label": "Food and interior photos", "assignee": "client", "required": true }
  ],
  "chases": [
    { "id": "chs_a1", "channel": "email", "kind": "invite",   "scheduled_at": "2024-03-15T10:22:00Z", "sent_at": "2024-03-15T10:22:05Z", "status": "sent",      "attempt_no": 1, "missing_items_count": null, "error": null },
    { "id": "chs_a2", "channel": "email", "kind": "reminder", "scheduled_at": "2024-03-17T09:00:00Z", "sent_at": "2024-03-17T09:00:00Z", "status": "sent",      "attempt_no": 2, "missing_items_count": 2,    "error": null },
    { "id": "chs_a3", "channel": "email", "kind": "reminder", "scheduled_at": "2024-03-20T09:00:00Z", "sent_at": null,                   "status": "scheduled", "attempt_no": 3, "missing_items_count": null, "error": null }
  ]
}

items[].assignee (client/owner) a .required jsou přítomné vždy; vlastníkova položka typu rozhodnutí nese navíc stejný objekt decision jako je popsaný u GET /v1/intakes/:id. chases[].kind je jedna z hodnot invite, reminder, revision, manual; .status je jedna z scheduled, sent, failed, bounced, complained, cancelled, skipped. scheduled_at udává, kdy je naplánovaná další čekající upomínka — místo odhadování z chase_schedule sledujte tohle.


GET /v1/intakes/:id/results

Vrátí otypované výsledky schválených položek. U souborů a obrázků jsou podepsané adresy s platností 24 hodin.

Jen API klíč — na rozdíl od všech ostatních endpointů kolem sběru podkladů tenhle neakceptuje session z dashboardu. Odhaluje tajemství a posouvá kurzor only_new vázaný na konkrétní API klíč, a obojí dává smysl jen pro agentův vlastní API klíč; dashboard místo toho používá GET /v1/intakes/:id a POST /v1/intakes/:id/items/:key/reveal.

Parametry dotazu

Parametr Typ Popis
only_new boolean Vrátí jen položky schválené od posledního volání tohoto endpointu (sleduje se podle API klíče).
include_pending boolean Zahrne i položky ve stavu submitted, které ještě nejsou schválené.
exclude_secrets boolean Vynechá položky typu secret bez jejich odhalení — meta hlásí secret_unavailable: true a jednorázové odhalení zůstává k dispozici. Hodí se pro integrace, které ukládají každou odpověď (Zapier, Make, n8n).

Odpověď

json
{
  "intake_id": "in_8f3kQmR2",
  "status": "in_progress",
  "progress": { "submitted": 2, "total": 4, "outstanding": 2, "percent": 50 },
  "missing": ["opening_hours"],
  "results": {
    "logo": { "url": "https://...", "filename": "logo.svg", "mime": "image/svg+xml", "size": 4821, "checksum_sha256": "..." },
    "hero_copy": "Real Napoli-style pizza, right in your neighbourhood."
  },
  "meta": {
    "logo": { "type": "image", "status": "approved", "submitted_at": "2024-03-16T10:00:00Z" },
    "hero_copy": { "type": "longtext", "status": "approved", "submitted_at": "2024-03-16T11:00:00Z" }
  }
}

results obsahuje jeden záznam na každou zahrnutou položku, klíčovaný jejím key, ve tvaru podle jejího type — položka secret tu svou hodnotu odhalí přesně jednou (viz níže) a při každém dalším čtení ji meta hlásí místo toho jako { secret_unavailable: true, reason, revealed_at }. missing vypisuje klíče povinných klientských položek, které pořád chybí. Čtení položky secret vyžaduje scope secrets:read (nebo admin); bez něj se položka vynechá z results i meta a meta místo toho nese { secret_unavailable: true, reason: "Scope 'secrets:read' or 'admin' required." }. Položka typu file/file_list, která ještě není dostupná (čeká na antivirovou kontrolu, nebo je infikovaná), se z výpisu souborů podobně vynechá a meta[key].files_pending udává jejich počet.


POST /v1/intakes/:id/items/:key/reveal

Odhalí hodnotu jedné položky typu secret. Jen session — způsob, jakým dashboard čte přístupový údaj; API klíč musí místo toho použít GET /v1/intakes/:id/results se scopem secrets:read, a zavolat to smí jen vlastník účtu (jiný člen týmu dostane 403 forbidden, reason secrets_owner_only). Stejně jako u /results se hodnota uvolní přesně jednou.

Odpověď (první odhalení)

json
{ "key": "admin_password", "value": "hunter2", "first_reveal": true, "expires_at": "2024-03-23T10:00:00Z" }

Odpověď (už odhaleno — HTTP 200, ne chyba)

json
{ "key": "admin_password", "value": null, "already_revealed": true, "revealed_at": "2024-03-16T10:05:00Z", "message": "This credential was already revealed. Secrets are shown once and cannot be shown again." }

POST /v1/intakes/:id/items

Přidá položky do existujícího sběru podkladů. Klientovi přijde e-mail.

Tělo požadavku

json
{
  "items": [
    {
      "key": "favicon",
      "label": "Favicon",
      "type": "image",
      "required": true,
      "constraints": { "formats": ["png","svg"], "min_width": 32 }
    }
  ]
}

Odpověď

json
{
  "intake_id": "in_8f3kQmR2",
  "items_added": [
    { "key": "favicon", "status": "pending" }
  ]
}

PATCH /v1/intakes/:id/items/:key

Změní jednu položku u požadavku, který už je u klienta — typ, popisek, nápovědu, povinnost i povolené formáty. Nese zároveň owner_note.

Hodí se, když se ukáže, že pole má špatný tvar: chtěli jste obrázek a klient má logo jen v PDF, nebo to, co jste žádali jako text, je ve skutečnosti soubor. Rozšíření formátů nebo změna typu klienta odblokuje, aniž byste přidávali duplicitní položku a původní promíjeli.

key změnit nejde — pod tím jménem se vracejí výsledky. Přidejte místo toho novou položku.

Pokud klient položku už vyplnil a změna by jeho odpověď zneplatnila, volání skončí 409 item_answer_would_be_discarded a nic se nezmění. Zopakujte ho s discard_submitted_value: true, čímž se odpověď smaže a klient ji vyplní znovu. Změna, po které odpověď dál platí (nový popisek, volnější limit), nezahodí nikdy nic.

Požadavek

json
{
  "type": "file",
  "label": "Logo",
  "constraints": { "formats": ["svg", "png", "pdf"] }
}

POST /v1/intakes/:id/revision

Vyžádá opravu konkrétní položky. Platí jen tehdy, když je stav položky submitted nebo approved (jinak 409 conflict). Vyžaduje funkci revisions — na tarifu Free není k dispozici (jinak 402 plan_required).

Tělo požadavku

json
{
  "item_key": "logo",
  "note": "The logo appears blurry at 320px. Please re-export at minimum 512px, ideally as SVG."
}

Odpověď

json
{
  "intake_id": "in_8f3kQmR2",
  "item_key": "logo",
  "status": "needs_revision",
  "client_notified": true
}

POST /v1/intakes/:id/items/:key/done

Odškrtnutí vlastního úkolu — položky vytvořené s "assignee": "owner".

Tělo požadavku

json
{
  "done": true
}

done je nepovinné a výchozí hodnota je true. Pošlete false pro znovuotevření úkolu.

Odpověď

json
{
  "key": "call_client",
  "done": true,
  "status": "approved"
}

Přijímají se jen vlastní úkoly. Klientská položka vrátí 400 — tu odpověď dává klient v portálu. Odškrtnutí úkolu nikdy sběr podkladů nedokončí ani nedoručí: vlastní úkoly jsou záměrně mimo postup klienta.


POST /v1/intakes/:id/items/:key/received-outside

Označí klientskou položku jako přijatou mimo BriefGate — klient poslal soubor e-mailem, předal ho na schůzce nebo jiným kanálem. Od té chvíle se položka počítá jako hotová, takže sběr podkladů může skončit, i když portálem nic nepřišlo. Pokud šlo o poslední chybějící položku, sběr se dokončí úplně stejně, jako by klient klikl na „Odeslat podklady“: spustí se webhook intake.completed a odejde volitelný děkovný e-mail.

Tělo požadavku

json
{
  "note": "Poslala e-mailem 5. 9."
}

note je nepovinná — krátká připomínka, kde podklad ve skutečnosti je. Zobrazuje se u položky v dashboardu, klient ji nikdy nevidí.

Odpověď

json
{
  "key": "logo",
  "status": "approved",
  "received_outside": true,
  "intake_status": "completed"
}

Přijímají se jen klientské položky; vlastní úkol vrátí 400 — ten se odškrtává přes /done. Položka, která už je schválená nebo prominutá, vrátí 409 (nejdřív zrušte prominutí), stejně jako archivovaný sběr podkladů. Každá položka v GET /v1/intakes/:id i ve výsledcích nese received_outside a received_outside_note, takže agent, který čte výsledky, ví, že podklad existuje, ale v BriefGate uložený není.


DELETE /v1/intakes/:id/items/:key/received-outside

Zruší označení. Položka se vrátí mezi ty, na které se čeká od klienta, a ukazatel postupu se odpovídajícím způsobem sníží; sběr podkladů, který se tímto označením dokončil, se znovu otevře stejně jako při zrušení prominutí. Pokud položka označená nebyla, vrátí 404.


POST /v1/intakes/:id/items/:key/answer

Rozhodne o rozhodnutí — vlastníkově položce typu select/multiselect, která volitelně nese agentovu vlastní navrhovanou odpověď (items[].proposed, viz POST /v1/intakes). value se ověřuje proti vlastním options položky, stejně jako u klientské odpovědi.

Záměrně jen session. API klíč tohle zavolat nemůže: ten drží AGENT, a přijetí by mu umožnilo potvrdit vlastní návrh a mít výsledek zaznamenaný jako decided_by: "owner" — přesně tomu má oddělení návrhu od odpovědi zabránit. Položka, která není rozhodnutím, vrátí 400 invalid_request.

Požadavek

json
{ "value": "29" }

Odpověď

json
{ "key": "attendee_count", "value": "29", "status": "approved", "decided_by": "owner" }

POST /v1/intakes/:id/items/:key/waive

Vlastník položku rovnou uzavře ("tohle mít nebudeme"). Přímo prominout smí jen vlastník — klient v portálu může prominutí jen navrhnout, o kterém pak vlastník rozhodne endpointem níže.

Požadavek

json
{ "reason": "Client doesn't have a logo yet; using a text wordmark instead." }

reason je nepovinný. Odpověď je { "item": { ... } }, stejný tvar položky jako u GET /v1/intakes/:id.


POST /v1/intakes/:id/items/:key/waive/decision

Vlastník přijme nebo zamítne prominutí, které navrhl klient. Vrátí 409 conflict, pokud u položky žádný návrh na prominutí nečeká na rozhodnutí.

Požadavek

json
{ "accept": true, "note": "Confirmed with the client by phone." }

Přijetí přesune položku do stavu waived; zamítnutí nechá její stav beze změny, ale zruší příznak čekání na vlastníka, takže se znovu upomíná jako každá jiná nevyřízená položka. note je jen pro auditní log. Odpověď je { "item": { ... } }.


DELETE /v1/intakes/:id/items/:key/waive

Vrátí prominutí zpátky do stavu pending a zahodí přitom hodnotu, odeslání i poznámku k opravě, které položka měla — klienta je tak jako tak potřeba požádat znovu. Pokud sběr podkladů dosáhl stavu completed, znovu se otevře na in_progress a naplánují se upomínky. Odpověď je { "item": { ... } }.


POST /v1/intakes/:id/recipients

Přidá dalšího člověka ke sběru podkladů, který už byl odeslán. Dostane stejný odkaz na portál a stejné budoucí upomínky jako primární klient; samotné volání e-mail neposílá — pošlete ho přes POST /v1/intakes/:id/send nebo .../chase. Nejvýš 4 další příjemci (5 celkem včetně primárního klienta); 409 conflict (reason recipient_exists), pokud už adresa na sběru podkladů je.

Požadavek

json
{ "email": "chef@bellanapoli.com", "name": "Giulia" }

Odpověď (HTTP 201)

json
{
  "intake_id": "in_8f3kQmR2",
  "also_notify": [
    { "email": "chef@bellanapoli.com", "name": "Giulia", "bounced_at": null }
  ]
}

DELETE /v1/intakes/:id/recipients/:email

Odebere dalšího příjemce (adresu URL-encodujte). Primárního klienta takhle odebrat nejde — na jeho změnu použijte PATCH /v1/intakes/:id, nebo založte sběr podkladů znovu přes POST /v1/intakes — při pokusu vrátí 400 invalid_request (reason recipient_is_primary). Při úspěchu vrací HTTP 204, 404 not_found, pokud adresa na sběru podkladů není.


POST /v1/intakes/:id/recipients/:email/reinstate

Zruší příznak odrazu na jedné adrese (URL-encodujte ji), ať jde o hlavní nebo další příjemce — pro odraz, který byl falešný poplach, nebo schránku, kterou klient mezitím opravil a požádal o opětovné zařazení. Pokud předtím nebyl nikdo, koho by šlo upomínat (odrazily se všechny adresy), a sběr podkladů je sent nebo in_progress, automatické upomínání se obnoví.

Vrátí 404 not_found (reason recipient_not_found), pokud adresa na sběru podkladů není, 409 conflict (reason recipient_not_bounced), pokud se nikdy neodrazila.

Odpověď (HTTP 200)

json
{
  "email": "owner@bellanapoli.com",
  "bounced_at": null,
  "still_chasing": true
}

still_chasing říká, jestli tahle adresa bude opravdu dostávat další automatické upomínky — false, pokud je sběr podkladů completed, archived, zaseknutý, nebo má chase_schedule nastavené na "off".


GET /v1/intakes/preview

Jen session. Vykreslí, co klient skutečně uvidí ve své schránce — předmět a jméno odesílatele — ještě předtím, než se cokoli odešle, podle aktuálního brandingu účtu. Hodí se na odhalení chybějícího jména odesílatele nebo špatného jazyka dřív, než to uvidí skutečný klient.

Parametry dotazu: language (výchozí je default_language účtu), project_name (výchozí je lokalizovaný zástupný text).

Odpověď

json
{
  "language": "en",
  "from_name": "Marco @ Bella Napoli (via BriefGate)",
  "subject": "Marco needs a few things from you — Bella Napoli — Website",
  "sender_name": "Marco @ Bella Napoli",
  "using_fallback_sender_name": false
}

POST /v1/intakes/:id/chase

Ručně odešle upomínku mimo automatický rozvrh.

Tělo požadavku

json
{
  "channel": "email"
}

channel je nepovinný: "email" (výchozí) nebo "sms". SMS vyžaduje funkci sms (na tarifu Free není k dispozici) a kladný zůstatek SMS kreditů — jinak 402 plan_required, nebo 402 quota_exceeded (reason sms_credits). Rate limit je 1 ruční upomínka na sběr podkladů za hodinu a 20 na účet za hodinu (429 rate_limited, reason manual_chase_intake/manual_chase_account), bez ohledu na kanál.


POST /v1/intakes/:id/send

Odešle klientovi sběr podkladů ve stavu konceptu. Platí jen tehdy, když je status roven draft (jinak 409 conflict). Rate limit je 30 pozvánek na účet za hodinu (429 rate_limited, reason intake_invites) — stejný limit, do kterého se počítá i POST /v1/intakes, když odesílá rovnou.


POST /v1/intakes/:id/archive

Uzavře sběr podkladů, aniž by ho smazal. Funguje z libovolného stavu (draft, sent, in_progress, completed); když je sběr už archivovaný, vrátí 409 conflict (reason intake_archived). Tělo požadavku je prázdné.

Vedlejší efekty:

Nic se nemaže: řádek, jeho položky, soubory i historie zůstávají přesně tak, jak byly, a GET /v1/intakes/:id sběr dál vrací. Vrací { intake } — stejný jednotlivý objekt intake jako PATCH /v1/intakes/:id, ne celý balík z GET /v1/intakes/:id (bez items/progress/owner_tasks) — s novým stavem archived.

Je to vratný protějšek DELETE /v1/intakes/:id níže, které je nevratné — „odarchivování" momentálně neexistuje.


GET /v1/intakes/:id/download/preflight

Nahlásí, co by obsahoval ZIP ke stažení (níže), aniž by ho generoval — počet bajtů, jestli přesahuje limit velikosti, a kolik přístupů typu secret jde do stažení zahrnout. Co ZIP obsahuje a jak se řeší volba u přístupů popisuje Stažení všeho v ZIPu.

Odpověď

json
{
  "files": 6,
  "bytes": 18420531,
  "skipped_files": 1,
  "secrets": { "total": 2, "unrevealed": 1, "already_revealed": 1 },
  "too_large": false,
  "max_bytes": 524288000,
  "filename": "podklady-bella-napoli-website-in_8f3kQmR2.zip"
}

skipped_files počítá nahrané soubory, které ještě čekají na antivirovou kontrolu — do ZIPu se nedostanou a jmenovitě se uvedou v podklady.pdf/podklady.md. secrets.unrevealed udává, kolik položek typu secret by zůstalo dostupných pro jednorázové odhalení, pokud je při stahování vynecháte; secrets.already_revealed byly odhalené už dřív a vždy se zobrazí jako already revealed on <datum> bez ohledu na include_secrets. too_large odpovídá tomu, jestli by volání stažení níže vrátilo 413.


GET /v1/intakes/:id/download

Stáhne všechny odevzdané položky jako jeden ZIP: podklady.pdf a podklady.md (stejný obsah — jeden pro čtení, druhý pro stroje) se štítkem, typem, stavem, odevzdanou hodnotou, rozhodnutími a důvody prominutí u každé položky, plus jednu podsložku pro každou položku se soubory, obsahující klientovy soubory přesně tak, jak byly odevzdané.

Parametry dotazu

Parametr Typ Popis
include_secrets boolean Odhalí a zahrne hodnoty položek typu secret do podklady.pdf. Výchozí false. Nikdy neovlivní podklady.md, který hodnoty secret nikdy nenese.

Přijímá session z dashboardu nebo API klíč se scopem intakes:read (nebo admin), stejně jako čtení sběru podkladů. include_secrets=true navíc vyžaduje vlastní session vlastníka účtu, nebo klíč se scopem secrets:read/admin; jiný volající dostane 403 forbidden, reason secrets_owner_only. Zahrnutí přístupů spotřebuje jednorázové odhalení každého dosud neodhaleného — stejně jako GET /v1/intakes/:id/results nebo POST /v1/intakes/:id/items/:key/reveal — viz Trezor na přístupy. Položka odhalená už dřív se v obou případech zobrazí jako already revealed on <datum> místo hodnoty.

Vrací application/zip s hlavičkou Content-Disposition: attachment; filename="podklady-<projekt>-<id sběru podkladů>.zip". Nad limitem velikosti hlášeným v max_bytes z preflight endpointu se odmítne s 413 download_too_large. Zaznamená se jako audit event intake.downloaded.


DELETE /v1/intakes/:id

Trvale smaže sběr podkladů i všechny nahrané soubory. Akce je nevratná. Při úspěchu vrací HTTP 204.


Clients

Adresář lidí, kterým tento účet poslal sběr podkladů. Neexistuje pro to žádná tabulka klientů — je to pohled na intakes, seskupený case-insensitive podle e-mailu, takže zná i klienty z doby před vznikem tohoto endpointu a nemůže se rozejít s tím, co bylo doopravdy odesláno. Cena za to je stejná jako u každého pohledu: překlepnutá adresa se stane vlastní položkou a zmizí, jen když se smažou sběry podkladů, které ji nesou.

GET /v1/clients   Vypíše klienty odvozené z minulých sběrů podkladů

GET /v1/clients

Vypíše klienty, nejaktivnější první.

Parametry dotazu

Parametr Popis
q Case-insensitive hledání podřetězce ve jméně a e-mailu klienta (1–100 znaků).
limit Počet výsledků na stránku (výchozí 20, max 100).
offset Posun stránkování (výchozí 0).

Odpověď

json
{
  "clients": [
    {
      "email": "jan@firma.cz",
      "name": "Jan Novák",
      "language": "cs",
      "phone": null,
      "timezone": "Europe/Prague",
      "folder_id": "fld_a1b2c3",
      "last_intake_id": "int_x9y8z7",
      "last_intake_at": "2026-09-18T10:00:00.000Z",
      "intake_count": 3
    }
  ],
  "total": 1,
  "limit": 20,
  "offset": 0
}

name, phone a folder_id mohou být null, pokud je poslední sběr podkladů nikdy nevyplnil. name, language, phone, timezone a folder_id pocházejí z posledního sběru podkladů daného klienta; intake_count a last_intake_at/last_intake_id se počítají přes všechny jeho sběry podkladů. Výsledky jsou řazené podle intake_count sestupně, pak podle last_intake_at sestupně.

Poznámka: Přijímá session z dashboardu nebo API klíč se scopem intakes:read, stejně jako GET /v1/intakes — API klíč vidí jen klienty ze sběrů podkladů ve svém vlastním režimu (test/live).


Folders

Jedna úroveň organizace sběrů podkladů, sdílená všemi na účtu — ne po jednotlivých uživatelích, a klient ji nikdy neuvidí: portál se o složce sběru podkladů nikdy nedozví. Pro zařazení použijte folder_id u POST /v1/intakes a PATCH /v1/intakes/:id, pro filtrování nebo hledání v seznamu folder_id/q u GET /v1/intakes.

GET    /v1/folders        Vypíše všechny složky
POST   /v1/folders        Založí složku
PATCH  /v1/folders/:id    Přejmenuje nebo přeřadí složku
DELETE /v1/folders/:id    Smaže složku

GET /v1/folders

Vypíše všechny složky na účtu, seřazené podle sort_order a pak podle name.

Odpověď

json
{
  "folders": [
    { "id": "fld_9k2mQxR7", "name": "Website projects", "sort_order": 0, "intake_count": 4, "created_at": "2024-03-01T09:00:00Z" },
    { "id": "fld_2wq8LpN3", "name": "Archived clients", "sort_order": 1, "intake_count": 0, "created_at": "2024-03-10T14:30:00Z" }
  ]
}

intake_count počítá sběry podkladů, které v ní jsou zařazené, pořád existují a nejsou součástí smazaného účtu.


POST /v1/folders

Založí novou složku.

Požadavek

json
{ "name": "Website projects" }

name se ořízne o bílé znaky a musí mít 1–80 znaků. Názvy složek jsou na účtu jedinečné bez ohledu na velikost písmen — duplicita vrátí 409 conflict (reason folder_exists).

Odpověď (HTTP 201) je objekt složky, stejný tvar jako jedna položka v GET /v1/folders.


PATCH /v1/folders/:id

Přejmenuje složku, změní její sort_order, nebo obojí. Všechna pole jsou nepovinná, ale aspoň jedno musí být zadané (jinak 400 invalid_request).

json
{ "name": "Website projects 2024" }

Přejmenování na název, který už na účtu používá jiná složka, vrátí 409 conflict (reason folder_exists). Odpověď je aktualizovaný objekt složky.


DELETE /v1/folders/:id

Smaže složku. Každý sběr podkladů, který v ní byl zařazený, se přesune mezi nezařazené (folder_id se nastaví na null) — samotné sběry podkladů i jejich soubory zůstávají nedotčené. Při úspěchu vrací HTTP 204.


Templates

Uloží definici sběru podkladů jako znovupoužitelnou šablonu, ať u opakujících se typů projektů nemusíte znovu zadávat položky — ani žádné další nastavení. Úplný přehled polí a pravidlo „nastavení jsou výchozí hodnoty" viz templates.md.

GET   /v1/templates        Vypsat všechny šablony
POST  /v1/templates        Vytvořit šablonu z pole definic položek, volitelně i s nastavením

Vytvoření šablony

POST /v1/templates vyžaduje přihlášenou session z dashboardu, ne API klíč — jako agent šablonu momentálně vytvořit nejde. Povinná jsou name a items; description, language a settings jsou nepovinné.

bash
curl -X POST https://api.briefgate.dev/v1/templates \
  -H "Cookie: bg_session=..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Restaurant Website",
    "items": [...],
    "settings": {
      "chase_schedule": "custom",
      "chase_interval": 5,
      "chase_interval_unit": "days",
      "due_in_days": 14
    }
  }'

Slug šablony pak v define_intake (nebo POST /v1/intakes) předáte jako "template": "web-restaurant" místo ručního výčtu items — items je v požadavku povinné i tak (viz známé omezení v templates.md). Každé nastavení, které šablona nese, se použije jako výchozí hodnota: doplní jen pole, která požadavek na založení sběru sám nevyplnil, a due_in_days se v okamžiku založení přepočítá na skutečné due_date.


Webhooks

BriefGate spouští webhooky při změnách stavu sběru podkladů. Každý obsah nese event, intake_id a timestamp a k tomu pole patřící dané události.

Každá cesta níže potřebuje na API klíči scope admin (endpoint dostává všechny události na celém účtu) — intakes:read/intakes:write nestačí. Session z dashboardu smí seznam číst, ale endpoint zaregistrovat, odebrat, otestovat nebo zopakovat doručení smí jen vlastník účtu (jiný člen dostane 403 forbidden).

GET    /v1/webhooks                                    Vypsat nastavené endpointy
POST   /v1/webhooks                                    Zaregistrovat nový endpoint
DELETE /v1/webhooks/:id                                Odebrat endpoint
GET    /v1/webhooks/:id/deliveries                     Historie doručení (posledních 100 pokusů)
POST   /v1/webhooks/:id/test                           Poslat na endpoint testovací událost
POST   /v1/webhooks/:id/deliveries/:deliveryId/retry   Ručně zopakovat jedno doručení

Registrace webhooku

bash
curl -X POST https://api.briefgate.dev/v1/webhooks \
  -H "Authorization: Bearer bg_live_xxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourapp.com/webhooks/briefgate",
    "events": ["intake.completed", "item.submitted"]
  }'

Podpisové tajemství generuje BriefGate a vrátí ho jednou v odpovědi — vy ho neposíláte. Přidáním "format": "slack" nebo "format": "discord" se místo na váš server doručuje do chatového kanálu.

Každý požadavek webhooku BriefGate podepisuje pomocí HMAC-SHA256 v hlavičce X-BriefGate-Signature. Než obsah zpracujete, ověřte podpis svým secret.

Události

Událost Spustí se, když
item.submitted Klient nahrál nebo vyplnil položku.
intake.completed Byly odeslány všechny povinné položky.
client.viewed Klient otevřel svůj portál.
chase.bounced Upomínka se natvrdo odrazila nebo byla nahlášena jako spam.
intake.stalled Sběr podkladů vyčerpal povolený počet upomínek, aniž by byl dokončen.
intake.overdue Uplynul termín a povinné položky pořád chybí (spustí se jednou za sběr podkladů).
intake.archived Sběr podkladů byl archivován přes POST /v1/intakes/:id/archive.

Tahle sedmice je jediná přijímaná; cokoli jiného se při registraci endpointu odmítne. Obsahy jednotlivých událostí najdete v webhooks.md.

Zopakování doručení

Když endpoint nevrátil 2xx, BriefGate ho už zkusil znovu podle automatického rozvrhu (ihned, pak +1 min, +5 min, +30 min, +2 h, +6 h — celkem 6 pokusů), než ho označil jako failed. Tohle stejné doručení zařadí do fronty ručně, přes stejnou cestu jako každé jiné odeslání — kontrola proti SSRF, čerstvě spočítaný podpis, zápis do logu jako každý jiný pokus. attempts se nevynuluje: doručení, které už vyčerpalo všech 6 pokusů, jede dál odtud, kde skončilo, takže tohle koupí přesně jeden pokus navíc, ne nový žebřík — pokud chcete víc, opravte nejdřív endpoint.

bash
curl -X POST https://api.briefgate.dev/v1/webhooks/whe_2f9k/deliveries/whd_9f8e7d6c5b4a/retry \
  -H "Authorization: Bearer bg_live_xxxxx"
json
{
  "delivery": {
    "id": "whd_9f8e7d6c5b4a",
    "event": "intake.completed",
    "status": "pending",
    "attempts": 6,
    "response_code": 500,
    "error": null,
    "next_retry_at": "2026-07-18T09:12:00Z",
    "created_at": "2026-07-18T09:11:00Z",
    "delivered_at": null
  }
}

404 not_found, pokud endpoint nebo doručení na tomhle účtu neexistuje. 409 conflict (reason already_delivered), pokud se doručení už povedlo — poslat ho znovu by událost na druhé straně zdvojilo. 409 conflict (reason endpoint_inactive), pokud byl endpoint mezitím vypnutý — nejdřív ho zapněte zpátky.


Účet a fakturace

GET   /v1/account               Údaje o účtu a aktuální tarif
PATCH /v1/account               Změna nastavení účtu (název, výchozí jazyk, retention_days, portal_link_ttl_days a další)
POST  /v1/account/logo          Nahrání loga zobrazeného v portálu a e-mailech (multipart `file`; jen dashboardová session)
DELETE /v1/account/logo         Odstranění loga
POST  /v1/account/signature     Nahrání podpisu do e-mailů (vizitka), který se vykreslí na konci každého e-mailu pro vaše klienty (multipart `file`, PNG/JPEG/WebP; jen dashboardová session)
DELETE /v1/account/signature    Odstranění podpisu
GET   /v1/usage                 Spotřeba za aktuální období proti limitům tarifu
GET   /v1/audit                 Stránkovaný auditní log akcí API a uživatelů (jen session, jen vlastník účtu)
POST  /v1/billing/checkout      Založení Stripe Checkout session pro přechod na vyšší tarif
POST  /v1/billing/portal        Založení session zákaznického portálu Stripe pro správu předplatného

Odpověď o spotřebě

json
{
  "period": "2024-03",
  "intakes": { "used": 12, "limit": 50 },
  "storage_bytes": { "used": 524288000, "limit": 5368709120 }
}

Sedadla v týmu. Sedadlo je člověk, který se přihlašuje do dashboardu — klienti žádné nezabírají, protože otevírají jen odkaz, který dostali e-mailem. Každá cesta níže je jen s dashboardovou session; nezavolá je žádný API klíč, ani se scopem admin — kromě přijetí pozvánky, které se místo toho prokáže tokenem pozvánky a session vůbec nepotřebuje. Seznam smí číst kterýkoli přihlášený člen; zvát, rušit pozvánku a odebírat člena smí jen vlastník (jiný dostane 403 forbidden).

GET    /v1/team                  Vypsat členy a čekající pozvánky
POST   /v1/team/invites          Pozvat e-mail do sedadla (jen vlastník)
DELETE /v1/team/invites/:id      Zrušit čekající pozvánku (jen vlastník)
POST   /v1/team/invites/accept   Přijmout pozvánku — bez session, prokazuje se tokenem
DELETE /v1/team/members/:id      Odebrat člena (jen vlastník)

GET /v1/team

Vrátí aktuální členy a k tomu pozvánky, které ještě čekají a nevypršely.

Odpověď

json
{
  "members": [
    { "id": "usr_9f3kqmr2", "email": "marco@bellanapoli.com", "name": "Marco Esposito", "role": "owner", "created_at": "2026-01-10T09:00:00Z", "last_login_at": "2026-09-04T08:12:00Z" }
  ],
  "invites": [
    { "id": "tin_7h2jvw4x", "email": "giulia@bellanapoli.com", "role": "member", "created_at": "2026-09-01T10:00:00Z", "expires_at": "2026-09-08T10:00:00Z" }
  ]
}

POST /v1/team/invites

Pozve e-mailovou adresu do koupeného sedadla. Každá pozvánka dává roli member — pozvat druhého vlastníka nejde.

Tělo požadavku

Pole Typ Povinné Popis
email string Ano Adresa k pozvání. Převede se na malá písmena; max. 320 znaků.

Odpověď (HTTP 201)

json
{ "id": "tin_7h2jvw4x", "email": "giulia@bellanapoli.com", "role": "member", "created_at": "2026-09-05T10:00:00Z", "expires_at": "2026-09-12T10:00:00Z" }

Pozvánka přijde e-mailem s odkazem platným 7 dní. Další pozvání stejné adresy nahradí tu předchozí — funguje vždy jen ten nejnovější odkaz.

402 quota_exceeded (reason seats), jakmile členové a čekající pozvánky dohromady zaplní kvótu sedadel tarifu — zrušte čekající pozvánku, odeberte člena, nebo si dokupte sedadlo navíc. 400 invalid_request, pokud daná adresa už na tomhle účtu patří členovi. 429 rate_limited (reason team_invites) nad 20 pozvánek na účet za hodinu.


DELETE /v1/team/invites/:id

Zruší čekající pozvánku. 404 not_found, pokud na tomhle účtu neexistuje. 400 invalid_request, pokud už byla přijatá — pak není co rušit. Vrací { "ok": true, "id": "tin_7h2jvw4x" }.


POST /v1/team/invites/accept

Bez autentizace — prokazuje se tokenem pozvánky, stejně jako odkaz na reset hesla. Založí uživatele v roli member, rovnou ho přihlásí a nastaví session cookie.

Tělo požadavku

Pole Typ Povinné Popis
token string Ano Token z odkazu v e-mailu s pozvánkou.
name string Ano Zobrazované jméno nového člena.
password string Ano Aspoň 12 znaků.

Odpověď (HTTP 201)

json
{
  "user": { "id": "usr_2k9fjbrt", "email": "giulia@bellanapoli.com", "name": "Giulia", "role": "member" },
  "account": { "id": "acc_8j3nq2mv", "name": "Bella Napoli", "tier": "agency" }
}

401 unauthorized („That invitation link is not valid or has expired.") pro token, který je neznámý, už přijatý, nebo propadlý — schválně jedna odpověď pro všechny tři případy, stejně jako u resetu hesla. 400 invalid_request („An account with this email already exists.") pokud pozvaná adresa už jinde má uživatele. 402 quota_exceeded (reason seats), pokud se sedadlo zaplnilo mezi odesláním pozvánky a jejím přijetím — kvóta se ověřuje znovu i tady, ne jen při založení pozvánky.


DELETE /v1/team/members/:id

Odebere člena: uživatele soft-smaže a okamžitě mu ukončí úplně všechny relace. 400 invalid_request, pokud :id je vaše vlastní id („You cannot remove your own account this way.") nebo patří vlastníkovi účtu („The account owner cannot be removed."). 404 not_found, pokud neodpovídá existujícímu členovi na tomhle účtu. Vrací { "ok": true, "id": "usr_2k9fjbrt" }.


Veřejné endpointy

Tyhle endpointy nevyžadují autentizaci a jsou určené ke strojovému zpracování.

Endpoint Popis
GET /pricing.json Strojově čitelné tarify, limity a příznaky funkcí. Agent podle nich pozná, jaký tarif doporučit, nebo si před zakládáním sběru podkladů ověří kvótu.
GET /v1/openapi.json Specifikace OpenAPI 3.1 pro celé API. Naimportujte do Postmanu, vygenerujte SDK nebo předejte agentovi, ať si API projde sám.
GET /healthz Liveness sonda. Vrací HTTP 200 s {"status":"ok"}, pokud proces API běží.
GET /readyz Readiness sonda. Vrací HTTP 200 jen tehdy, když je v pořádku proces API i všechny závislosti (databáze, objektové úložiště, poštovní provider). Během nasazování a výpadků vrací HTTP 503.