Login & self-service profile — full walkthrough
Logging in
TP=(-H "X-Touchpoint-Code: <code>" -H "X-Touchpoint-Key: <key>" -H "Content-Type: application/json")
curl -sX POST "$BASE/api/v1/login" "${TP[@]}" -d '{
"identifier": "ada@example.com",
"password": "Secret123!"
}'
# → 200 { "customerId": "...", "token": "<Customer JWT>" }
identifier accepts email, cellphone, or document number — whichever the consumer used to
register. Wrong credentials return 401 INVALID_CREDENTIALS (deliberately the same response
whether the identifier doesn't exist or the password is wrong, so you can't enumerate accounts by
probing). Missing/invalid touchpoint credential returns 401 TOUCHPOINT_UNAUTHORIZED instead —
check which code came back.
Hammering login too fast returns 429 RATE_LIMITED with a retryAfter in seconds — see
Errors & rate limits.
Keep the returned token; attach it as Authorization: Bearer <token> on every call below.
Viewing your own profile
JWT=(-H "Authorization: Bearer <token>")
curl -sX GET "$BASE/api/v1/me" "${TP[@]}" "${JWT[@]}"
# → 200 { "id": "...", "version": 3, "firstName": "Ada", "email": "ada@example.com", ... }
version is the optimistic-lock counter — read it before every PATCH.
Editing your own profile
curl -sX PATCH "$BASE/api/v1/me" "${TP[@]}" "${JWT[@]}" -d '{
"version": 3,
"firstName": "Ada",
"addressCity": "Rosario"
}'
# → 200 updated profile, version incremented
Only a fixed field set is honored: version, email, cellphone, country, addressCountry,
addressState, addressCity, addressLine1, addressLine2, addressPostalCode, firstName,
lastName, birthdate, gender, companyName, emailOptin, smsOptin, whatsappOptin,
termsAccepted, privacyAccepted. Anything else — status, type, verification state,
document/identity fields, custom fields — is silently ignored; you cannot escalate your own
account this way.
Things to handle in your UI:
- Stale
version→409 VERSION_CONFLICT. Re-fetchGET /meand retry with the freshversion. - Email/cellphone collision →
409 DUPLICATE_CUSTOMERwithfieldnaming which one. - Changing email or cellphone resets that channel to
UNVERIFIED— prompt the consumer to re-verify (below). - Inactive account →
403 CUSTOMER_INACTIVE.
Verifying a channel
Whether the email/cellphone is fresh (just changed) or was never verified (instant registration), the flow is the same — requires the Customer JWT:
curl -sX POST "$BASE/api/v1/verifications/EMAIL/request" "${TP[@]}" "${JWT[@]}"
# → 202 (code sent)
curl -sX POST "$BASE/api/v1/verifications/EMAIL/confirm" "${TP[@]}" "${JWT[@]}" -d '{"code":"123456"}'
# → 200 { "status": "VERIFIED" }
A wrong code returns 400 INVALID_OTP. channel is EMAIL or CELLPHONE.
Changing your password
curl -sX POST "$BASE/api/v1/password/change" "${TP[@]}" "${JWT[@]}" -d '{
"oldPassword": "Secret123!",
"newPassword": "NewSecret1!"
}'
# → 200
Wrong oldPassword → 401 INVALID_CREDENTIALS.
Forgot / reset password (no session needed)
curl -sX POST "$BASE/api/v1/password/forgot" "${TP[@]}" -d '{"identifier":"ada@example.com","channel":"EMAIL"}'
# → 200 always (doesn't reveal whether the account exists)
curl -sX POST "$BASE/api/v1/password/reset" "${TP[@]}" -d '{
"identifier": "ada@example.com",
"channel": "EMAIL",
"code": "123456",
"newPassword": "Reset123!"
}'
# → 200
Logging out
curl -sX POST "$BASE/api/v1/logout" "${TP[@]}" "${JWT[@]}"
# → 200
Logout is stateless on the server side — there's no session to invalidate remotely. Discard the JWT client-side; it simply expires on its own after that.