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.

results matching ""

    No results matching ""