In Lesson 1.6 Eric was NOT_ELIGIBLE, but the engine said success. The service would have to read KEZA’s JSON to notice. We want a clean 400 with a clear code and message instead. New idea: response.validation.failureCondition + errorMapping.
| Field | Value | |
|---|---|---|
| **Endpoint adapter *** | FMAPPING (fetch) |
locked after save |
| **Endpoint code *** | VICTOR_KEZA_ELIGIBILITY_DECISION |
locked after save |
| **Endpoint url *** | http://mock-service-engine.apps:8000/victor/keza/v1/eligibility |
|
| **Endpoint type *** | FETCH (set by the adapter) |
|
| **Endpoint name *** | Victor KEZA Eligibility Decision |
|
| **Partner *** | KEZA |
locked after save |
| Active | ON |
|
| **Endpoint description *** | Victor course: eligibility with business-failure validation and a clean transform. |
**Endpoint Mapping ***
{
"method": "GET",
"query": { "nationalId": nationalId, "program": programCode },
"auth": {
"type": "USER_CREDENTIALS",
"baseUrl": "http://mock-service-engine.apps:8000",
"parameters": {
"authPath": "/victor/keza/v1/auth/login",
"bodyTemplate": { "username": "irembo-integration", "password": "Keza@2026" }
},
"tokenConfig": {
"storageKey": "VICTOR_KEZA_TOKEN",
"headerName": "Authorization",
"tokenPrefix": "Bearer",
"expiryBuffer": 300,
"extractPath": "data.token"
}
},
"response": {
"validation": {
"failureCondition": eligibility.status = "NOT_ELIGIBLE",
"errorMapping": {
"code": "KEZA_NOT_ELIGIBLE",
"message": "Not eligible for " & eligibility.programCode & ": " & eligibility.reasonCode,
"exception": "InvalidRequestException"
}
},
"transform": {
"eligible": eligibility.status = "ELIGIBLE",
"fullName": learner.firstName & " " & learner.lastName,
"district": learner.district
}
}
}
responseCode. Choose stable, searchable codes.InvalidRequestException → HTTP 400; NotFoundException → HTTP 404.Secrets · training literal. Hard-coded only because KEZA is a training mock. In a real integration use the environment variable instead: Keza@2026 → "${KEZA_PASSWORD}" (the whole quoted string, nothing before or after; see Lesson 3.4).

Response validation in the portal editor
HTTP 200 0.71 s captured on staging · 26 Sep 2026
1 · Request (curl)
curl -s -X POST "https://integration-gateway.staging.iremboinc.com/integration/v1/fetch/sync" \
-H "Authorization: Bearer $TOKEN" \
-H "portal: integration-management-portal" \
-H "Content-Type: application/json" \
-d '{
"endpointCode": "VICTOR_KEZA_ELIGIBILITY_DECISION",
"callerId": "victor-course",
"requester": "victor-course",
"payload": {
"nationalId": "1199880012345678",
"programCode": "DATA_ANALYTICS"
}
}' | jq
2 · Real response
{
"status": true,
"responseCode": "integration_870000",
"responseMessage": "integration_870000",
"data": {
"id": "26ef9164-bbf6-4af1-a751-4c21922af040",
"endpointCode": "VICTOR_KEZA_ELIGIBILITY_DECISION",
"callerId": "victor-course",
"response": "{\"eligible\":true,\"fullName\":\"Aline Mukamana\",\"district\":\"Gasabo\"}",
"adapterCode": "FMAPPING"
},
"timestamp": "2026-09-26T09:48:18.045610694",
"traceId": "6ab778c158e96695d7201e11155cfb0c"
}
3 · Decoded data.response
{
"eligible": true,
"fullName": "Aline Mukamana",
"district": "Gasabo"
}
4 · What to notice
HTTP 400 0.73 s captured on staging · 26 Sep 2026
1 · Request (curl)
curl -s -X POST "https://integration-gateway.staging.iremboinc.com/integration/v1/fetch/sync" \
-H "Authorization: Bearer $TOKEN" \
-H "portal: integration-management-portal" \
-H "Content-Type: application/json" \
-d '{
"endpointCode": "VICTOR_KEZA_ELIGIBILITY_DECISION",
"callerId": "victor-course",
"requester": "victor-course",
"payload": {
"nationalId": "1199770098765432",
"programCode": "DATA_ANALYTICS"
}
}' | jq
2 · Real response
{
"httpStatus": 400,
"exception": "InvalidRequestException",
"responseCode": "KEZA_NOT_ELIGIBLE",
"responseMessage": "Not eligible for DATA_ANALYTICS: AGE_LIMIT",
"fieldErrors": []
}
3 · What to notice
responseCode KEZA_NOT_ELIGIBLE and a readable message.Gotcha · Always pair failureCondition with errorMapping
A
failureConditionwithouterrorMappingcrashes with a 500 (null pointer) instead of your 400. And the condition only sees 2xx answers: partner 4xx/5xx never reach it.
KEZA returns 200 {"found": false} for unknown learners. You want the caller to get HTTP 404 LEARNER_NOT_FOUND. What do you write?
C. NotFoundException gives 404. InvalidRequestException gives 400; a transform cannot change the HTTP status.
Your turn · predict the status, then prove it
Copy the mapping into
${YOUR_FIRST_NAME}_KEZA_ELIGIBILITY_DECISION(FMAPPING) on your own eligibility mock path. Change the error code to${YOUR_FIRST_NAME}_NOT_ELIGIBLEand the exception toNotFoundException. Replace the variables before saving (Aline →ALINE_…,/aline/…).Predict Eric’s HTTP status before you call. Done when: Eric returns 404 with your code, and Aline still returns 200 with the three flat fields. Then set the exception back to
InvalidRequestExceptionand confirm 400.
← 4.1 Transform the response: dropdown options · 4.3 Accept “errors” that mean success: safe enrollment →