API i integracje Proposals
Beta. Na czas bety integracje włączamy osobno dla każdego zespołu. Jeśli w swoim koncie Proposals nie widzisz Ustawienia → Integracje, napisz na support@proposals.co, a włączymy je.
Integracje pozwalają tworzyć i prowadzić oferty z narzędzi, których już używasz: z ChatGPT, z Claude albo z CRM przez Zapier, Make lub n8n. Oferta zrobiona w ten sposób przechodzi przez ten sam silnik co oferta z panelu – z Twoją marką, Twoją ceną, tymi samymi kontrolami jakości i tym samym śledzeniem. W panelu widzisz ją jak każdą inną, z oznaczeniem, skąd przyszła.
Dwóch rzeczy integracje celowo nie robią:
- Proposals nie pisze i nie wysyła maili przez API. Dostajesz publiczny link i najważniejsze fakty o ofercie. Maila piszesz Ty albo asystent, z którym rozmawiasz – on zna rozmowę i klienta lepiej niż jakikolwiek szablon.
- Jedna oferta na jedno wywołanie. Możesz utworzyć wiele ofert, ale każdą osobnym żądaniem i w ramach limitów. Nie ma importu list ani kampanii.
Przewodniki
| Przewodnik | Do czego |
|---|---|
| ChatGPT | Podłączenie Proposals do ChatGPT i oferta zrobiona w rozmowie |
| Claude | Podłączenie Proposals do Claude i oferta zrobiona w rozmowie |
| Zapier, Make i n8n | Oferty z szansy sprzedaży w CRM, z kluczem API |
| Referencja API | Każdy endpoint z przykładem żądania i odpowiedzi |
Aktualny opis OpenAPI jest pod adresem https://api.proposals.co/api/public/v1/openapi.json.
Dwie drogi
| REST API | Serwer MCP | |
|---|---|---|
| Dla kogo | Automatyzacje i własny kod | ChatGPT, Claude i inni asystenci obsługujący konektory MCP |
| Adres | https://api.proposals.co/api/public/v1 |
https://api.proposals.co/mcp |
| Logowanie | Klucz API (Authorization: Bearer prp_live_…) |
OAuth: logujesz się do Proposals i zatwierdzasz uprawnienia |
| Kto konfiguruje | Klucz tworzy administrator Proposals | Każdy członek zespołu podłącza swojego asystenta |
Obie drogi wołają tę samą usługę, więc zasady poniżej dotyczą obu.
Uwierzytelnianie
Klucze API (REST)
Administrator tworzy klucze w Ustawienia → Integracje → Klucze API. Sekret zaczyna się od prp_live_ i jest pokazywany tylko raz, zaraz po utworzeniu. Zapisz go w miejscu na sekrety w narzędziu do automatyzacji, nigdy we wspólnym dokumencie.
Wysyłaj go w nagłówku Authorization przy każdym żądaniu:
Authorization: Bearer prp_live_...Klucz w adresie (query string) nie jest akceptowany. Domyślnie klucz jest ważny 365 dni, a przy tworzeniu możesz wybrać krótszy okres. Każdy członek zespołu widzi listę kluczy z ich prefiksem i datą ostatniego użycia, ale tworzyć i unieważniać je mogą tylko administratorzy.
Klucz działa w imieniu administratora, który go utworzył, i nigdy nie ma większych uprawnień niż ta osoba. Jeśli odejdzie z organizacji, klucz przestaje działać.
Podłączone aplikacje (MCP)
ChatGPT i Claude łączą się przez OAuth. Kiedy dodajesz konektor, trafiasz do Proposals, logujesz się i zatwierdzasz uprawnienia. Publikacja jest domyślnie odznaczona. Aplikację możesz w każdej chwili odłączyć w Ustawienia → Integracje → Podłączone aplikacje – jej dostęp kończy się natychmiast.
Uprawnienia (zakresy)
| Zakres | Pozwala integracji |
|---|---|
brands:read |
Zobaczyć Twoje marki (nazwę, język, walutę), żeby wybrać właściwego nadawcę |
proposals:read |
Czytać oferty: status, pytania, najważniejsze fakty, link oraz to, czy klient otworzył lub zaakceptował ofertę |
proposals:write |
Tworzyć oferty, odpowiadać na ich pytania, prosić o poprawki, zmieniać odbiorcę i warunki, oznaczać ofertę jako wysłaną |
proposals:publish |
Opublikować ofertę (uruchomić jej link) i cofnąć publikację |
Nowy klucz API dostaje brands:read, proposals:read i proposals:write. proposals:publish pojawia się tylko wtedy, gdy go zaznaczysz. Bez niego integracja przygotuje szkic, ale opublikuje go człowiek w panelu.
Wywołanie bez potrzebnego zakresu kończy się błędem 403 insufficient_scope, a detail.params.required podaje brakujący zakres.
Co zostaje pod Twoją kontrolą
- Szkice są prywatne. Utworzenie oferty nigdy jej nie publikuje.
- Publikacja wymaga trzech rzeczy naraz: zakresu
proposals:publish, braku blokad w kontroli przed publikacją i jawnego"confirm": truew wywołaniu. Przez API nie da się obejść blokady. - Widzisz wszystko. Każda oferta ma w panelu oznaczenie źródła (na przykład „Utworzona w ChatGPT”), każda ma historię działań integracji, a publikacja przez integrację wysyła właścicielowi oferty powiadomienie.
- Twoje dane są Twoje. Oferty i marki innych organizacji dla Twojego klucza nie istnieją: odpowiadają
404, nigdy403.
Status oferty
Każda oferta ma jeden status, wyliczany z jej bieżącego stanu:
| Status | Znaczenie | Co zrobić |
|---|---|---|
generating |
Szkic właśnie powstaje (zwykle od 30 do 120 sekund) | Sprawdź ponownie po next_poll_after_ms |
needs_input |
Notatki są niejednoznaczne, na przykład są w nich dwie różne ceny albo dwie nazwy firmy | Zadaj użytkownikowi pytania z questions i wyślij odpowiedzi |
ready_for_review |
Szkic jest gotowy i nic nie blokuje publikacji | Przejrzyj go (panel_url) albo opublikuj |
blocked |
Szkic jest gotowy, ale kontrola przed publikacją znalazła blokadę | Przeczytaj preflight.blockers i usuń blokady, zwykle w panelu |
failed |
Generowanie się nie skończyło, a error.code mówi dlaczego |
Usuń przyczynę i ponów, wysyłając puste answers |
draft |
Oferta istnieje, ale nie ma jeszcze strony (na przykład zaczęto ją w panelu) | Kontynuuj w panelu |
published |
Link działa | Wyślij go klientowi |
sent |
Oferta została oznaczona jako wysłana albo wysłano ją z panelu | Czekaj na klienta |
opened |
Klient otworzył ofertę | Odezwij się, póki temat jest świeży |
accepted |
Klient zaakceptował ofertę | – |
Publikacja to nie wysyłka. Oferta dostaje status sent dopiero wtedy, gdy to zadeklarujesz (mark-sent) albo gdy wysłano ją z panelu.
Praca w tle i odpytywanie
Pisanie oferty trwa, dlatego POST /proposals, POST /proposals/{id}/answers i POST /proposals/{id}/revise od razu zwracają 202 z ofertą w statusie generating. Dalej:
- Odczekaj
next_poll_after_msmilisekund (to pole pojawia się tylko przy statusiegenerating). - Wywołaj
GET /proposals/{id}. - Powtarzaj, dopóki status jest
generating.
Jeśli Twoje narzędzie nie obsługuje pętli, dodaj do POST /proposals parametr ?wait_seconds=50. Wywołanie poczeka wtedy do 50 sekund i zwróci stan z tej chwili. Oferta może nadal mieć status generating, więc zostaw jedno sprawdzenie zapasowe.
Idempotencja
Każdy POST wymaga nagłówka Idempotency-Key. Użyj wartości unikalnej dla zamierzonej akcji, na przykład identyfikatora szansy z CRM i nazwy akcji (deal-731-create).
- Ten sam klucz i ta sama treść: dostajesz pierwotną odpowiedź, a nic nie wykonuje się dwa razy. To bezpieczne po przekroczeniu czasu albo utracie odpowiedzi.
- Ten sam klucz i inna treść:
409 idempotency_conflict, nic się nie dzieje. - Ten sam klucz, gdy pierwsze żądanie jeszcze trwa:
409 idempotency_in_progress, ponów za chwilę. POSTbez nagłówka:422 idempotency_key_required.
Klucze pamiętamy przez 30 dni, osobno dla każdego poświadczenia. Klucz może mieć do 255 znaków.
external_reference chroni Cię drugi raz: jeśli go ustawisz (na przykład na identyfikator szansy z CRM), druga oferta z tą samą wartością kończy się błędem 409 external_reference_exists, a detail.params.proposal_id wskazuje istniejącą ofertę.
Klienci MCP nie wysyłają nagłówków, więc serwer MCP pilnuje powtórek sam: to samo wywołanie narzędzia z tymi samymi argumentami w ciągu 10 minut zwraca pierwszy wynik.
Limity
Na każdy klucz API albo podłączoną aplikację:
- 60 odczytów na minutę,
- 10 nowych ofert na minutę,
- 20 poprawek na 10 minut,
- 30 innych zmian na minutę.
Na organizację: najwyżej trzy oferty mogą powstawać jednocześnie.
Po przekroczeniu limitu dostajesz 429 z nagłówkiem Retry-After (w sekundach). rate_limited oznacza, że poświadczenie wysłało za dużo żądań, a too_many_generations – że trzy oferty już powstają.
Twój plan działa dokładnie tak jak w panelu: oferta utworzona przez integrację liczy się jako jedna utworzona oferta, a akcje AI podlegają tym samym zasadom fair use. Gdy plan blokuje akcję, dostajesz 402 z tymi samymi kodami co w panelu.
Błędy
Każdy błąd ma ten sam kształt:
{
"detail": {
"code": "insufficient_scope",
"message": "Ten klucz nie może publikować ofert.",
"params": { "required": "proposals:publish" }
},
"request_id": "req_01J..."
}message jest napisany dla człowieka i zależy od nagłówka Accept-Language (pl daje polski, każda inna wartość angielski). Logikę opieraj na code, a nie na message. Pisząc do wsparcia, podaj request_id.
| HTTP | Najczęstsze kody | Znaczenie |
|---|---|---|
401 |
invalid_credentials |
Brak klucza albo tokenu, jest błędny, wygasł lub został unieważniony |
402 |
trial_offer_cap, usage_limit_exceeded, fair_use_exceeded, subscription_inactive |
Plan w tej chwili na to nie pozwala; sprawdź ustawienia rozliczeń w panelu |
403 |
insufficient_scope, integrations_not_enabled |
Brak uprawnienia albo integracje nie są włączone dla Twojej organizacji |
404 |
not_found |
Obiekt nie istnieje albo należy do innej organizacji |
409 |
idempotency_conflict, idempotency_in_progress, external_reference_exists, site_conflict, generation_in_progress, offer_accepted |
Konflikt z bieżącym stanem, szczegóły poniżej |
422 |
idempotency_key_required, preflight_blockers, błędne dane |
Żądania nie da się wykonać w tej postaci |
429 |
rate_limited, too_many_generations |
Odczekaj tyle sekund, ile podaje Retry-After |
Kilka kodów warto obsłużyć jawnie:
site_conflict– ktoś zmienił szkic od rewizji podanej wexpected_revision. Nic nie zginęło: odczytaj ofertę ponownie i zdecyduj.generation_in_progress– oferta już powstaje; odpytuj zamiast zaczynać od nowa.offer_accepted– klient zaakceptował ofertę, więc nie można jej już zmieniać.preflight_blockers– publikacja została odrzucona; blokady są w polupreflightoferty.brand_name_unconfirmed– nazwa marki nie jest jeszcze potwierdzona; potwierdź ją w panelu, w ustawieniach marki.email_verification_required– konto, do którego należy poświadczenie, nie ma jeszcze potwierdzonego adresu e-mail.
Wersjonowanie
Wersja API jest w ścieżce (/api/public/v1). W ramach v1 tylko dodajemy: nowe pola, nowe parametry opcjonalne, nowe kody błędów. Pisz klientów, którzy ignorują nieznane pola. Zmiany, które mogłyby zepsuć działającą integrację, trafiają do /v2, a v1 działa co najmniej 12 miesięcy od ogłoszenia v2.
W czasie bety unikamy zmian niekompatybilnych. Jeśli któraś okaże się konieczna, wpiszemy ją do dziennika zmian poniżej, zanim wejdzie w życie.
Dziennik zmian
- 05.10.2026 – MCP: bezpośrednia edycja szkicu (
get_proposal_content,edit_proposal_content,update_proposal_settings, historia wersji, odrzucenie zmian, cofnięcie publikacji). REST:PATCH /proposals/{id}przyjmuje teżclient_name,client_website,service_type,next_stepipricing. - 26.09.2026 –
v1w wersji beta: marki, oferty (tworzenie, odczyt, lista, odpowiedzi, poprawki, zmiana danych, publikacja, cofnięcie publikacji, oznaczenie wysyłki), serwer MCP z OAuth.