Build with AnybanQID
AnybanQID is a private digital identity service operated by Clobe (Pvt) Ltd. Your users prove who they are once, then approve logins, transactions and document signatures in the AnybanQID app โ biometric-gated, device-bound. Two integrations work today: CIBA and App approval.
Use cases
๐ฒ Decoupled auth (CIBA)
- Call centre, POS, kiosk, web โ no browser redirect on the user's side.
- Initiate with
login_hint=nic:<nic>, poll the token endpoint (poll mode). - The user approves the request in the AnybanQID app.
๐ธ App approval & transactions
- Confirm logins and payments with signed display data (amount, merchant).
- Create an order server-side; show it as a QR code or a same-device app link; poll its status.
- What the user sees is what gets signed.
โ๏ธ e-Signatures
- Sign documents with the citizen's device key (PAdES).
- Signed under a per-citizen certificate issued at their first signature.
- Multi-signer ordering, hash-reviewed on the phone.
๐ Login with AnybanQID โ coming soon
- Web & mobile sign-in by browser redirect โ coming soon.
- Standard OIDC Authorization Code + PKCE. No authorization code is issued yet โ use CIBA or App approval today.
- Assurance levels
loa1โloa3viaacr_values.
How a request reaches the citizen
AnybanQID does not send push notifications. A request reaches the AnybanQID app in one of three ways:
the citizen scans a QR code you display; they tap an app link on the same phone
(https://id.anybanq.lk/app/order/<id> or anybanqid://order/<id>, with an
optional ?return=https://โฆ to come back to your site); or it appears when they open the app.
Tell the citizen to open AnybanQID when you start a CIBA request.
How a browser login will flow โ coming soon
Signing certificates
Document signatures are made under an X.509 certificate issued to the citizen personally, not a service-held key. That certificate is issued the first time the citizen signs a document (or when they join a company that requires it): the app builds a PKCS#10 CSR from the device's secure-element key, so the private key never leaves the phone. As a relying party you normally never touch these endpoints — the app enrols the certificate when it is first needed — but the states are visible on the signing request, and it is worth knowing the failure modes.
Issuance against the live CA is two-phase. The first call is accepted but does not return a certificate: the CA emails the citizen a PIN, which the second call redeems.
# Phase 1 โ submit the CSR. Returns {id, status: "PENDING_PIN"}.
POST /certificate/certificates/requests
{ "type": "SIGNING", "csrPem": "-----BEGIN CERTIFICATE REQUEST-----..." }
# Phase 2 โ redeem the emailed PIN. Returns the issued certificate.
POST /certificate/certificates/requests/:id/verify-pin
{ "pin": "..." }
- The certificate subject is resolved from the citizen's verified identity — it is never read from the request body.
- The email in the CSR must match the citizen's verified address, because that is where the PIN is delivered. A mismatch is rejected.
- A wrong PIN returns
400and leaves the request redeemable, so it can simply be retried. - A signing request from a citizen with no active certificate comes back
FAILED, notDECLINED— the latter means the citizen actually refused. Do not treat the two the same.
Certificates expire. AnybanQID reminds the citizen ahead of time and marks lapsed
certificates EXPIRED, so a signing request can fail for a citizen who signed
successfully last year. Handle FAILED as a retryable, explainable state rather
than a dead end.
# Renewal โ single-phase, no PIN. The replaced certificate becomes SUPERSEDED.
POST /certificate/certificates/:serial/renew
{ "csrPem": "-----BEGIN CERTIFICATE REQUEST-----..." }
A renewed certificate gets a new serial, so anything you have stored against the old one keeps referring to the certificate that actually made those signatures. A revoked certificate cannot be renewed — revocation is a trust decision, not an expiry.
Set up in four steps
Get sandbox credentials
The developer portal is not self-serve yet. Email hello@anybanq.lk for sandbox credentials โ you'll get a client id/secret with the CIBA grant enabled if you need decoupled auth.
Discover the endpoints
curl https://id.anybanq.lk/oidc/.well-known/openid-configuration
Start a request โ CIBA or App approval
# CIBA (poll mode) โ issuer https://id.anybanq.lk/oidc
curl -X POST https://id.anybanq.lk/oidc/oauth2/bc-authorize \
-u "$ANYBANQID_CLIENT_ID:$ANYBANQID_CLIENT_SECRET" \
-d 'login_hint=nic:<12-digit NIC>' \
-d 'scope=openid profile'
# โ { "auth_req_id": "...", "expires_in": 300, "interval": 5 }
curl -X POST https://id.anybanq.lk/oidc/oauth2/token \
-u "$ANYBANQID_CLIENT_ID:$ANYBANQID_CLIENT_SECRET" \
-d 'grant_type=urn:openid:params:grant-type:ciba' \
-d "auth_req_id=$AUTH_REQ_ID"
# pending โ { "error": "authorization_pending" }; approved โ tokens
# App approval โ create an order, show it as a QR code or app link, poll its status
curl -X POST https://id.anybanq.lk/api/v1/auth/auth/orders \
-H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" \
-d '{ "type": "TRANSACTION", "userRef": { "nic": "<12-digit NIC>" },
"displayData": { "title": "Confirm payment", "amount": 24500, "currency": "LKR" } }'
# โ { "orderId": "...", "expiresAt": "..." }
# QR / link: https://id.anybanq.lk/app/order/<orderId>?return=https://app.example.lk/done
curl https://id.anybanq.lk/api/v1/auth/auth/orders/$ORDER_ID/status \
-H "Authorization: Bearer $ACCESS_TOKEN"
Handle tokens & refresh
Tokens are ES256-signed; refresh tokens rotate on every use with reuse detection โ always store the newest one. Full flow diagrams (app-approval orders, CIBA, error codes) live in the documentation.