API reference
All calls are HTTPS and JSON unless noted. Error bodies and general rules are in Integration conventions.
You call core
Section titled “You call core”Base: https://test-api.finnsbali.com/api/v1/booking · Authorization: Bearer <booking API token>
POST /handoffs/peek
Section titled “POST /handoffs/peek”Who does this code belong to? Does not use the code up.
// Request{ "code": "q3V0…43 chars" }// 200{ "displayName": "Ayu Lestari", "email": "ayu@example.com" }displayName may be "", email may be null. Any unknown, used, expired, revoked, malformed or wrong-audience code: 404 not_found.
POST /handoffs/redeem
Section titled “POST /handoffs/redeem”Use the code up and learn who it is. Succeeds once, even under concurrent requests.
// Request{ "code": "q3V0…" }// 200{ "sub": "6f1c2a…", "sid": "a9d0…", "displayName": "Ayu Lestari", "email": "ayu@example.com" }Errors: 404 not_found as above. Never retry a redeem.
POST /bookings
Section titled “POST /bookings”A booking was paid. Credits floor(totalIdr / 10000) points once per bookingId.
// Request{ "sub": "6f1c2a…", "bookingId": "BK-2026-10-13-0042", "totalIdr": 3155000 }| Answer | When |
|---|---|
204 |
Credited, nothing to credit, or a repeat of the same request |
400 malformed |
Not JSON |
422 invalid |
fields names sub, bookingId or totalIdr as required or invalid |
422 idempotency_mismatch |
Same bookingId, different totalIdr |
Retry timeouts, 5xx and 429 with the same body.
Core calls you
Section titled “Core calls you”POST /auth/revoke
Section titled “POST /auth/revoke”At the root of your origin · Authorization: Bearer <revoke token>
{ "sub": "6f1c2a…", "sid": "a9d0…" }Answer 200. Delete sessions for sub and sid. See Signing out.
Keycloak
Section titled “Keycloak”| Issuer | https://test-auth.finnsbeachclub.com/realms/finns |
| Discovery | {issuer}/.well-known/openid-configuration |
| Client | Your own, public with PKCE (S256), scopes openid email profile |
| Redirect URI | Your /redirect (exact match) |
| Back-channel logout | Your /auth/backchannel-logout, session required |
| Variants you use | prompt=none (silent), plain, prompt=login&max_age=0 (fresh, before payment) |
Credentials FINNS gives you
Section titled “Credentials FINNS gives you”| Secret | Direction | Use |
|---|---|---|
| Booking API token | you → core | Authorization on every call above |
| Revoke token | core → you | Check it on /auth/revoke |
| Keycloak client id | you → Keycloak | Public client, no secret |
Both tokens are at least 32 characters, different from each other, and rotated by arrangement with FINNS.
Internal and confidential. Share partner sections only as partner builds (pnpm build:partner).

