Authentication Flow
RiskSage uses a two-step authentication flow: credential exchange followed by an MFA challenge. Every subsequent request uses the resulting Bearer JWT.
Step 1 — Login with credentials
Submit your email and password to the login endpoint. On success, the API returns an MFA challenge token.
// Step 1: Exchange credentials for MFA challenge POST /auth/login Content-Type: application/json { "email": "analyst@acme-bank.in", "password": "********" } // Response 200 { "mfaChallengeToken": "eyJhbGciOi...", "mfaMethod": "TOTP", "expiresIn": 300 }
Step 2 — Complete MFA challenge
Submit the TOTP code from your authenticator app along with the challenge token. The response contains your Bearer JWT and a refresh token.
// Step 2: Complete MFA challenge POST /auth/mfa/challenge Content-Type: application/json { "mfaChallengeToken": "eyJhbGciOi...", "totpCode": "482901" } // Response 200 { "accessToken": "eyJhbGciOiJSUzI1NiIs...", "refreshToken": "dGhpcyBpcyBhIHJlZnJl...", "expiresIn": 3600, "tokenType": "Bearer" }
Using the token
Include the access token as a Bearer token in the Authorization header of every subsequent request:
GET /incidents
Authorization: Bearer eyJhbGciOiJSUzI1NiIs...
X-Tenant-Id: acme-bank
POST /auth/refresh endpoint with your refresh token to obtain a new access token without re-authenticating. Refresh tokens expire after 7 days of inactivity.
Tenant-Scoped Endpoints
RiskSage is a multi-tenant platform. Every API request must include the X-Tenant-Id header. The JWT encodes the user's tenant membership, and requests to a tenant the user does not belong to will return 403 Forbidden.
// All data endpoints require tenant scoping GET /incidents Authorization: Bearer <token> X-Tenant-Id: acme-bank // Omitting X-Tenant-Id returns: // 400 { "error": "MISSING_TENANT", "message": "X-Tenant-Id header is required" }
Key Route Groups
The RiskSage API is organised into five primary route groups. All routes are prefixed with /api/v1 in production.
| Route Group | Base Path | Description |
|---|---|---|
| Incidents | /incidents | CERT-In incident lifecycle, multi-regulator deadline tracking, AI-drafted 9-field reports |
| VAPT | /vapt | Vulnerability assessments, report ingestion (Nessus, Burp, OpenVAS, Qualys), finding management |
| CRQ | /crq | Cyber Risk Quantification — FAIR v3.0, FAIR-MAM, NIST 800-30/ALE, Probabilistic VaR analyses |
| Threat Models | /threat-models | STRIDE + PASTA threat modelling, DFD components, regulatory mapping (RBI TRA, SEBI CSCRF, IRDAI) |
| Dashboard | /dashboard | Aggregated risk posture, compliance status, widget data for executive and operational views |
Rate Limits
RiskSage enforces per-tenant rate limits to ensure fair usage across the platform. Limits are applied using a sliding window algorithm.
| Tier | Limit | Window | Applies To |
|---|---|---|---|
| Standard | 120 requests | 1 minute | All authenticated endpoints |
| Auth | 10 requests | 1 minute | /auth/* endpoints |
| AI-Assisted | 20 requests | 1 minute | AI report drafting, /crq/use-cases/:id/suggest-inputs |
| Bulk Upload | 5 requests | 1 minute | VAPT report parsing, bulk import |
Rate limit status is returned in response headers:
X-RateLimit-Limit: 120 X-RateLimit-Remaining: 87 X-RateLimit-Reset: 1712467200
429 status with a Retry-After header (in seconds). Implement exponential backoff in your integration. Do not retry immediately.
Error Handling Patterns
All RiskSage API errors follow a consistent JSON envelope. Every error response includes a machine-readable error code and a human-readable message.
// Standard error envelope { "error": "VALIDATION_ERROR", "message": "Field 'severity' must be one of: CRITICAL, HIGH, MEDIUM, LOW, INFO", "field": "severity", "status": 422 }
| Status | Error Code | Meaning |
|---|---|---|
400 | MISSING_TENANT | X-Tenant-Id header not provided |
401 | TOKEN_EXPIRED | Access token has expired — refresh or re-authenticate |
403 | FORBIDDEN | User does not have access to the requested tenant or resource |
404 | NOT_FOUND | Resource does not exist within the tenant scope |
422 | VALIDATION_ERROR | Request body failed schema validation |
429 | RATE_LIMITED | Too many requests — check Retry-After header |
500 | INTERNAL_ERROR | Unexpected server error — include the X-Request-Id when contacting support |
X-Request-Id response header. When contacting CreativeCyber support, include this ID for fast issue resolution. Every request generates a unique trace ID that maps to our internal observability stack.
Next Steps
With authentication working and an understanding of the route structure, explore the detailed guides for each module: