-
1. Sign up (customer)
Signup creates a draft account and emails a magic link to verify the address. The magic link is single-use and expires in 24 hours.
curl -X POST https://billing-api.pbx.lt/v1/signup \ -H 'content-type: application/json' \ -d '{ "email": "[email protected]", "company_name": "Acme Ltd", "country": "LT", "plan_tier": "starter" }'On success: HTTP 202 with
{ "signup_id": "..." }. The email arrives within seconds. -
2. Redeem the magic link (first login)
The link lands you on billing.pbx.lt, which redeems the token and prompts you to set a password. The raw redemption endpoint:
curl -X POST https://billing-api.pbx.lt/v1/auth/magic-link/redeem \ -H 'content-type: application/json' \ -d '{ "token": "MAGIC_LINK_TOKEN_FROM_EMAIL", "password": "<new-strong-password>" }'On success: HTTP 200 with
{ "access_token": "...", "refresh_token": "...", "expires_in": 900 }. -
3. Sign in (returning customer)
curl -X POST https://billing-api.pbx.lt/v1/auth/sign-in \ -H 'content-type: application/json' \ -d '{ "email": "[email protected]", "password": "<password>" }'On failure: HTTP 401 with a problem-details body whose
typeisurn:codus-nullus:pbx-billing:problem:auth.invalid_credentials. -
4. Sign in (admin, 2FA-gated)
Admin sessions require an enrolled TOTP authenticator. The flow is two-step: post credentials, then post the 6-digit code with the challenge id from the first response. Both happen in the admin.pbx.lt sign-in screen.
# Step 1: post credentials, get a 2FA challenge curl -X POST https://billing-api.pbx.lt/v1/auth/admin/sign-in \ -H 'content-type: application/json' \ -d '{ "email": "[email protected]", "password": "<password>" }' # -> 200 { "challenge_id": "...", "expires_in": 300 } # Step 2: post the TOTP code curl -X POST https://billing-api.pbx.lt/v1/auth/admin/2fa/verify \ -H 'content-type: application/json' \ -d '{ "challenge_id": "...", "code": "123456" }' # -> 200 { "access_token": "...", "refresh_token": "...", "expires_in": 900 }On invalid code: HTTP 401, problem-details type
urn:codus-nullus:pbx-billing:problem:auth.totp_invalid. -
5. Call a protected endpoint
curl https://billing-api.pbx.lt/v1/me \ -H 'authorization: Bearer ACCESS_TOKEN' -
6. Refresh the access token
Access tokens expire after 15 minutes. Refresh tokens last 30 days and rotate on every refresh - store the new refresh token and discard the old one on every call.
curl -X POST https://billing-api.pbx.lt/v1/auth/refresh \ -H 'content-type: application/json' \ -d '{ "refresh_token": "REFRESH_TOKEN" }' -
JWT shape
sub: user id (UUID)acc: account id (UUID)-
roles: array ofcustomer|admin|support iat/exp:exp - iat = 900seconds-
twofa:truefor admin sessions that completed step 2 above; absent otherwise
-
Idempotency-Key (required for mutating endpoints)
Every mutating endpoint that touches money, subscriptions, or upstream pbx-core provisioning requires a client-generated
Idempotency-Keyheader. We store the first response for 24 hours and replay it on retry. See the reference for the per-endpoint requirement.curl -X POST https://billing-api.pbx.lt/v1/payments/topup \ -H 'authorization: Bearer ACCESS_TOKEN' \ -H 'content-type: application/json' \ -H 'idempotency-key: 9b5c2e3a-4d7e-4f8a-9b6c-1a2b3c4d5e6f' \ -d '{ "amount_minor": 5000, "currency": "EUR", "save_card": true }'Use a UUID v4 per logical operation. Same key + same body returns the original response; same key + different body returns HTTP 409.
-
Sign out
curl -X POST https://billing-api.pbx.lt/v1/auth/sign-out \ -H 'authorization: Bearer ACCESS_TOKEN'
Auth
Authentication
The pbx-billing API uses bearer JWTs. Customers go through a magic-link first-login flow on signup; subsequent sessions use email + password. The admin surface additionally requires TOTP 2FA. The sections below walk through the complete flow with copy-pasteable curl examples.