Integration Flow
This page walks through a complete integration scenario using real route names, curl commands, and example responses. The flow covers: authenticate, fetch tenant, import data, calculate BHI, read fraud signals, get recommendations, subscribe to alerts, and verify the audit trail.
All routes verified at commit 4b572c2.
Step 1: Authenticate
Option A: API Key (Machine-to-Machine)
API keys are provisioned during tenant creation. Use the key as a Bearer token.
curl -X GET https://api.example.com/api/v1/tenants/me \
-H "Authorization: Bearer ely_sk_a1b2c3d4e5f6...64hex..."
Response:
{
"tenantId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"name": "Acme Bank Ghana",
"type": "bank",
"plan": "enterprise",
"status": "active"
}
The X-API-Key-Expires-In response header indicates remaining key lifetime (e.g., X-API-Key-Expires-In: 2592000 for 30 days). Use this to trigger key rotation before expiry.
Option B: User Signin (JWT)
curl -X POST https://api.example.com/api/public/signin \
-H "Content-Type: application/json" \
-d '{
"email": "admin@acmebank.com",
"password": "securepassword"
}'
Response (no MFA):
{
"token": "eyJhbGciOiJIUzI1NiIs...",
"refreshToken": "eyJhbGciOiJIUzI1NiIs...",
"expiresIn": 3600,
"tenant": {
"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"name": "Acme Bank Ghana"
},
"user": {
"id": "user-uuid",
"email": "admin@acmebank.com",
"role": "admin"
}
}
Response (MFA enabled):
{
"mfaRequired": true,
"mfaToken": "temporary-mfa-token",
"message": "MFA verification required"
}
Complete MFA:
curl -X POST https://api.example.com/api/public/mfa/verify \
-H "Content-Type: application/json" \
-d '{
"mfaToken": "temporary-mfa-token",
"code": "123456"
}'
Token Refresh
curl -X POST https://api.example.com/api/public/refresh \
-H "Content-Type: application/json" \
-d '{
"refreshToken": "eyJhbGciOiJIUzI1NiIs..."
}'
Step 2: Import Financial Data
CSV Upload (Bank Statement Import)
Upload a CSV file with a bank preset for automatic column detection:
curl -X POST https://api.example.com/api/data/v1/import/upload \
-H "Authorization: Bearer ely_sk_..." \
-F "file=@statement_jan2026.csv" \
-F "bankPreset=gcb" \
-F "delimiter=,"
Supported bank presets: gcb, ecobank, stanbic, arb_apex, custom.
Response:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"fileName": "statement_jan2026.csv",
"fileSize": 245780,
"totalRows": 5230,
"detectedColumns": [
"Transaction Date",
"Description",
"Debit",
"Credit",
"Balance"
],
"bankPreset": "gcb",
"suggestedMapping": {
"transactionDate": "Transaction Date",
"description": "Description",
"debit": "Debit",
"credit": "Credit",
"balance": "Balance"
},
"status": "uploaded"
}
Start processing:
curl -X POST https://api.example.com/api/data/v1/import/550e8400-e29b-41d4-a716-446655440000/start \
-H "Authorization: Bearer ely_sk_..." \
-H "Content-Type: application/json" \
-d '{
"bankPreset": "gcb",
"currency": "GHS"
}'
Response (202 Accepted):
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "processing",
"message": "Import started"
}
Poll until complete:
curl -X GET https://api.example.com/api/data/v1/import/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer ely_sk_..."
Response (completed):
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"processedRows": 5230,
"errorCount": 0,
"completedAt": "2026-02-19T10:35:22Z"
}
Connector Sync (Core Banking System)
curl -X POST https://api.example.com/api/data/v1/sync/core-banking \
-H "Authorization: Bearer ely_sk_..."
Response (202 Accepted):
{
"syncId": "sync-uuid",
"status": "running",
"message": "Sync started"
}
Step 3: Read Customer Data
curl -X GET "https://api.example.com/api/data/v1/customers?limit=20&offset=0" \
-H "Authorization: Bearer ely_sk_..."
Response:
{
"data": [
{
"id": "cust-001-uuid",
"externalId": "GCB-SME-4521",
"name": "Kwame Enterprises Ltd",
"type": "business",
"industry": "retail",
"status": "active",
"createdAt": "2026-01-15T08:00:00Z"
},
{
"id": "cust-002-uuid",
"externalId": "GCB-SME-4522",
"name": "Adwoa Agro Services",
"type": "business",
"industry": "agriculture",
"status": "active",
"createdAt": "2026-01-15T08:00:00Z"
}
],
"total": 1250,
"hasMore": true
}
Step 4: Calculate Business Health Index
curl -X POST https://api.example.com/api/v1/bhi/calculate \
-H "Authorization: Bearer ely_sk_..." \
-H "Content-Type: application/json" \
-d '{ "customerId": "cust-001-uuid" }'
Response:
{
"customerId": "cust-001-uuid",
"overall": 72,
"band": "good",
"components": {
"liquidity": { "score": 68 },
"volatility": { "score": 75 },
"revenueStability": { "score": 80 },
"expenseRatio": { "score": 65 },
"paymentBehavior": { "score": 70 }
},
"trend": "stable",
"seasonalAdjustment": {
"industry": "retail",
"applied": true
},
"scoringMethod": "heuristic",
"calculatedAt": "2026-02-19T10:40:00Z"
}
Scoring method will be "heuristic" by default. If the ML Service is configured, it will return "ml" as the scoring method.
Step 5: Check Fraud Signals
curl -X GET "https://api.example.com/api/v1/risk/fraud-signals?customerId=cust-001-uuid" \
-H "Authorization: Bearer ely_sk_..."
Response (example with triggered signals):
{
"customerId": "cust-001-uuid",
"overallScore": 35,
"severity": "medium",
"signals": [
{
"id": "rapid-in-out",
"category": "pattern",
"severity": "medium",
"triggered": true,
"confidence": 0.72,
"evidence": {
"threshold": "Inflow/outflow ratio 0.80-1.20",
"observed": "Ratio: 0.95",
"inflowTotal": 45200,
"outflowTotal": 43100
},
"contributingFactors": ["High volume pass-through pattern"],
"mitigatingFactors": ["Established business with 6-month history"]
}
],
"window": "30d",
"calculatedAt": "2026-02-19T10:40:05Z"
}
Step 6: Get Recommendations (GraphQL)
curl -X POST https://api.example.com/graphql \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"query": "query GetRecommendations($customerId: ID!) { recommendations(customerId: $customerId, pagination: { first: 5 }) { edges { node { id type priority confidence description requiresApproval expiresAt } } totalCount } }",
"variables": { "customerId": "cust-001-uuid" }
}'
Response:
{
"data": {
"recommendations": {
"edges": [
{
"node": {
"id": "rec-001-uuid",
"type": "credit_increase_strong_bhi",
"priority": "medium",
"confidence": 0.82,
"description": "Credit limit increase recommended based on strong BHI (72, good band) and stable trend",
"requiresApproval": true,
"expiresAt": "2026-02-26T10:40:00Z"
}
}
],
"totalCount": 3
}
}
}
Step 7: Approve a Recommendation (GraphQL Mutation)
curl -X POST https://api.example.com/graphql \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"query": "mutation ApproveRecommendation($id: ID!, $input: ReviewRecommendationInput!) { reviewRecommendation(id: $id, input: $input) { id status reviewedAt reviewedBy } }",
"variables": {
"id": "rec-001-uuid",
"input": {
"approved": true,
"notes": "Approved after portfolio review โ customer BHI stable for 3 months"
}
}
}'
Response:
{
"data": {
"reviewRecommendation": {
"id": "rec-001-uuid",
"status": "approved",
"reviewedAt": "2026-02-19T11:15:00Z",
"reviewedBy": "user-uuid"
}
}
}
Step 8: Subscribe to Real-Time Alerts (GraphQL Subscription)
Connect to the GraphQL WebSocket endpoint and subscribe:
subscription {
recommendationCreated {
id
type
priority
confidence
description
customerId
createdAt
}
}
Or subscribe to specific task updates:
subscription {
taskUpdated(taskId: "task-uuid") {
id
status
currentStepIndex
totalSteps
result
error
}
}
Subscriptions require the same JWT authentication as queries and mutations, provided during WebSocket connection initialization. All events are tenant-isolated.
Step 9: Verify Audit Trail
curl -X GET "https://api.example.com/api/v1/audit/customers/cust-001-uuid?limit=10" \
-H "Authorization: Bearer ely_sk_..."
Response:
{
"data": [
{
"id": "audit-003-uuid",
"action": "recommendation.reviewed",
"description": "Credit limit increase recommendation approved",
"actorType": "user",
"actorId": "user-uuid",
"entityType": "recommendation",
"entityId": "rec-001-uuid",
"regulatoryRelevance": "high",
"createdAt": "2026-02-19T11:15:00Z"
},
{
"id": "audit-002-uuid",
"action": "fraud.signals_calculated",
"description": "Fraud signals evaluated for customer",
"actorType": "system",
"actorId": "insights-service",
"entityType": "customer",
"entityId": "cust-001-uuid",
"regulatoryRelevance": "medium",
"createdAt": "2026-02-19T10:40:05Z"
},
{
"id": "audit-001-uuid",
"action": "bhi.calculated",
"description": "Business Health Index calculated: 72 (good)",
"actorType": "system",
"actorId": "insights-service",
"entityType": "customer",
"entityId": "cust-001-uuid",
"regulatoryRelevance": "medium",
"createdAt": "2026-02-19T10:40:00Z"
}
],
"total": 3,
"hasMore": false
}
Every operation in this flow โ authentication, data import, BHI calculation, fraud analysis, recommendation generation, and human approval โ is captured in the tamper-evident audit trail with actor, timestamp, and regulatory relevance classification.
Error Handling
All error responses follow the same format:
# Invalid API key
curl -X GET https://api.example.com/api/v1/tenants/me \
-H "Authorization: Bearer ely_sk_invalid..."
Response (401):
{
"error": "unauthorized",
"message": "Invalid or expired API key"
}
# Rate limited
curl -X POST https://api.example.com/api/public/signin \
-H "Content-Type: application/json" \
-d '{ "email": "test@test.com", "password": "wrong" }'
# ... after exceeding rate limit
Response (429):
{
"error": "rate_limit_exceeded",
"message": "Too many requests. Try again in 45 seconds.",
"retryAfter": 45
}
All routes implemented across services at commit 4b572c2.