Dla programistów
Partnerskie API
Klienta przesyłają nam Państwo pod własnym pseudonimowym identyfikatorem - bez e-maila, nazwiska i innych danych osobowych - i w dowolnej chwili odczytują stan jego szkolenia. Służy to jako kontrola compliance przed zawarciem umowy, wpłatą lub wypłatą.
Wersja 1.3.2 · JSON przez HTTPS · OpenAPI
Jak to działa
API jest takie samo dla wszystkich partnerów. W pięciu krokach:
- Włączamy API dla Państwa firmy; w swojej administracji tworzą Państwo klucz API w zakładce API.
- Gdy klient ma zostać przeszkolony, Państwa system wywołuje POST /v1/users z Państwa identyfikatorem klienta.
- Zakładamy profil bez e-maila i zwracamy link wejściowy (entryUrl); pokazują go Państwo klientowi jako przycisk.
- Klient go klika i od razu jest w kursie.
- Stan odczytują Państwo w dowolnej chwili przez GET /v1/users/{identifier} albo powiadamiamy o nim Państwa serwer webhookiem.
Administratorem identyfikatora są Państwo, my przetwarzamy wyłącznie dane spseudonimizowane. Jako identyfikatora nigdy nie należy wysyłać adresu e-mail ani nazwiska - adres e-mail API odrzuca błędem 422.
Adres i uwierzytelnianie
Każde wywołanie idzie przez HTTPS na adres poniżej i niesie Państwa klucz API w nagłówku Authorization.
https://api.responsiblo.com Authorization: Bearer rsb_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- rsb_live_... otwiera Państwa program produkcyjny, rsb_test_... Państwa program testowy (sandbox).
- Klucz wyświetla się tylko raz, przy utworzeniu; przechowujemy wyłącznie jego odcisk. Proszę traktować go jako tajemnicę na swoim serwerze - nigdy w przeglądarce ani w aplikacji.
- Klucz ma uprawnienia: read (stan i lista osób, certyfikat) oraz write (przesyłanie i anonimizacja osób). Może być ograniczony do Państwa adresów IP i mieć okres ważności.
- Wymiana: tworzą Państwo nowy klucz, stary działa jeszcze 7 dni, potem wygasa.
- Odpowiedzi nigdy nie są zapisywane w pamięci podręcznej (Cache-Control: no-store), a API nie przyjmuje wywołań z przeglądarki (bez CORS).
POST /v1/users
Przesyła osobę do programu klucza (uprawnienie write).
curl -X POST https://api.responsiblo.com/v1/users \
-H "Authorization: Bearer $RSB_KEY" \
-H "Content-Type: application/json" \
-d '{"identifier":"client-48213","language":"cs","label":"campaign-2026-10"}'
| Pole | Wymagane | Znaczenie |
|---|---|---|
identifier |
tak | Państwa pseudonim osoby, od 1 do 64 znaków A-Z a-z 0-9 . _ : @ -; nigdy adres e-mail (odrzucony błędem 422). |
program |
nie | Kod programu; jeśli go Państwo podadzą, musi to być program klucza. |
language |
nie | Język kursu (cs, en, ...); domyślnie pierwszy język programu. |
label |
nie | Państwa etykieta - kohorta lub kampania, od 1 do 64 znaków, nigdy dana osobowa. |
expiresAt |
nie | Ostatni dzień dostępu, RRRR-MM-DD. |
201 Created dla nowej osoby, 200 OK, gdy identyfikator już istnieje - nic się nie zmienia, wywołanie można bezpiecznie powtórzyć. Treść odpowiedzi to stan opisany poniżej, razem z entryUrl. Wyczerpany limit osób lub licencji programu zwraca 403.
GET /v1/users/{identifier}
Stan osoby (uprawnienie read): to, czego potrzebuje kontrola compliance, nic więcej.
curl https://api.responsiblo.com/v1/users/client-48213 -H "Authorization: Bearer $RSB_KEY"
{
"identifier": "client-48213",
"program": "your-program",
"status": "in_progress",
"progress": 43,
"lessonsCompleted": 3,
"lessonsTotal": 7,
"quizScore": null,
"label": "campaign-2026-10",
"createdAt": "2026-10-20T10:02:11Z",
"startedAt": "2026-10-20T10:05:40Z",
"completedAt": null,
"lastActivityAt": "2026-10-20T10:31:40Z",
"expiresAt": null,
"certificate": null,
"entryUrl": "https://your-company.responsiblo.com/entry/..."
}
status | Znaczenie |
|---|---|
enrolled |
przesłana, jeszcze nie weszła |
started |
weszła, jeszcze niczego nie ukończyła |
in_progress |
ma ukończone lekcje, program jeszcze nie |
completed |
program jest ukończony (completedAt) |
expired |
dostęp się skończył (minął expiresAt; osoba w sandboxie kończy po 7 dniach) |
quizScore to wynik quizu końcowego w %, gdy tylko zostanie ukończony. Czasy są w UTC z dokładnością do pełnych sekund. Pole certificate zawiera certyfikat osoby (zob. niżej); dopóki go nie ma, jest null.
?include=detail
Dodaje postęp w każdym kursie i wynik każdego quizu - nigdy pojedyncze odpowiedzi.
"courses": [{"id": "733db340-...", "name": "Introduction", "progress": 40, "lessonsCompleted": 2, "lessonsTotal": 5, "completed": false}],
"quizzes": [{"id": "d2e72fd7-...", "name": "Quiz of the introduction", "score": 85, "completedAt": "2026-10-20T10:31:40Z"}]
GET /v1/users
Lista osób, które przesłali Państwo do programu klucza (uprawnienie read), strona po stronie: każda pozycja ma postać stanu opisanego wyżej. Opcjonalnie status (tylko osoby w tym stanie), limit (od 1 do 500, domyślnie 100) i cursor.
curl "https://api.responsiblo.com/v1/users?status=completed&limit=100" -H "Authorization: Bearer $RSB_KEY"
{
"items": [{ "identifier": "client-48213", "status": "completed", "...": "the state of GET /v1/users/{identifier}" }],
"nextCursor": "MjAyNi0xMC0yMFQxMDowMjoxMVp8...",
"limit": 100
}
curl "https://api.responsiblo.com/v1/users?status=completed&limit=100&cursor=MjAyNi0xMC0yMFQxMDowMjoxMVp8..." -H "Authorization: Bearer $RSB_KEY"
- Proszę kontynuować z cursor = nextCursor, dopóki nextCursor nie jest null; kursor to nieprzezroczysty tekst, nigdy nie należy składać go samodzielnie.
- Osoby występują według chwili przesłania w stałej kolejności (także przy tej samej chwili), żadna dwa razy; osób zanonimizowanych na liście nie ma.
- Z filtrem status przeglądamy dla jednej strony najwyżej 2000 osób, dlatego strona może mieć mniej pozycji niż limit, nawet żadnej - proszę kontynuować, dopóki jest nextCursor.
Certyfikat osoby
Gdy tylko osoba ukończy program, kurs wydaje jej certyfikat - pod jej pseudonimem (pseudonim profilu ID XXXXXX), bez nazwiska i bez e-maila. Nic nie jest wysyłane e-mailem; w stanie osoby jest pole certificate z numerem, czasami i publiczną stroną weryfikacji, a PDF pobierają Państwo przez GET /v1/users/{identifier}/certificate.
"certificate": {
"number": "RSP-7KQ2-M4XH-9TWB",
"issuedAt": "2026-10-20T10:39:15Z",
"expiresAt": "2028-10-20T10:39:12Z",
"verifyUrl": "https://responsiblo.com/verify/RSP-7KQ2-M4XH-9TWB"
}
curl https://api.responsiblo.com/v1/users/client-48213/certificate -H "Authorization: Bearer $RSB_KEY" -o client-48213.pdf
- Strona weryfikacji verifyUrl pokazuje tylko pseudonim, program, partnera i ważność - nigdy Państwa identyfikatora.
- PDF zwraca application/pdf (uprawnienie read). Bez certyfikatu odpowiedź to 404 certificateNotFound, a gdy PDF jest dopiero przygotowywany, 404 certificatePdfNotReady z Retry-After.
- Unieważniony certyfikat nigdy nie zostanie wydany (pole certificate jest wtedy null, PDF 404); certyfikat, którego ważność upłynęła, pozostaje prawdziwym dowodem i zostanie wydany.
- Webhook ogłasza certyfikat zdarzeniem certificate.issued (zaraz po user.completed).
DELETE /v1/users/{identifier}
Anonimizuje osobę (uprawnienie write): z profilu znika Państwa identyfikator, etykieta i każda wiadomość webhooka, która go wymienia; linki wejściowe przestają działać. Certyfikat i wynik kursu pozostają pod numerem certyfikatu - jako dowód compliance.
curl -X DELETE https://api.responsiblo.com/v1/users/client-48213 -H "Authorization: Bearer $RSB_KEY" HTTP/1.1 204 No Content
Odpowiedź 204 bez treści; każde kolejne wywołanie z tym samym identyfikatorem zwraca 404 userNotFound, więc powtórzenie jest bezpieczne. Ten sam identyfikator mogą Państwo potem przesłać ponownie jako nową osobę.
Link wejściowy
entryUrl należy pokazać osobie (przycisk Rozpocznij kurs w Państwa systemie). Loguje ją do kursu - bez e-maila i bez hasła.
Link jest ważny 30 dni i można go używać wielokrotnie; każde wywołanie GET /v1/users/{identifier} zwraca nowy. Nigdy nie należy wysyłać go nikomu innemu: kto ma link, wchodzi jako ta osoba.
Webhooki
W zakładce API swojej administracji ustawiają Państwo jeden webhook dla każdego programu: publiczny adres HTTPS swojego serwera i zdarzenia. Następnie wysyłamy Państwu POST z JSON - tylko identyfikatory i stany, nigdy link wejściowy.
| Zdarzenie | Kiedy |
|---|---|
user.enrolled |
osoba została przesłana (pierwszy raz, gdy Państwa webhook ją zna) |
user.started |
osoba weszła do kursu |
user.completed |
osoba ukończyła program |
certificate.issued |
osoba uzyskała certyfikat; pole data zawiera certificate (numer, czasy, verifyUrl) |
user.expired |
dostęp osoby się skończył |
POST https://your-server.example/responsiblo/webhook
Content-Type: application/json
X-Responsiblo-Event: user.completed
X-Responsiblo-Delivery: 5b0c1f9e-2d1a-4a57-9a3e-0d6c9c1f2b77
X-Responsiblo-Signature: t=1792492800,v1=3f1c...e9
{
"id": "5b0c1f9e-2d1a-4a57-9a3e-0d6c9c1f2b77",
"type": "user.completed",
"createdAt": "2026-10-20T10:40:00Z",
"apiVersion": "1.3.2",
"program": "your-program",
"data": {
"identifier": "client-48213",
"status": "completed",
"progress": 100,
"lessonsCompleted": 7,
"lessonsTotal": 7,
"quizScore": 85,
"label": "campaign-2026-10",
"startedAt": "2026-10-20T10:05:40Z",
"completedAt": "2026-10-20T10:39:12Z",
"expiresAt": null
}
}
Podpis
Każda wiadomość niesie nagłówek X-Responsiblo-Signature: t=<czas uniksowy>,v1=<HMAC-SHA256 tekstu t.treść z sekretem webhooka, hex>. Sekret (whsec_...) wyświetla się raz przy tworzeniu webhooka. Zanim zaufają Państwo wiadomości, proszę zweryfikować podpis i wiek t; jako klucza idempotencji proszę użyć X-Responsiblo-Delivery.
// PHP: $secret = "whsec_...", $header = X-Responsiblo-Signature, $body = the raw body
preg_match('/^t=(\d+),v1=([0-9a-f]{64})$/', $header, $m);
$valid = $m
&& abs(time() - (int) $m[1]) <= 300
&& hash_equals(hash_hmac('sha256', $m[1] . '.' . $body, $secret), $m[2]);
Doręczenie i ponowienia
Doręczono = odpowiedź 2xx w ciągu 10 sekund. W przeciwnym razie próbujemy ponownie po 1 minucie, 5 minutach, 30 minutach, 2 godzinach i 12 godzinach, potem rezygnujemy. Przekierowań nie śledzimy.
20 niedoręczonych wiadomości z rzędu wyłącza webhook, dopóki Państwo go ponownie nie włączą; wiadomości z tego czasu czekają. Przycisk Test wysyła ping; dziennik doręczeń znajdą Państwo w swojej administracji.
Zdarzenie certificate.issued dodają Państwo do webhooka w jego ustawieniach; webhook utworzony przed wersją 1.2 nie otrzymuje go sam.
Błędy
Każdy błąd ma jedną postać: status, code, reason i message; błąd 422 dodaje errors (pole - co jest nie tak).
{ "status": "error", "code": 422, "reason": "invalidBody", "message": "The body is not valid.",
"errors": { "identifier": "identifier must be a pseudonym of the partner, never an e-mail address" } }
| HTTP | reason | Co zrobić |
|---|---|---|
| 400 | invalidJson |
proszę wysłać jeden obiekt JSON |
| 401 | missingToken, invalidToken |
proszę wysłać ważny klucz (unieważniony i wygasły klucz wyglądają tak samo); nagłówek WWW-Authenticate mówi Bearer |
| 403 | scopeDenied, ipNotAllowed, apiDisabled, partnerInactive, spaceUnavailable, httpsRequired, userLimitReached, seatsExhausted |
klucz nie ma do tego uprawnień, API jest dla Państwa firmy wyłączone albo program jest pełny |
| 404 | userNotFound, notFound |
w programie klucza nie ma osoby o tym identyfikatorze (nawet zanonimizowanej) |
| 404 | certificateNotFound, certificatePdfNotReady |
osoba nie ma jeszcze certyfikatu albo jego PDF jest przygotowywany - proszę spróbować po Retry-After |
| 409 | identifierTaken |
identyfikator należy do osoby z innego programu |
| 422 | invalidBody, invalidParameter |
zob. errors (pole treści albo parametr zapytania - co jest nie tak) |
| 429 | rateLimited |
proszę odczekać Retry-After sekund |
| 500 | internalError |
proszę spróbować później; naszemu wsparciu proszę podać incidentId |
Dla programów i agentów
- Decyzje należy podejmować według code i reason, nigdy według tekstu message; errors to obiekt pole -> co jest nie tak.
- Ponawiać należy tylko 429, 500 i certificatePdfNotReady, i to po Retry-After sekundach (w przeciwnym razie z rosnącym odstępem); innych 4xx niż 429 nie należy ponawiać bez poprawienia wywołania.
- POST /v1/users jest idempotentne według identifier (201 za pierwszym razem, potem 200); DELETE zwraca 204 za pierwszym razem i 404 później - oba można bezpiecznie powtarzać.
- Webhooki należy deduplikować według X-Responsiblo-Delivery; kolejność wiadomości nie jest gwarantowana, decyduje stan w data.
Przewodnik po pożyczce
Przewodnik po pożyczce to krótki kurs dla osób ubiegających się o pożyczkę u pożyczkodawcy: przed podpisaniem umowy osoba wnioskująca przechodzi trzy lekcje, osiem praktycznych sytuacji i ewentualnie quiz, wszystko na liczbach własnej oferty, a na końcu potwierdza ofertę. Na każdym ekranie może poprosić o wyjaśnienie. Ofertę przesyłają Państwo przez API, otrzymują link wejściowy, a o wyniku informuje Państwa webhook.
Przewodnik po pożyczce aktywujemy w porozumieniu z Państwem.
Również tutaj osoba wnioskująca jest tylko Państwa pseudonimowym profilem z POST /v1/users. Ofertę identyfikują Państwa referencje (externalApplicationId, offerReference), a dokumenty wyłącznie link z odciskiem SHA-256 - nigdy imię i nazwisko, e-mail, numer PESEL, numer rachunku ani telefon. responsiblo nie zatwierdza pożyczki, nie pobiera ani nie przechowuje dokumentów, nie weryfikuje tożsamości i nie wydaje certyfikatu za przewodnik.
- Zakładają Państwo profil osoby wnioskującej: POST /v1/users z Państwa pseudonimem.
- Przesyłają Państwo ofertę: POST /v1/users/{identifier}/loan-offers; odpowiedź 201 zawiera entryUrl.
- entryUrl przekazują Państwo osobie wnioskującej własnym zweryfikowanym kanałem. Link jest ważny 30 dni i można go używać wielokrotnie; przewodnik pokaże liczby jej oferty.
- O zakończeniu dowiedzą się Państwo z webhooka (loanGuide.completed, loanGuide.assistanceRequested i inne).
- Stan odczytują Państwo przez GET …/loan-offers/{offerReference}, ewidencję do swoich akt przez GET …/evidence. Zmieniona oferta = nowa oferta z supersedes, wycofany wniosek = POST …/cancel.
Do czasu aktywacji operacje przewodnika odpowiadają 404 notFound lub 409 loanGuideNotConfigured. Uprawnienie write przesyła i anuluje ofertę, read odczytuje stan i ewidencję.
POST /v1/users/{identifier}/loan-offers
Przesyła ofertę do profilu osoby wnioskującej (uprawnienie write). Opcjonalny nagłówek Idempotency-Key ma od 1 do 255 widocznych znaków ASCII. Przykład: pożyczka 10 000 CZK, do zapłaty 10 800 CZK jedną płatnością 30 dni po wypłacie, RRSO 155,10%.
curl -X POST https://api.responsiblo.com/v1/users/applicant-30417/loan-offers \
-H "Authorization: Bearer $RSB_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: offer-30417-1" \
-d '{
"externalApplicationId": "APP-30417",
"offerReference": "OFF-30417-1",
"locale": "cs-CZ",
"currency": "CZK",
"principalMinor": 1000000,
"disbursedAmountMinor": 1000000,
"totalPayableMinor": 1080000,
"aprPercent": "155.10",
"interestRate": { "percent": "8", "period": "month" },
"repayment": {
"type": "singlePayment",
"amountMinor": 1080000,
"due": { "kind": "relative", "days": 30, "anchor": "disbursement" }
},
"documents": [
{ "role": "precontract_information", "reference": "DOC-PRE-30417", "title": "Předsmluvní informace",
"url": "https://documents.lender.example/pre/30417.pdf",
"sha256": "623f4a37e444268c076896d6c2f389b46f568d1a26539b013f2ba25d03846f72" },
{ "role": "contract_package", "reference": "DOC-CON-30417", "title": "Smlouva a podmínky",
"url": "https://documents.lender.example/contract/30417.pdf",
"sha256": "9c7bfe0077d1189914f0e1c483c961f4c5b36e9892385f3d2ab6168e0c088aa6" }
],
"validUntil": "2026-11-15T18:00:00Z"
}'
HTTP/1.1 201 Created
{
"offerReference": "OFF-30417-1",
"externalApplicationId": "APP-30417",
"offerStatus": "active",
"guideStatus": "created",
"validUntil": "2026-11-15T18:00:00Z",
"snapshotSha256": "8055bfa3c5f2c163691b85785eaf61221169a123bed67aff2c1dbaf2a8e44e7e",
"entryUrl": "https://your-company.responsiblo.com/entry/...",
"createdAt": "2026-11-10T09:14:05Z"
}
| Pole | Wymagane | Znaczenie |
|---|---|---|
externalApplicationId |
tak | Państwa numer wniosku, od 1 do 128 znaków A-Z a-z 0-9 . _ : -; nigdy adres e-mail. |
offerReference |
tak | Państwa referencja oferty, te same zasady co externalApplicationId. |
locale |
tak | Język i kraj przewodnika: cs-CZ. |
currency |
tak | Waluta: CZK. |
principalMinor |
tak | Kwota pożyczki w halerzach, liczba całkowita od 1 do 10 000 000 000. |
disbursedAmountMinor |
tak | Wypłacona kwota w halerzach; musi być równa kwocie pożyczki. |
totalPayableMinor |
tak | Całkowita kwota do zapłaty w halerzach; co najmniej kwota pożyczki i dokładnie suma płatności. |
aprPercent |
tak | RRSO w procentach jako tekst ("155.10"), obliczona i gwarantowana przez Państwa. Dodatnie koszty przy RRSO 0 API odrzuci. |
interestRate |
nie | Stopa oprocentowania {percent, period}, period = year, month lub day. |
repayment |
tak | Spłata: singlePayment {amountMinor, due} z datą (kind date) lub liczbą dni od wypłaty (kind relative, od 1 do 365) albo installments {schedule: [{date, amountMinor}]} z liczbą rat od 1 do 360 w kolejności rosnącej, żadna w przeszłości. Typ musi odpowiadać produktowi ustawionemu dla Państwa przewodnika. |
documents |
tak | Od 2 do 10 dokumentów {role, reference, title, url, sha256}; muszą obejmować role wymagane przez ustawienia Państwa przewodnika (domyślnie precontract_information i contract_package). url tylko HTTPS na hoście dozwolonym w ustawieniach Państwa przewodnika, najwyżej 2 048 znaków, bez danych logowania; sha256 = 64 znaki szesnastkowe deklarowane przez Państwa. |
validUntil |
tak | Ważność oferty, RFC 3339 z przesunięciem strefy czasowej, w przyszłości i najwyżej 7 dni naprzód. |
supersedes |
nie | offerReference aktywnej oferty tego samego profilu, którą nowa oferta zastępuje. |
returnUrl |
nie | Opcjonalnie: adres, na który strona „Gotowe” odsyła wnioskodawcę po przewodniku. Tylko bezwzględny HTTPS, najwyżej 2048 znaków, bez danych logowania; symbole {offerReference} i {externalApplicationId} zastępujemy referencjami oferty. Bez niego obowiązuje adres powrotu z ustawień Państwa przewodnika. |
Ta sama treść ponownie (pod tymi samymi referencjami lub tym samym Idempotency-Key) zwraca 200 z istniejącą ofertą i nowym entryUrl; inna treść pod nimi zwraca 409 offerConflict. Profil ma jedną aktywną ofertę: kolejna bez supersedes zwraca 409 activeOfferExists, błędne supersedes 409 notSupersedable. Ustawienia Państwa przewodnika (quiz, kontakt) zostają w tym momencie zablokowane dla oferty.
Stan, ewidencja i anulowanie
GET /v1/users/{identifier}/loan-offers/{offerReference}- stan (uprawnienie read): offerStatus (active, expired, superseded, cancelled), guideStatus (created, in_progress, completed), ukończone lekcje, praktyczne sytuacje, quiz (null, gdy jest wyłączony) oraz chwile przedstawienia oferty, potwierdzenia i prośby o wyjaśnienie. Nigdy odpowiedzi, wartości oferty ani link. Ukończenie pozostaje, nawet jeśli oferta później wygaśnie.GET /v1/users/{identifier}/loan-offers/{offerReference}/evidence- ewidencja do Państwa akt (uprawnienie read): schemaVersion loan-guide-evidence/1, migawka Państwa oferty z odciskiem snapshotSha256, wydanie kursu z odciskami lekcji, zdarzenia w kolejności sequence, każda odpowiedź ze wszystkimi próbami, potwierdzenie i limitations - czego ewidencja nie dowodzi (przedstawione nie znaczy przeczytane, tożsamość deklarują Państwo, dokumenty tylko jako odnośnik, żaden certyfikat, żadne zatwierdzenie pożyczki).POST /v1/users/{identifier}/loan-offers/{offerReference}/cancel- anuluje aktywną ofertę (uprawnienie write), reasonCode = withdrawn_by_provider lub application_closed; 200 zwraca stan, oferta, która nie jest aktywna lub ma ukończony przewodnik, zwraca 409 notActive.
curl https://api.responsiblo.com/v1/users/applicant-30417/loan-offers/OFF-30417-1 -H "Authorization: Bearer $RSB_KEY"
{
"offerReference": "OFF-30417-1",
"externalApplicationId": "APP-30417",
"offerStatus": "active",
"guideStatus": "completed",
"quizEnabled": true,
"lessonsCompleted": 3,
"lessonsTotal": 3,
"practiceCompleted": true,
"quizPassed": true,
"offerPresentedAt": "2026-11-10T18:32:47Z",
"confirmedAt": "2026-11-10T18:34:02Z",
"completedAt": "2026-11-10T18:34:02Z",
"assistanceRequested": false,
"assistanceRequestedAt": null,
"validUntil": "2026-11-15T18:00:00Z",
"evidenceErased": false,
"...": "..."
}
curl -X POST https://api.responsiblo.com/v1/users/applicant-30417/loan-offers/OFF-30417-1/cancel \
-H "Authorization: Bearer $RSB_KEY" \
-H "Content-Type: application/json" \
-d '{"reasonCode":"withdrawn_by_provider"}'
?externalApplicationId= jest potrzebne tylko wtedy, gdy jedna offerReference należy do kilku wniosków profilu (w przeciwnym razie 409 ambiguousOfferReference).
Webhooki przewodnika
Webhook programu (zob. Webhooki) otrzymuje zdarzenia przewodnika bez osobnej subskrypcji. Podpis, doręczanie i ponowienia są takie same jak przy pozostałych zdarzeniach; data zawierają identifier, offerReference, externalApplicationId, guideStatus, occurredAt i sequence (kolejność zdarzeń jednej oferty) - nigdy ewidencji, wartości oferty ani linku wejściowego.
| Zdarzenie | Kiedy |
|---|---|
loanGuide.completed |
osoba wnioskująca przeszła przewodnik i potwierdziła ofertę |
loanGuide.assistanceRequested |
osoba wnioskująca poprosiła o wyjaśnienie (proszę do niej zadzwonić) |
loanGuide.expired |
ofercie upłynął validUntil |
loanGuide.superseded |
ofertę zastąpiła nowa (supersedes) |
loanGuide.cancelled |
anulowali Państwo ofertę |
POST https://your-server.example/responsiblo/webhook
Content-Type: application/json
X-Responsiblo-Event: loanGuide.completed
X-Responsiblo-Delivery: 0f6e2a4c-91d3-4b8e-a7c5-3e2d1b9f6a08
X-Responsiblo-Signature: t=1794335647,v1=8b2d...4c
{
"id": "0f6e2a4c-91d3-4b8e-a7c5-3e2d1b9f6a08",
"type": "loanGuide.completed",
"createdAt": "2026-11-10T18:34:07Z",
"apiVersion": "1.3.2",
"program": "your-program",
"data": {
"identifier": "applicant-30417",
"offerReference": "OFF-30417-1",
"externalApplicationId": "APP-30417",
"guideStatus": "completed",
"occurredAt": "2026-11-10T18:34:02Z",
"sequence": 23
}
}
Każde zdarzenie trafia do jednego webhooka najwyżej raz (klucz idempotencji = X-Responsiblo-Delivery). Webhook utworzony później nie odtwarza starszych zdarzeń, a zdarzenia starsze niż 28 dni nie są już ogłaszane.
Retencja ewidencji
Gdy ścieżka oferty się zakończy (oferta ukończona, anulowana, wygasła lub zastąpiona), biegnie okres przechowywania z ustawień Państwa przewodnika (domyślnie 30 dni). Potem ewidencja zostaje usunięta: GET …/evidence zwraca 410 evidenceErased, a stan nadal odpowiada z evidenceErased: true, referencjami i chwilami. Aktywna oferta nigdy nie jest usuwana. Ewidencję, którą muszą Państwo przechowywać, proszę pobrać zaraz po loanGuide.completed.
Błędy przewodnika
Błędy mają postać API opisaną wyżej. Dodatkowo dla przewodnika:
| HTTP | reason | Co zrobić |
|---|---|---|
| 404 | offerNotFound |
profil nie ma takiej oferty (userNotFound = profil nie istnieje) |
| 409 | offerConflict, activeOfferExists, notSupersedable |
referencje lub Idempotency-Key należą już do innej treści albo profil ma inną aktywną ofertę - proszę przesłać supersedes |
| 409 | loanGuideNotConfigured |
przewodnik nie jest aktywny dla Państwa programu - prosimy o kontakt |
| 409 | ambiguousOfferReference |
proszę dodać ?externalApplicationId= |
| 409 | notActive |
oferta nie jest aktywna lub ma ukończony przewodnik |
| 410 | evidenceErased |
ewidencja została usunięta po okresie retencji, stan pozostaje |
| 422 | invalidOffer |
errors = {ścieżka: kod[,kod]} ze ścieżką w treści (repayment.schedule[2].date, documents[0].url); kody w tabeli poniżej |
| 422 | invalidBody |
supersedes, Idempotency-Key lub treść anulowania |
errors | Kody błędu invalidOffer |
|---|---|
required |
brak pola |
invalidFormat |
zły format (typ, wzorzec, długość, link bez HTTPS lub z danymi logowania) |
outOfRange |
poza dozwolonym zakresem (kwota, liczba dokumentów, rat lub dni) |
notEqualPrincipal |
wypłacona kwota nie jest równa kwocie pożyczki |
sumMismatch |
suma płatności nie jest równa całkowitej kwocie do zapłaty |
belowPrincipal |
całkowita kwota do zapłaty jest niższa niż kwota pożyczki |
aprContradiction |
RRSO 0 przy dodatnich kosztach |
typeMismatch |
typ spłaty nie odpowiada produktowi ustawionemu dla Państwa przewodnika |
missingRole |
brak dokumentu z rolą wymaganą przez ustawienia Państwa przewodnika |
hostNotAllowed |
link dokumentu prowadzi do hosta, którego ustawienia Państwa przewodnika nie dopuszczają |
notAscending |
daty rat nie są rosnące lub się powtarzają |
inPast |
data raty lub validUntil jest w przeszłości |
tooFar |
validUntil jest więcej niż 7 dni naprzód |
unsupported |
nieobsługiwana wartość (locale, currency, type, period, kind) |
unknownField |
pole, którego API nie zna |
looksLikeEmail |
referencja wygląda jak adres e-mail |
Błąd nigdy nie powtarza wartości, którą Państwo przesłali. Przykład: ta sama oferta z płatnością 10 700 CZK zamiast 10 800 CZK i ważnością 9 dni:
"repayment": { "type": "singlePayment", "amountMinor": 1070000, "due": { "kind": "relative", "days": 30, "anchor": "disbursement" } },
"validUntil": "2026-11-19T18:00:00Z"
HTTP/1.1 422 Unprocessable Entity
{
"status": "error",
"code": 422,
"reason": "invalidOffer",
"message": "The offer contains invalid data.",
"errors": {
"repayment.amountMinor": "sumMismatch",
"validUntil": "tooFar"
}
}
Limity
120 wywołań na minutę na klucz. Po 30 odrzuconych kluczach z jednego adresu w ciągu dziesięciu minut adres czeka 10 minut.
Dziennik wywołań (bez treści, identyfikator tylko jako odcisk SHA-256) przechowujemy 180 dni, doręczone i porzucone wiadomości webhooków 30 dni.
Stan i kontrakt
GET /v1/status- bez klucza, zwraca {"status":"ok","version":"1.3.2"}GET /openapi- bez klucza, dokument OpenAPI 3 partnerskiego API
Sandbox
Klucz testowy rsb_test_... otwiera Państwa program testowy z tym samym kursem. Osoby w nim kończą po 7 dniach; webhook programu testowego jest oddzielony od produkcyjnego.
Historia wersji
- 1.3.2 (2026-11) - Każda operacja dokumentu OpenAPI ma nazwę i opis, a operacje są podzielone na grupy. /v1/status i webhooki podają wersję 1.3.2. Kształt żądań i odpowiedzi bez zmian.
- 1.3.1 (2026-10) - Poprawki bez zmian endpointów i ich odpowiedzi.
- 1.3.0 (2026-10) - Przewodnik po pożyczce: POST /v1/users/{identifier}/loan-offers, stan, ewidencja i anulowanie oferty, webhooki loanGuide.*, retencja ewidencji. Opcjonalne pole returnUrl oferty (własny adres powrotu).
- 1.2.0 (2026-10) - GET /v1/users ze stronicowaniem, certyfikat osoby (pole certificate, GET /v1/users/{identifier}/certificate, zdarzenie certificate.issued), DELETE /v1/users/{identifier} (anonimizacja), identyfikator najwyżej 64 znaki, retencja dziennika.
- 1.1.0 (2026-10) - Klucze API, POST /v1/users, GET /v1/users/{identifier} z ?include=detail, link wejściowy, webhooki, jedna postać błędów, publiczny stan i OpenAPI, limity.
- 1.0.0 (2024) - GET /v1/user/{identifier} z JWT klucza partnerskiego.
Chcą Państwo API dla swojej firmy? Prosimy o kontakt