Skip to content

Status postbacks

For: Lenders (integration team)

When a consumer applies for one of your products through Prosperas, you process that application on your side (approve it, disburse it, reject it). A postback is how you tell Prosperas what happened, in near real time, so we can update the lead status, reconcile revenue, and keep the consumer experience in sync.

The integration is deliberately small: one endpoint, one credential, one payload shape.

Property Value
Direction You → Prosperas (you call us)
Endpoint POST {BASE_URL}/client_app/webhook/lender/loan-status
Auth X-API-KEY header (recommended) or source-IP allowlist
Body format JSON, snake_case
Events application, approval, disbursement, rejected
Success 200 OK with a JSON acknowledgement
Retries You retry on 5xx / network errors (we do not retry you)

Every postback must authenticate. Prosperas checks the API key first, then the source IP. If neither matches a registered credential, the request is rejected with 403.

Send your key in the HTTP header:

X-API-KEY: <your-key>
  • The header name is case-insensitive (X-API-KEY, x-api-key, X-Api-Key all work).
  • The key is matched by exact string. No prefix, no Bearer, no encoding.

If you were provisioned by IP, no header is required — we read your source IP from X-Forwarded-For, then X-Real-IP, then the socket peer.

  • The match is exact string against the IP we registered.
  • No CIDR / subnet ranges are supported. Every individual egress IP you use must be registered. If your infrastructure rotates IPs, use the API key method instead.

Authentication is not only about the credential — it is bound to a real lead. A request succeeds only when all of the following hold:

  1. Your credential (key or IP) matches a registered lender origin, and
  2. the click_id in the request resolves to a lead, and
  3. that lead belongs to a product owned by your lender account.

If your credential is valid but the click_id does not resolve to one of your leads, you still get 403 (not 404). In practice this means: a wrong, unknown, or foreign click_id returns 403.

click_id is the single identifier that ties a consumer’s journey together across Prosperas and your systems.

  • Prosperas generates it and hands it to you at the moment the consumer is redirected to you (as the tracking / click identifier in the hand-off URL).
  • You must store it and echo it back — exactly — in every postback for that application.
  • It carries no personal data; it is an opaque reference.

Accepted formats:

Format Example Notes
Bare UUID 7e1c2f1f-9b4d-4c1d-9f6c-2f3c1a2b4d5e
orgname_UUID claro_7e1c2f1f-9b4d-4c1d-9f6c-2f3c1a2b4d5e Exactly one underscore

More than one underscore, or an unparseable UUID, returns 400.

Method: POST (recommended). A GET variant exists with the same fields as query parameters, but POST with a JSON body is the supported server-to-server method.

Headers:

Content-Type: application/json
X-API-KEY: <your-key>

Body (JSON, snake_case):

{
"click_id": "claro_7e1c2f1f-9b4d-4c1d-9f6c-2f3c1a2b4d5e",
"event": "approval",
"occurred_at": "2026-07-01T12:34:56Z",
"data": {
"provider": "your-brand",
"client": {
"email": "consumer@example.com",
"fullName": "Ana Gomez",
"firstName": "Ana",
"lastName": "Gomez",
"idNumber": "1234567890",
"phoneNumber": "3001234567",
"returningCustomer": false
}
}
}
Field Type Required Notes
click_id string Yes The tracking id described above. Echo it exactly.
event string Yes One of application, approval, disbursement, rejected. Lowercase only — uppercase is rejected with 422.
occurred_at string ISO-8601 timestamp of when the event happened on your side (e.g. 2026-07-01T12:34:56Z).
data object Optional audit blob. Recognized keys: provider (string) and client (object below).
data.client object Optional consumer data. See next section.

data.client lets you enrich the consumer record. All fields are optional.

Field Type Notes
email string
firstName string Used only if fullName is absent.
lastName string Used only if fullName is absent.
fullName string Takes priority: first token → first name, remainder → last name.
idNumber string National ID / document number.
phoneNumber string
returningCustomer boolean Defaults to false if omitted. See the caution below.

Send one postback per status transition, using the event that matches what happened:

event Meaning Required?
application The consumer’s application was received / started on your side. Optional
approval The application was approved. Yes
disbursement Funds were disbursed. Yes
rejected The application was rejected. Yes

application is accepted but optional — send it if you have a meaningful “application received” milestone; otherwise the three terminal outcomes (approval, disbursement, rejected) are what matter most.

Send events in the order they occur. Prosperas tolerates events arriving out of order, but in-order delivery keeps the lead history clean.

Success body (200 OK):

{
"ok": true,
"lead_id": 12345,
"status": "APPROVAL",
"user_id": 6789
}
  • ok — always true on success.
  • lead_id — the Prosperas lead the event was recorded against.
  • status — the internal status your event mapped to (APPLICATION / APPROVAL / DISBURSEMENT / REJECTED).
  • user_id — the consumer record id, when available.

Status codes:

Code Meaning What you should do
200 Event recorded. Done.
400 Malformed click_id (bad UUID or too many underscores). Fix the click_id; do not retry unchanged.
403 Auth failed or the click_id doesn’t resolve to one of your leads. Check your key/IP and that you’re echoing the correct click_id. Do not blindly retry.
404 Session not found (rare edge, after auth succeeds). Verify the click_id; contact Prosperas if it persists.
422 Validation error — e.g. camelCase clickId, uppercase event, wrong types. Fix the payload shape (see common mistakes below). Do not retry unchanged.
5xx Transient Prosperas-side error. Retry with exponential backoff (see below).

Common mistakes (read this before you build)

Section titled “Common mistakes (read this before you build)”

These four mistakes account for almost every failed first integration. Avoid them:

❌ Don’t ✅ Do
Use camelCase clickId in the body Use snake_case click_id — camelCase → 422
Send event: "APPROVAL" (uppercase) Send lowercase approval — uppercase → 422
Assume the endpoint is public / no auth Send X-API-KEY (or call from an allowlisted IP) — else 403
Put the API key in a query string or expect the pixel to authenticate Send the key in the X-API-KEY header on a POST
  • You own retries. Prosperas does not retry you. On a 5xx or a network failure, retry the postback with exponential backoff (e.g. 1s, 2s, 4s, 8s…), up to a sensible ceiling.
  • Do not retry on 4xx. A 400, 403, or 422 means the request is wrong — fix it and send a corrected request instead of hammering the same payload.
  • The endpoint is not idempotent. Each accepted postback records a new event. If you retry after a request that actually succeeded (but whose response you missed), you may create a duplicate event. Keep retries bounded and prefer retrying only on confirmed failures.
  • Every request is logged on our side (with your API key masked) for support and reconciliation.
Ventana de terminal
curl -X POST "{BASE_URL}/client_app/webhook/lender/loan-status" \
-H "Content-Type: application/json" \
-H "X-API-KEY: <your-key>" \
-d '{
"click_id": "claro_7e1c2f1f-9b4d-4c1d-9f6c-2f3c1a2b4d5e",
"event": "approval",
"occurred_at": "2026-07-01T12:34:56Z",
"data": { "provider": "your-brand" }
}'

Response — 200 OK:

{ "ok": true, "lead_id": 12345, "status": "APPROVAL", "user_id": 6789 }

Disbursement with consumer enrichment (POST)

Section titled “Disbursement with consumer enrichment (POST)”
Ventana de terminal
curl -X POST "{BASE_URL}/client_app/webhook/lender/loan-status" \
-H "Content-Type: application/json" \
-H "X-API-KEY: <your-key>" \
-d '{
"click_id": "7e1c2f1f-9b4d-4c1d-9f6c-2f3c1a2b4d5e",
"event": "disbursement",
"occurred_at": "2026-07-01T15:00:00Z",
"data": {
"provider": "your-brand",
"client": { "fullName": "Ana Gomez", "idNumber": "1234567890" }
}
}'
Ventana de terminal
# WRONG: "clickId" (camelCase) instead of "click_id"
curl -X POST "{BASE_URL}/client_app/webhook/lender/loan-status" \
-H "Content-Type: application/json" \
-H "X-API-KEY: <your-key>" \
-d '{ "clickId": "7e1c2f1f-...", "event": "approval" }'
# → 422 Unprocessable Entity (field "click_id" is required)

Error — missing / wrong credential (403)

Section titled “Error — missing / wrong credential (403)”
Ventana de terminal
# No X-API-KEY header and IP not allowlisted → 403
curl -X POST "{BASE_URL}/client_app/webhook/lender/loan-status" \
-H "Content-Type: application/json" \
-d '{ "click_id": "7e1c2f1f-...", "event": "approval" }'
# → 403 Forbidden
Endpoint POST {BASE_URL}/client_app/webhook/lender/loan-status
Auth header X-API-KEY: <your-key> (case-insensitive)
Required body fields click_id (snake_case), event (lowercase)
Events application · approval · disbursement · rejected
Optional body fields occurred_at (ISO-8601), data, data.client
Success 200{ ok, lead_id, status, user_id }
Client errors 400 bad click_id · 403 auth/lead · 404 session · 422 validation
Retry on 5xx / network only, exponential backoff
Signing None (no HMAC) — protect the API key

Next step: with postbacks working, close out the integration with Product data.


Last verified: 2026-07-01 · v1.1 · matches Lender-Postback-Integration-Guide.md