IDaaS — Integration Guide
Audience: Engineers integrating a client application with the IDaaS platform.
Base URL:https://<your-idaas-host>/api(all paths below omit this prefix)
Interactive docs:GET /swagger-ui.html· Machine-readable spec:GET /v3/api-docs
Table of Contents
- What IDaaS Is
- Core Concepts
- How the Platform Works End to End
- Quick-Start Checklist
- Step 1 — Register Your Application ← includes
appHandle - Step 2 — Authenticate (Get a Token)
- Step 3 — Create Subjects and Tags
- Step 4 — Initiate a Payment
- Step 5 — Receive and Handle Webhooks
- Step 6 — Accept or Reject a Transaction
- Step 7 — Monitor Webhooks and Delivery
- Step 8 — Wallet and Ledger
- Step 9 — Settlement
- Payload Encryption (JWE)
- Webhook Signature Verification
- Idempotency
- Rate Limiting
- Cross-App Tag Claims and Consent
- Namespaced Tags — Onboarding Existing Tag Systems ← new
- Tag Federation
- Error Handling
- API Reference Summary
- Integration Flows — Sequence Diagrams
1. What IDaaS Is
IDaaS (Identity as a Service) is a multi-tenant platform that provides:
Your application communicates with IDaaS exclusively via HTTPS REST APIs. All side-effects (webhook dispatch, audit logging) happen asynchronously via Kafka so API calls remain fast.
2. Core Concepts
Application
The top-level entity in IDaaS — it represents your service. Each application gets:- A
clientIdandclientSecretfor authentication - A
webhookSecretfor verifying inbound webhook signatures - An EC P-256 keypair for payload encryption
- One escrow wallet for net monetary position tracking
Subject
A user identity within your application. A subject maps your internal user ID (externalId) to the IDaaS system. One subject can own many tags.
Tag
A portable identity handle (e.g.alice, shop-main) scoped to the creating application. Each application has a short, unique appHandle slug (e.g. walletapp). The tag’s globally unique identifier is the qualified address: localTag@appHandle (e.g. alice@walletapp).
This means two different applications can each have a user named alice without any conflict — they become alice@walletapp and alice@shopapp, clearly distinct identities.
Tag rules:
localTagpart: 3–64 characters, lowercase alphanumeric + hyphens, not starting or ending with a hyphenappHandlepart: 3–30 characters, lowercase alphanumeric + hyphens, not starting or ending with a hyphen; set at registration time and immutable- Tags can be resolved publicly using either the bare local name (
alice) or the qualified address (alice@walletapp) - A bare name lookup that matches tags in more than one application returns 409 Conflict — use the qualified address in that case
- Can receive payments from any other tag on any application
Transaction
A cross-application payment from one tag to another. Transactions go through a two-step lifecycle — the sending application initiates, the receiving application explicitly accepts or rejects.Wallet
IDaaS maintains oneApplicationWallet per application. It tracks the cumulative credits and debits from all completed transactions. This is an escrow/settlement wallet, not an end-user wallet — per-user balances remain your application’s responsibility.
Webhook
An outbound HTTP POST from IDaaS to your application notifying you of transaction events. There are two distinct notifications per transaction:- RECEIVER webhook — sent to the receiving app’s
transactionWebhookUrlwhen a transaction is addressed to one of its tags - SENDER callback — sent to the
callbackUrlprovided by the sending app when the transaction outcome is determined
3. How the Platform Works End to End
4. Quick-Start Checklist
- Register your application (
POST /v1/applications) — saveclientSecret,webhookSecret, and key material; they are shown only once - Authenticate (
POST /v1/auth/token) — obtain a Bearer JWT - Provision wallet (
POST /v1/wallet) — idempotent, safe to call on every startup - Create subjects for your users (
POST /v1/subjects) - Create tags for your users (
POST /v1/tags) - Expose a webhook endpoint at your
transactionWebhookUrlto receiveTRANSACTION_INITIATEDevents - Verify webhook signatures using
X-IDaaS-Signatureon every inbound webhook - Respond with 2xx within 10 seconds on webhook delivery; IDaaS retries 3 times
- Set up a callback endpoint for
TRANSACTION_COMPLETED/TRANSACTION_REJECTED/TRANSACTION_EXPIREDnotifications
5. Step 1 - Register Your Application
Registration is public (no auth required). Each application registration creates an independent tenant.Request
Response
⚠️ Store immediately and securely:Lose any of these and you must rotate (use key/webhook secret rotation endpoints, or deactivate + re-register).
clientSecret— used to obtain Bearer tokens; never shown againwebhookSecret— used to verifyX-IDaaS-Signatureon every inbound webhook; never shown againappPrivateJwk— your application’s private EC key (containsd); required to decrypt JWE-encrypted webhook payloads; never shown againappHandle— returned in the response and inGET /v1/applications/{id}; it is the namespace for all your tags (e.g.alice@walletapp). Immutable.
6. Step 2 - Authenticate (Get a Token)
All protected endpoints require a Bearer JWT. Tokens expire after 1 hour (configurable viaIDAAS_APP_TOKEN_TTL).
Request (form-encoded)
Request (JSON body)
Response
Using the token
Add the JWT to every subsequent request:Rate limit: 10 requests / minute per IP. Implement token caching — refresh proactively before expiry rather than waiting for a 401.
Token refresh pattern
7. Step 3 - Create Subjects and Tags
7.1 Create a Subject
A subject represents one of your users inside IDaaS. Create a subject for every user who needs a tag.id (IDaaS subject UUID) — you need it to create a tag.
7.2 Create a Tag
IDaaS automatically derives the qualified address by appending your application’s
appHandle: alice → alice@walletapp.
ThequalifiedAddress(alice@walletapp) is the canonical cross-platform identifier for this tag. Share it with other applications so they can address payments to it unambiguously.
7.3 Resolve Any Tag (Public, Cached)
Any application can look up any tag — no auth required. Results are cached for 30 seconds. You can resolve by bare local name or by qualified address:
If alice exists on more than one application, the bare-string lookup returns 409 Conflict with the list of qualified addresses. Use the qualified address to avoid ambiguity.
ACTIVE.
8. Step 4 - Initiate a Payment
The sending application calls this endpoint to begin a cross-application payment.Tag addressing: BothsenderTagandreceiverTagaccept either a bare local name (alice) or a qualified address (alice@walletapp).
Use the qualified address whenever possible — bare names that exist on more than one application return a 409 Conflict asking you to specify the qualified address.
Response
Transaction responses always return qualified addresses insenderTagandreceiverTag(e.g.alice@walletapp,bob@shopapp).
What happens next
- IDaaS persists the transaction in
AWAITING_ACCEPTANCEstate - IDaaS persists a
TransactionWebhookrecord (direction=RECEIVER, status=PENDING) - IDaaS publishes a
WebhookDispatchEventto theidaas.webhooksKafka topic - The
WebhookDispatchConsumerPOSTs aTRANSACTION_INITIATEDnotification to the receiver app’stransactionWebhookUrl(asynchronously) - The transaction auto-expires after 24 hours if not accepted
9. Step 5 - Receive and Handle Webhooks
IDaaS POSTs notifications to yourtransactionWebhookUrl. You must:
- Expose a publicly reachable HTTPS endpoint
- Verify the
X-IDaaS-Signatureheader (see §15) - Return
2xxwithin 10 seconds; IDaaS retries up to 3 times (after 1 s and 2 s back-off)
9.1 RECEIVER Webhook — TRANSACTION_INITIATED
Sent to the receiving application when a new payment is addressed to one of its tags.
- Verify the signature (see §15)
- Parse the
reference— this is the key you’ll use to accept or reject - Apply your own business logic (check funds, validate the order, etc.)
- Call
POST /v1/transactions/{reference}/acceptor.../rejectwithin 24 hours - Return
200 OKimmediately — do your business logic asynchronously if needed
9.2 SENDER Callback — Outcome Notification
Sent to the sending application’s transaction-specificcallbackUrl when provided; otherwise IDaaS falls back to the sending application’s registered transactionWebhookUrl after the transaction outcome is determined.
9.3 Webhook Endpoint Implementation Checklist
10. Step 6 - Accept or Reject a Transaction
Only the receiving application can accept or reject. IDaaS enforces this — calling accept/reject with the wrong token returns403.
Accept
- Sender’s wallet is debited by
amount - Receiver’s wallet is credited by
amount - Two immutable
LedgerEntryrows are written - Transaction status moves to
COMPLETED - Sender’s
callbackUrlreceivesTRANSACTION_COMPLETED(or the sender app’stransactionWebhookUrlif no transaction-specific callback was supplied)
Reject
reason field is optional (max 500 chars). On success:
- No ledger movement
- Transaction status moves to
REJECTED - Sender’s
callbackUrlreceivesTRANSACTION_REJECTED(or the sender app’stransactionWebhookUrlif no transaction-specific callback was supplied)
Error responses for accept/reject
11. Step 7 - Monitor Webhooks and Delivery
Check delivery status for a transaction
RECEIVER and one SENDER:
Webhook delivery statuses
Find all failed webhooks for your app
12. Step 8 - Wallet and Ledger
Provision wallet (call on startup)
Get current balance
balance = totalCredited − totalDebited. A positive balance means you have net received more than you sent. A negative balance means you have net sent more than you received.
Get ledger statement (paginated)
13. Step 9 - Settlement
IDaaS automatically runs an end-of-day settlement job at 23:59 UTC every day. It aggregates all completed transactions for the day and produces per-application net positions.Get today’s settlement (after 23:59 UTC)
Manual trigger (operational use)
14. Payload Encryption (JWE)
WhenencryptionEnabled=true for your application, all request bodies must be JWE-encrypted and all webhook payloads you receive will be JWE-encrypted. This provides end-to-end payload confidentiality on top of TLS.
Algorithm
14.1 Encrypting Requests Sent TO IDaaS
14.2 Decrypting Webhooks Received FROM IDaaS
WhenContent-Encryption: JWE is present on an inbound webhook, the body is a JWE compact string encrypted with your application’s EC public key. Decrypt it with your private key (appPrivateJwk) received once at registration/rotation.
14.3 Key Rotation
Rotate your keypair periodically or after a key compromise:appPublicKeyJwk and appPrivateJwk — store the private JWK immediately, it is shown only once.
After rotation:
- IDaaS encrypts all subsequent webhooks with the new public key
- Requests encrypted with the old public key will be rejected
- Allow a brief overlap window for in-flight messages before destroying the old private key
14.4 Webhook Secret Rotation
If your application loses its webhook secret (or suspects compromise), rotate it without re-registering:webhookSecret — store it immediately, it is shown only once.
After rotation:
- IDaaS signs all subsequent webhooks with the new secret
- Verification with the old secret fails immediately
15. Webhook Signature Verification
Every outbound webhook POST from IDaaS includes two headers:Signature algorithm
webhookSecret is the raw (unhashed) secret returned at registration.
It can also be rotated via POST /v1/applications/webhook-secret/rotate if lost or compromised.
Verification (pseudo-code)
Implementation examples
Java:16. Idempotency
POST /v1/transactions supports the Idempotency-Key request header. Supplying the same key within 24 hours returns the original response without creating a duplicate transaction.
- Use UUID v4 as idempotency keys
- Generate the key before the first attempt and store it alongside your order/payment record
- Re-use the same key on all retries of the same logical payment
- Do not re-use keys across different payments
17. Rate Limiting
When the limit is exceeded, IDaaS returns:
Handling 429 in your integration:Retry-After— number of seconds until the bucket refills. Read this value and wait at least that long before retrying.
X-RateLimit-Remaining— tokens remaining in the current window;0when you are throttled.
18. Cross-App Tag Claims and Consent
If your application needs to associate one of your users with a tag they own on another application (e.g.bob on ShopApp), you can request a claim through the consent flow.
18.1 Request a Claim
18.2 Consent Approval Flow
18.3 After Approval
On approval, IDaaS returns an attestation JWT:19. Namespaced Tags — Onboarding Existing Tag Systems
The problem
Many applications that integrate IDaaS already run their own tag / username system. When they onboard their users onto IDaaS, tag collisions are inevitable: WalletApp may already have a useralice, and so does ShopApp — completely different people.
A single global UNIQUE(tag_string) constraint would block one application from onboarding. IDaaS solves this with qualified addressing.
How it works
Every application registers with a short, uniqueappHandle slug (e.g. walletapp). Every tag automatically derives a qualified address localTag@appHandle:
These are different identities sharing a local name — IDaaS tracks them separately with no constraint conflict.
What stays the same for the host app
Your application continues to use its own tag system internally. IDaaS only requires that you onboard the tags you want to be discoverable cross-platform:- Register on IDaaS with your
appHandle - Create a Subject for each user:
POST /v1/subjects - Create a Tag for each user you want discoverable:
POST /v1/tagswith{"tag": "alice", "subjectId": "..."} - IDaaS records
alice@walletappas the globally unique qualified address - Other applications discover your users via
GET /v1/tags/alice@walletapp - Payments are routed to
alice@walletapp— your internal tag system is unaffected
Address resolution behaviour
Example: sending a payment to a user on another app
alice is unique on the platform and bob is unique on the platform. If either is ambiguous, IDaaS returns 409 and lists the qualified addresses to use.
appHandle rules
20. Tag Federation
Federation links a tag to an identity on an external identity provider (e.g. “alice on WalletApp is the same person as alice@github.com”). This is for advanced cross-platform identity scenarios.21. Error Handling
All IDaaS responses use a consistentApiResponse<T> envelope:
errorCode is the stable machine-readable identifier (for example IDAAS-AUTH-1002).
Client applications should branch handling logic by errorCode, not by free-text message.
Complete error code catalog
All IDaaS errors are returned with a stable error code in theerrorCode field. Client applications should parse and branch on this code rather than free-text messages, enabling reliable structured error handling.
Authentication & Authorization (1000–1999)
Validation Errors (2000–2999)
Resource Not Found (3000–3999)
Resource Conflicts (4000–4999)
Invalid State / Business Logic (5000–5999)
Rate Limiting (6000–6999)
System / Internal Errors (9000–9999)
Error Code Categories
Total: 41 documented error codes – all error responses include
errorCode and message.
HTTP status codes
Validation error example
22. API Reference Summary
Base path for all endpoints:/api/v1
All protected endpoints require:Authorization: Bearer <token>