Pour les développeurs
API partenaire
Envoyez-nous un client sous votre propre identifiant pseudonyme - sans e-mail, sans nom ni autres données personnelles - et consultez à tout moment l'état de sa formation. Cela sert de contrôle de conformité avant un contrat, un dépôt ou un versement.
Version 1.3.2 · JSON via HTTPS · OpenAPI
Comment cela fonctionne
L'API est la même pour tous les partenaires. En cinq étapes :
- Nous activons l'API pour votre entreprise ; dans votre administration, vous créez une clé API dans l'onglet API.
- Lorsqu'un client doit être formé, votre système appelle POST /v1/users avec votre identifiant du client.
- Nous créons un profil sans e-mail et renvoyons un lien d'accès (entryUrl) ; vous le montrez au client sous forme de bouton.
- Le client clique dessus et se retrouve directement dans le cours.
- Vous consultez l'état à tout moment via GET /v1/users/{identifier}, ou nous l'annonçons à votre serveur par un webhook.
Vous êtes le responsable du traitement de l'identifiant, nous ne traitons que des données pseudonymisées. N'envoyez jamais un e-mail ni un nom comme identifiant - l'API refuse une adresse e-mail avec l'erreur 422.
Adresse et authentification
Chaque appel passe par HTTPS vers l'adresse ci-dessous et porte votre clé API dans l'en-tête Authorization.
https://api.responsiblo.com Authorization: Bearer rsb_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- rsb_live_... ouvre votre programme de production, rsb_test_... votre programme de test (sandbox).
- La clé ne s'affiche qu'une fois, à sa création ; nous n'en conservons que l'empreinte. Gardez-la comme un secret sur votre serveur - jamais dans un navigateur ni dans une application.
- La clé a des droits : read (l'état et la liste des personnes, le certificat) et write (l'envoi et l'anonymisation des personnes). Elle peut être limitée à vos adresses IP et avoir une validité.
- Renouvellement : vous créez une nouvelle clé, l'ancienne reste valable 7 jours, puis elle expire.
- Les réponses ne sont jamais mises en cache (Cache-Control: no-store) et l'API n'accepte pas d'appels depuis un navigateur (pas de CORS).
POST /v1/users
Envoie une personne dans le programme de la clé (droit 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"}'
| Champ | Obligatoire | Signification |
|---|---|---|
identifier |
oui | Votre pseudonyme de la personne, 1 à 64 caractères A-Z a-z 0-9 . _ : @ - ; jamais une adresse e-mail (refusée avec 422). |
program |
non | Code du programme ; si vous l'indiquez, ce doit être le programme de la clé. |
language |
non | Langue du cours (cs, en, ...) ; par défaut la première langue du programme. |
label |
non | Votre étiquette - une cohorte ou une campagne, 1 à 64 caractères, jamais une donnée personnelle. |
expiresAt |
non | Dernier jour d'accès, AAAA-MM-JJ. |
201 Created pour une nouvelle personne, 200 OK si l'identifiant existe déjà - rien ne change, l'appel peut être répété sans risque. Le corps est l'état ci-dessous, avec entryUrl. Une limite de personnes ou de licences du programme épuisée renvoie 403.
GET /v1/users/{identifier}
État d'une personne (droit read) : ce dont un contrôle de conformité a besoin, rien de plus.
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 | Signification |
|---|---|
enrolled |
envoyée, pas encore entrée |
started |
entrée, rien terminé pour l'instant |
in_progress |
a terminé des leçons, pas encore le programme |
completed |
le programme est terminé (completedAt) |
expired |
l'accès a pris fin (expiresAt est passé ; une personne de la sandbox s'arrête après 7 jours) |
quizScore est le résultat du quiz final en %, dès qu'il est terminé. Les heures sont en UTC à la seconde entière. Le champ certificate porte le certificat de la personne (voir ci-dessous) ; tant qu'elle n'en a pas, il vaut null.
?include=detail
Ajoute la progression dans chaque cours et le résultat de chaque quiz - jamais les réponses individuelles.
"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
Liste des personnes que vous avez envoyées dans le programme de la clé (droit read), page par page : chaque élément a la forme de l'état ci-dessus. En option status (uniquement les personnes dans cet état), limit (1 à 500, 100 par défaut) et 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"
- Continuez avec cursor = nextCursor tant que nextCursor n'est pas null ; le curseur est un texte opaque, ne le composez jamais vous-même.
- Les personnes viennent selon le moment de leur envoi, dans un ordre stable (y compris au même moment), aucune deux fois ; les personnes anonymisées ne figurent pas dans la liste.
- Avec le filtre status, nous parcourons au plus 2000 personnes pour une page ; une page peut donc contenir moins d'éléments que limit, voire aucun - continuez tant qu'il y a un nextCursor.
Certificat de la personne
Dès que la personne termine le programme, le cours lui délivre un certificat - sous son pseudonyme (le surnom du profil ID XXXXXX), sans nom et sans e-mail. Rien n'est envoyé par e-mail ; l'état de la personne contient le champ certificate avec le numéro, les dates et la page publique de vérification, et vous téléchargez le PDF via 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
- La page de vérification verifyUrl n'affiche que le pseudonyme, le programme, le partenaire et la validité - jamais votre identifiant.
- Le PDF renvoie application/pdf (droit read). Sans certificat, la réponse est 404 certificateNotFound ; tant que le PDF est en cours de fabrication, 404 certificatePdfNotReady avec Retry-After.
- Un certificat révoqué n'est jamais délivré (le champ certificate vaut alors null, le PDF 404) ; un certificat dont la validité a expiré reste une preuve véridique et il est délivré.
- Un webhook annonce le certificat par l'événement certificate.issued (juste après user.completed).
DELETE /v1/users/{identifier}
Anonymise une personne (droit write) : votre identifiant, l'étiquette et chaque message de webhook qui le nomme disparaissent du profil ; les liens d'accès cessent d'être valables. Le certificat et le résultat du cours restent sous le numéro du certificat - comme preuve de conformité.
curl -X DELETE https://api.responsiblo.com/v1/users/client-48213 -H "Authorization: Bearer $RSB_KEY" HTTP/1.1 204 No Content
Réponse 204 sans corps ; tout appel suivant avec le même identifiant renvoie 404 userNotFound, la répétition est donc sans risque. Vous pouvez ensuite renvoyer le même identifiant comme une nouvelle personne.
Lien d'accès
Montrez entryUrl à la personne (un bouton Démarrer le cours dans votre système). Il la connecte au cours - sans e-mail et sans mot de passe.
Le lien est valable 30 jours et peut être utilisé plusieurs fois ; chaque appel GET /v1/users/{identifier} en renvoie un nouveau. Ne l'envoyez jamais à quelqu'un d'autre : qui a le lien entre en tant que cette personne.
Webhooks
Dans l'onglet API de votre administration, vous configurez un webhook par programme : une adresse HTTPS publique de votre serveur et les événements. Nous vous envoyons ensuite un POST avec du JSON - uniquement des identifiants et des états, jamais le lien d'accès.
| Événement | Quand |
|---|---|
user.enrolled |
la personne a été envoyée (la première fois que votre webhook la connaît) |
user.started |
la personne est entrée dans le cours |
user.completed |
la personne a terminé le programme |
certificate.issued |
la personne a obtenu un certificat ; data contient certificate (le numéro, les dates, verifyUrl) |
user.expired |
l'accès de la personne a pris fin |
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
}
}
Signature
Chaque message porte l'en-tête X-Responsiblo-Signature: t=<temps Unix>,v1=<HMAC-SHA256 du texte t.corps avec le secret du webhook, hex>. Le secret (whsec_...) s'affiche une fois à la création du webhook. Avant de faire confiance à un message, vérifiez la signature et l'âge de t ; utilisez X-Responsiblo-Delivery comme clé d'idempotence.
// 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]);
Livraison et nouvelles tentatives
Livré = réponse 2xx en moins de 10 secondes. Sinon, nous réessayons après 1 minute, 5 minutes, 30 minutes, 2 heures et 12 heures, puis nous abandonnons. Nous ne suivons pas les redirections.
20 messages non livrés d'affilée désactivent le webhook jusqu'à ce que vous le réactiviez ; les messages de cette période attendent. Le bouton Test envoie un ping ; le journal des livraisons se trouve dans votre administration.
Vous ajoutez l'événement certificate.issued à un webhook dans ses paramètres ; un webhook créé avant la version 1.2 ne le reçoit pas de lui-même.
Erreurs
Chaque erreur a une seule forme : status, code, reason et message ; une erreur 422 ajoute errors (champ - ce qui ne va pas).
{ "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 | Que faire |
|---|---|---|
| 400 | invalidJson |
envoyez un seul objet JSON |
| 401 | missingToken, invalidToken |
envoyez une clé valide (une clé révoquée et une clé expirée se ressemblent) ; l'en-tête WWW-Authenticate indique Bearer |
| 403 | scopeDenied, ipNotAllowed, apiDisabled, partnerInactive, spaceUnavailable, httpsRequired, userLimitReached, seatsExhausted |
la clé n'a pas ce droit, l'API est désactivée pour votre entreprise, ou le programme est complet |
| 404 | userNotFound, notFound |
aucune personne avec cet identifiant dans le programme de la clé (pas même anonymisée) |
| 404 | certificateNotFound, certificatePdfNotReady |
la personne n'a pas encore de certificat, ou son PDF est en cours de fabrication - réessayez après Retry-After |
| 409 | identifierTaken |
l'identifiant appartient à une personne d'un autre programme |
| 422 | invalidBody, invalidParameter |
voir errors (un champ du corps ou un paramètre de la requête - ce qui ne va pas) |
| 429 | rateLimited |
attendez Retry-After secondes |
| 500 | internalError |
réessayez plus tard ; indiquez incidentId à notre support |
Pour les programmes et les agents
- Décidez selon code et reason, jamais selon le texte de message ; errors est un objet champ -> ce qui ne va pas.
- Ne répétez que 429, 500 et certificatePdfNotReady, après Retry-After secondes (sinon avec un intervalle croissant) ; ne répétez pas les autres 4xx que 429 sans corriger l'appel.
- POST /v1/users est idempotent selon identifier (201 la première fois, puis 200) ; DELETE renvoie 204 la première fois et 404 ensuite - les deux peuvent être répétés sans risque.
- Dédupliquez les webhooks selon X-Responsiblo-Delivery ; l'ordre des messages n'est pas garanti, c'est l'état dans data qui décide.
Guide du prêt
Le guide du prêt est un court cours destiné à la personne qui demande un prêt auprès d'un prêteur : avant de signer le contrat, elle suit trois leçons, huit situations pratiques et, le cas échéant, un quiz, le tout avec les chiffres de sa propre offre, puis elle confirme l'offre à la fin. Sur chaque écran, elle peut demander une explication. Vous envoyez l'offre via l'API, vous recevez un lien d'accès et un webhook vous annonce le résultat.
Nous activons le guide du prêt en accord avec vous.
Ici aussi, la personne qui fait la demande n'est que votre profil pseudonymisé issu de POST /v1/users. L'offre est déterminée par vos références (externalApplicationId, offerReference) et les documents uniquement par un lien avec une empreinte SHA-256 - jamais un nom, un e-mail, un numéro d'identification national, un numéro de compte ni un téléphone. responsiblo n'approuve pas le prêt, ne télécharge ni ne conserve les documents, ne vérifie pas l'identité et ne délivre aucun certificat pour le guide.
- Vous créez le profil de la personne qui fait la demande : POST /v1/users avec votre pseudonyme.
- Vous envoyez l'offre : POST /v1/users/{identifier}/loan-offers ; la réponse 201 porte entryUrl.
- Vous transmettez entryUrl à la personne par votre propre canal vérifié. Le lien est valable 30 jours et peut être utilisé plusieurs fois ; le guide affiche les chiffres de son offre.
- Vous apprenez la fin par un webhook (loanGuide.completed, loanGuide.assistanceRequested et d'autres).
- Vous lisez l'état via GET …/loan-offers/{offerReference}, l'enregistrement pour votre dossier via GET …/evidence. Offre modifiée = nouvelle offre avec supersedes, demande retirée = POST …/cancel.
Jusqu'à l'activation, les opérations du guide répondent 404 notFound ou 409 loanGuideNotConfigured. Le droit write envoie et annule une offre, read lit l'état et la preuve.
POST /v1/users/{identifier}/loan-offers
Envoie une offre pour le profil de la personne qui fait la demande (droit write). L'en-tête facultatif Idempotency-Key compte de 1 à 255 caractères ASCII visibles. Exemple : prêt de 10 000 CZK, 10 800 CZK à payer en un seul paiement 30 jours après le versement, TAEG 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"
}
| Champ | Obligatoire | Signification |
|---|---|---|
externalApplicationId |
oui | Votre numéro de demande, 1 à 128 caractères A-Z a-z 0-9 . _ : -; jamais une adresse e-mail. |
offerReference |
oui | Votre référence de l'offre, mêmes règles que externalApplicationId. |
locale |
oui | Langue et pays du guide : cs-CZ. |
currency |
oui | Devise : CZK. |
principalMinor |
oui | Montant du prêt en hellers (centièmes de couronne), nombre entier de 1 à 10 000 000 000. |
disbursedAmountMinor |
oui | Montant versé en hellers ; il doit être égal au montant du prêt. |
totalPayableMinor |
oui | Montant total à payer en hellers ; au moins le montant du prêt et exactement la somme des paiements. |
aprPercent |
oui | TAEG en pourcentage sous forme de texte ("155.10"), calculé et garanti par vous. L'API refuse des coûts positifs avec un TAEG de 0. |
interestRate |
non | Taux d'intérêt {percent, period}, period = year, month ou day. |
repayment |
oui | Remboursement : singlePayment {amountMinor, due} avec une date (kind date) ou un nombre de jours à compter du versement (kind relative, 1 à 365), ou installments {schedule: [{date, amountMinor}]} avec 1 à 360 échéances par ordre croissant, aucune dans le passé. Le type doit correspondre au produit configuré pour votre guide. |
documents |
oui | 2 à 10 documents {role, reference, title, url, sha256} ; les rôles exigés par les paramètres de votre guide doivent être couverts (par défaut precontract_information et contract_package). url uniquement en HTTPS sur un hôte autorisé dans les paramètres de votre guide, 2 048 caractères au plus, sans identifiants de connexion ; sha256 = 64 caractères hexadécimaux que vous déclarez. |
validUntil |
oui | Validité de l'offre, RFC 3339 avec décalage horaire, dans le futur et au plus 7 jours à l'avance. |
supersedes |
non | offerReference de l'offre active du même profil que la nouvelle offre remplace. |
returnUrl |
non | Facultatif : l'adresse vers laquelle la page « Terminé » renvoie le demandeur à la fin du guide. HTTPS absolu uniquement, 2 048 caractères au maximum, sans identifiants ; nous remplaçons les symboles {offerReference} et {externalApplicationId} par les références de l'offre. Sans elle, l'adresse de retour des paramètres de votre guide s'applique. |
Le même corps envoyé à nouveau (sous les mêmes références ou la même Idempotency-Key) renvoie 200 avec l'offre existante et un nouvel entryUrl ; un autre corps sous celles-ci renvoie 409 offerConflict. Un profil a une seule offre active : une autre sans supersedes renvoie 409 activeOfferExists, un supersedes erroné 409 notSupersedable. Les paramètres de votre guide (quiz, contact) sont alors verrouillés pour l'offre.
État, preuve et annulation
GET /v1/users/{identifier}/loan-offers/{offerReference}- état (droit read) : offerStatus (active, expired, superseded, cancelled), guideStatus (created, in_progress, completed), leçons terminées, pratique, quiz (null s'il est désactivé) et les moments de la présentation de l'offre, de la confirmation et de la demande d'explication. Jamais les réponses, les valeurs de l'offre ni le lien. L'achèvement reste acquis même si l'offre expire plus tard.GET /v1/users/{identifier}/loan-offers/{offerReference}/evidence- enregistrement pour votre dossier (droit read) : schemaVersion loan-guide-evidence/1, instantané de votre offre avec son empreinte snapshotSha256, édition du cours avec les empreintes des leçons, événements dans l'ordre de sequence, chaque réponse avec toutes ses tentatives, la confirmation et limitations - ce que l'enregistrement ne prouve pas (présenté ne signifie pas lu, l'identité est affirmée par vous, les documents uniquement par référence, aucun certificat, aucune approbation du prêt).POST /v1/users/{identifier}/loan-offers/{offerReference}/cancel- annule une offre active (droit write), reasonCode = withdrawn_by_provider ou application_closed ; 200 renvoie l'état, une offre qui n'est pas active ou dont le guide est terminé renvoie 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= n'est nécessaire que lorsqu'une offerReference appartient à plusieurs demandes du profil (sinon 409 ambiguousOfferReference).
Webhooks du guide
Le webhook du programme (voir Webhooks) reçoit les événements du guide sans abonnement particulier. La signature, la livraison et les nouvelles tentatives sont les mêmes que pour les autres événements ; data portent identifier, offerReference, externalApplicationId, guideStatus, occurredAt et sequence (l'ordre des événements d'une offre) - jamais la preuve, les valeurs de l'offre ni le lien d'accès.
| Événement | Quand |
|---|---|
loanGuide.completed |
la personne a parcouru le guide et confirmé l'offre |
loanGuide.assistanceRequested |
la personne a demandé une explication (appelez-la) |
loanGuide.expired |
le validUntil de l'offre est dépassé |
loanGuide.superseded |
une nouvelle offre l'a remplacée (supersedes) |
loanGuide.cancelled |
vous avez annulé l'offre |
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
}
}
Chaque événement parvient au plus une fois à un même webhook (clé d'idempotence = X-Responsiblo-Delivery). Un webhook créé plus tard ne rejoue pas les événements plus anciens, et les événements de plus de 28 jours ne sont plus annoncés.
Conservation de la preuve
Lorsque le parcours d'une offre se termine (offre terminée, annulée, expirée ou remplacée), la durée de conservation des paramètres de votre guide court (30 jours par défaut). Ensuite, la preuve est supprimée : GET …/evidence renvoie 410 evidenceErased et l'état continue de répondre avec evidenceErased: true, les références et les moments. Une offre active n'est jamais supprimée. Téléchargez la preuve que vous devez conserver juste après loanGuide.completed.
Erreurs du guide
Les erreurs ont la forme de l'API ci-dessus. En plus, pour le guide :
| HTTP | reason | Que faire |
|---|---|---|
| 404 | offerNotFound |
le profil n'a pas une telle offre (userNotFound = le profil n'existe pas) |
| 409 | offerConflict, activeOfferExists, notSupersedable |
les références ou l'Idempotency-Key appartiennent déjà à un autre corps, ou le profil a une autre offre active - envoyez supersedes |
| 409 | loanGuideNotConfigured |
le guide n'est pas activé pour votre programme - écrivez-nous |
| 409 | ambiguousOfferReference |
ajoutez ?externalApplicationId= |
| 409 | notActive |
l'offre n'est pas active ou son guide est terminé |
| 410 | evidenceErased |
la preuve a été supprimée après la durée de conservation, l'état reste |
| 422 | invalidOffer |
errors = {chemin: code[,code]} avec le chemin dans le corps (repayment.schedule[2].date, documents[0].url) ; les codes dans le tableau ci-dessous |
| 422 | invalidBody |
supersedes, Idempotency-Key ou corps de l'annulation |
errors | Codes de l'erreur invalidOffer |
|---|---|
required |
le champ manque |
invalidFormat |
forme incorrecte (type, motif, longueur, lien sans HTTPS ou avec identifiants de connexion) |
outOfRange |
hors de la plage autorisée (montant, nombre de documents, d'échéances ou de jours) |
notEqualPrincipal |
le montant versé n'est pas égal au montant du prêt |
sumMismatch |
la somme des paiements n'est pas égale au montant total à payer |
belowPrincipal |
le montant total à payer est inférieur au montant du prêt |
aprContradiction |
TAEG de 0 avec des coûts positifs |
typeMismatch |
le type de remboursement ne correspond pas au produit configuré pour votre guide |
missingRole |
il manque un document avec un rôle exigé par les paramètres de votre guide |
hostNotAllowed |
le lien d'un document pointe vers un hôte que les paramètres de votre guide n'autorisent pas |
notAscending |
les dates des échéances ne sont pas croissantes ou se répètent |
inPast |
la date d'une échéance ou validUntil est dans le passé |
tooFar |
validUntil est à plus de 7 jours dans le futur |
unsupported |
valeur non prise en charge (locale, currency, type, period, kind) |
unknownField |
champ que l'API ne connaît pas |
looksLikeEmail |
une référence ressemble à une adresse e-mail |
Une erreur ne répète jamais une valeur que vous avez envoyée. Exemple : la même offre avec un paiement de 10 700 CZK au lieu de 10 800 CZK et une validité de 9 jours :
"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"
}
}
Limites
120 appels par minute et par clé. Après 30 clés refusées depuis une même adresse en dix minutes, l'adresse attend 10 minutes.
Nous conservons le journal des appels (sans corps, l'identifiant uniquement sous forme d'empreinte SHA-256) 180 jours, les messages de webhook livrés et abandonnés 30 jours.
État et contrat
GET /v1/status- sans clé, renvoie {"status":"ok","version":"1.3.2"}GET /openapi- sans clé, le document OpenAPI 3 de l'API partenaire
Sandbox
La clé de test rsb_test_... ouvre votre programme de test avec le même cours. Les personnes y prennent fin après 7 jours ; le webhook du programme de test est séparé de celui de production.
Historique des versions
- 1.3.2 (2026-11) - Chaque opération du document OpenAPI a un nom et une description, et les opérations sont réparties en groupes. /v1/status et les webhooks indiquent la version 1.3.2. La forme des requêtes et des réponses reste inchangée.
- 1.3.1 (2026-10) - Corrections sans changement des endpoints ni de leurs réponses.
- 1.3.0 (2026-10) - Guide du prêt : POST /v1/users/{identifier}/loan-offers, état, preuve et annulation d'une offre, webhooks loanGuide.*, conservation de la preuve. Champ facultatif returnUrl d'une offre (adresse de retour propre).
- 1.2.0 (2026-10) - GET /v1/users avec pagination, le certificat de la personne (champ certificate, GET /v1/users/{identifier}/certificate, événement certificate.issued), DELETE /v1/users/{identifier} (anonymisation), identifiant de 64 caractères au plus, conservation du journal.
- 1.1.0 (2026-10) - Clés API, POST /v1/users, GET /v1/users/{identifier} avec ?include=detail, lien d'accès, webhooks, une seule forme d'erreurs, état public et OpenAPI, limites.
- 1.0.0 (2024) - GET /v1/user/{identifier} avec le JWT de la clé partenaire.
Vous voulez l'API pour votre entreprise ? Écrivez-nous