Skip to main content

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

  1. What IDaaS Is
  2. Core Concepts
  3. How the Platform Works End to End
  4. Quick-Start Checklist
  5. Step 1 — Register Your Application ← includes appHandle
  6. Step 2 — Authenticate (Get a Token)
  7. Step 3 — Create Subjects and Tags
  8. Step 4 — Initiate a Payment
  9. Step 5 — Receive and Handle Webhooks
  10. Step 6 — Accept or Reject a Transaction
  11. Step 7 — Monitor Webhooks and Delivery
  12. Step 8 — Wallet and Ledger
  13. Step 9 — Settlement
  14. Payload Encryption (JWE)
  15. Webhook Signature Verification
  16. Idempotency
  17. Rate Limiting
  18. Cross-App Tag Claims and Consent
  19. Namespaced Tags — Onboarding Existing Tag Systemsnew
  20. Tag Federation
  21. Error Handling
  22. API Reference Summary
  23. 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 clientId and clientSecret for authentication
  • A webhookSecret for 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:
  • localTag part: 3–64 characters, lowercase alphanumeric + hyphens, not starting or ending with a hyphen
  • appHandle part: 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 one ApplicationWallet 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 transactionWebhookUrl when a transaction is addressed to one of its tags
  • SENDER callback — sent to the callbackUrl provided 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) — save clientSecret, 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 transactionWebhookUrl to receive TRANSACTION_INITIATED events
  • Verify webhook signatures using X-IDaaS-Signature on 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_EXPIRED notifications

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:
  • clientSecret — used to obtain Bearer tokens; never shown again
  • webhookSecret — used to verify X-IDaaS-Signature on every inbound webhook; never shown again
  • appPrivateJwk — your application’s private EC key (contains d); required to decrypt JWE-encrypted webhook payloads; never shown again
  • appHandle — returned in the response and in GET /v1/applications/{id}; it is the namespace for all your tags (e.g. alice@walletapp). Immutable.
Lose any of these and you must rotate (use key/webhook secret rotation endpoints, or deactivate + re-register).

6. Step 2 - Authenticate (Get a Token)

All protected endpoints require a Bearer JWT. Tokens expire after 1 hour (configurable via IDAAS_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.
Save the returned 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: alicealice@walletapp.
The qualifiedAddress (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.
Use this before initiating a payment to confirm the destination tag exists and is ACTIVE.

8. Step 4 - Initiate a Payment

The sending application calls this endpoint to begin a cross-application payment.
Tag addressing: Both senderTag and receiverTag accept 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 in senderTag and receiverTag (e.g. alice@walletapp, bob@shopapp).

What happens next

  1. IDaaS persists the transaction in AWAITING_ACCEPTANCE state
  2. IDaaS persists a TransactionWebhook record (direction=RECEIVER, status=PENDING)
  3. IDaaS publishes a WebhookDispatchEvent to the idaas.webhooks Kafka topic
  4. The WebhookDispatchConsumer POSTs a TRANSACTION_INITIATED notification to the receiver app’s transactionWebhookUrl (asynchronously)
  5. The transaction auto-expires after 24 hours if not accepted

9. Step 5 - Receive and Handle Webhooks

IDaaS POSTs notifications to your transactionWebhookUrl. You must:
  1. Expose a publicly reachable HTTPS endpoint
  2. Verify the X-IDaaS-Signature header (see §15)
  3. Return 2xx within 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.
What to do when you receive this:
  1. Verify the signature (see §15)
  2. Parse the reference — this is the key you’ll use to accept or reject
  3. Apply your own business logic (check funds, validate the order, etc.)
  4. Call POST /v1/transactions/{reference}/accept or .../reject within 24 hours
  5. Return 200 OK immediately — do your business logic asynchronously if needed

9.2 SENDER Callback — Outcome Notification

Sent to the sending application’s transaction-specific callbackUrl 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 returns 403.

Accept

No request body required. On success:
  • Sender’s wallet is debited by amount
  • Receiver’s wallet is credited by amount
  • Two immutable LedgerEntry rows are written
  • Transaction status moves to COMPLETED
  • Sender’s callbackUrl receives TRANSACTION_COMPLETED (or the sender app’s transactionWebhookUrl if no transaction-specific callback was supplied)

Reject

The reason field is optional (max 500 chars). On success:
  • No ledger movement
  • Transaction status moves to REJECTED
  • Sender’s callbackUrl receives TRANSACTION_REJECTED (or the sender app’s transactionWebhookUrl if no transaction-specific callback was supplied)

Error responses for accept/reject


11. Step 7 - Monitor Webhooks and Delivery

Check delivery status for a transaction

Returns up to two records — one RECEIVER and one SENDER:

Webhook delivery statuses

Find all failed webhooks for your app

Use this for operational monitoring — set up an alert if this list is non-empty.

12. Step 8 - Wallet and Ledger

Provision wallet (call on startup)

Idempotent — safe to call on every application start.

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)

Idempotent — if the date is already settled, returns the existing record.

14. Payload Encryption (JWE)

When encryptionEnabled=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

Fetch the IDaaS public key (no auth required):
Example (Java with Nimbus JOSE+JWT):
Example (Node.js with jose library):
Example (Python with joserfc):

14.2 Decrypting Webhooks Received FROM IDaaS

When Content-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:
Returns a new appPublicKeyJwk and appPrivateJwkstore 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:
Returns a new webhookSecretstore 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

Where 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:
Node.js:
Python:

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.
Best practices:
  • 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:
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; 0 when you are throttled.
Handling 429 in your integration:

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

IDaaS sends a time-limited consent notification to the tag owner. The consent token URL is:
This is the URL you can present to the tag owner (e.g. via email or in-app notification) so they can approve or deny the claim.

18.3 After Approval

On approval, IDaaS returns an attestation JWT:
Store this token — it proves your application has an approved link to that tag. You can verify it with the IDaaS public key.

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 user alice, 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, unique appHandle 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:
  1. Register on IDaaS with your appHandle
  2. Create a Subject for each user: POST /v1/subjects
  3. Create a Tag for each user you want discoverable: POST /v1/tags with {"tag": "alice", "subjectId": "..."}
  4. IDaaS records alice@walletapp as the globally unique qualified address
  5. Other applications discover your users via GET /v1/tags/alice@walletapp
  6. Payments are routed to alice@walletapp — your internal tag system is unaffected
Tags that are not onboarded are simply not discoverable via IDaaS. This is intentional — you control which users participate in the cross-platform network.

Address resolution behaviour

Example: sending a payment to a user on another app

The second form works only when 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.
IDaaS issues a challenge; your application must verify ownership on the external provider, then call:

21. Error Handling

All IDaaS responses use a consistent ApiResponse<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 the errorCode 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>

Applications & Authentication

Encryption Key Management

Subjects

Tags

Transactions

Wallet & Ledger

Settlement

Webhooks

Claims

Federation

Actuator


23. Integration Flows — Sequence Diagrams

Flow A: Two-App Payment (Happy Path)

Flow B: Transaction Rejected

Flow C: Transaction Expired

Flow D: Encrypted Payment