SAA-v1.1

Architecture Guide

Implementation Guide v1.1

Service API
Architecture

A comprehensive guide for implementing the instruction-based Service API Architecture as standalone, independent servers. Each Service API follows the nuvion-core structural patterns.

3-Layer

Architecture

Multi-Provider

Support

Versioned

Instructions

Type-Safe

VSL Validation

Idempotent

Operations

Section 1

Architecture Overview

Understanding the core concepts and deployment model

The architecture decouples the Core Service from third-party provider implementations through a unified, versioned instruction protocol.

// Critical Architectural Points

  • 1. One Service API = One Server
  • 2. Provider-Specific VSL Specs
  • 3. Versioned Instructions (v1, v2)
Section 2

Three-Layer Architecture

Click on each layer to explore its responsibilities

Core Service → Instruction Request

Layer 1: Instruction Handler

Endpoint Layer

Layer 2: Service Orchestrator

Service Layer

Layer 3: Provider Executor

Provider Adapter

External Provider (Flutterwave, Stripe, etc.)

Section 3

Instruction Protocol

The unified interface for all Service APIs through a single /instructions endpoint

Request Structure
{
"instruction": "create.account",
"version": "v1",
"unique_reference": "client-uuid-12345",NEW
"provider": { id, meta },
"payload": { ... }
}
Field Reference
instruction

The action to perform (verb.noun format)

version

API version for backward compatibility (v1, v2)

unique_referencev1.1

Client-generated unique identifier for idempotency

provider

3-char provider code + optional routing hints

payload

Provider-specific data validated against spec

Idempotency via unique_reference

The composite key provider.id + unique_reference ensures duplicate requests return cached responses instead of re-executing. This prevents issues from network retries or client errors.

Common Instructions

create.accountlist.accountsget.accountupdate.accountcreate.payoutlist.cards
Interactive Simulation

Idempotency Flow

See how duplicate requests are handled using the unique_reference field

Simulation Controls

// Instruction Request

"unique_reference": "req-flw-12345-uuid"
"provider.id": "FLW"
// Composite Key: FLW:req-flw-12345-uuid

0

Requests Sent

0

Cached Responses

Execution Flow
Click "Send First Request" to start the simulation
Section 4

Provider System

Each provider has different requirements. Select a provider to see its specific specs.

FLW

Flutterwave

Provider Integration

Regions

NGKEGHZA

Currencies

NGNKESGHSZARUSD

Supported Instructions

create.account
v1v2
list.accounts
v1
get.account
v1
update.account
v1

VSL Spec: FLW/specs/v1/create-account.vsl.js

root { // Flutterwave create account v1

bvn string<length:11>
email string<isEmail>
currency string(NGN|KES|GHS)

...

}

Key insight: Each provider's create.account spec is different! FLW requires BVN, STR requires SSN/routing, THR requires NIN.

Transformer Deep Dive

Cross-Provider Field Mapping

How the same unified payload gets transformed differently for each provider

Unified Payload (from Core)
customer_name:"John Doe"
kyc_reference:"REF-12345"
phone:"+2348012345678"
entity_id:"01HQWXYZ..."
currency:"NGN"
Transformer
FLW Payload (to Provider)
account_name:"John Doe"
bvn:"REF-12345"
mobilenumber:"+2348012345678"
tx_ref:"01HQWXYZ..."
currency:"NGN"
Field Mapping Reference
Unified FieldFLWSTRTHR
customer_nameaccount_nameaccount_holder_namename
kyc_referencebvnssnnin
phonemobilenumberphone_numbermobile
entity_idtx_refmetadata.entity_idreference
currencycurrencycurrencycurrency
Architecture Clarification

Provider Failover Responsibility

Service APIs are pure delivery mechanisms - failover logic lives in Core Service

Service APIs Do NOT Handle
  • Provider failover logic
  • Automatic provider switching
  • Retry logic for failed providers
  • Provider selection decisions
Service APIs DO Handle
  • Instruction execution for specified provider
  • Payload transformation to provider format
  • Provider API communication
  • Response normalization
Failover Flow Example
1

Core Service sends instruction to Account Issuing API with provider=FLW

2

FLW fails (timeout, error, etc.) - Service API returns error to Core Service

3

Core Service decides: retry FLW or switch to STR (based on business logic)

4

Core Service sends new instruction with provider=STR

Why This Design?

Central Knowledge

Core Service knows all available providers across all Service APIs

Business Logic

Core Service has provider selection logic (cost, features, reliability)

Health Metrics

Core Service maintains provider health metrics and routing decisions

Simple Executors

Service APIs stay focused on execution, not orchestration

Section 5

Directory Structure

Each Service API is a standalone application with this structure. Click folders to expand.

nuvion-account-issuing-api/
app.js
bootstrap.js
core/
errors/
logger/
validator/
mongoose/
http-request/
repository-factory/
endpoints/
instructions.js
health.js
services/
orchestrator/
providers/
models/
account-base.js
FLW-account.js
repository/
FLW-account/
STR-account/
middlewares/
messages/

Key Difference from nuvion-core

  • • Single /instructions endpoint
  • • Provider-specific specs with versioning
  • • Service-focused domain only

Repository Examples

  • • nuvion-core
  • • nuvion-account-issuing-api
  • • nuvion-payouts-api
  • • nuvion-card-issuing-api
Section 6

Versioning Strategy

How instruction versions enable backward compatibility

Version Evolution Example

v1Original

bvn: required
nin: optional
date_of_birth: —

v2Updated

bvn: required
nin: required
date_of_birth: required

Reject

Return error saying v1 is deprecated

Auto-upgrade

Transform v1 payload to v2 (if possible)

Support Both

Maintain backward compatibility

// Spec resolution path

providers/[PROVIDER_ID]/specs/[VERSION]/[instruction].vsl.js

// Example: providers/FLW/specs/v2/create-account.vsl.js

Section 7

Inter-Service Communication

How services communicate via HTTP with service keys

Core Service (nuvion-core)

Creates instruction payload, adds X-Service-Key header

POST /instructions

Account Issuing API

Validates key, executes instruction, returns response

Service Authentication

// Request Header

X-Service-Key: sk_account_issuing_xxxxx

Service Discovery

ACCOUNT_ISSUING_API_URL=:3001

PAYOUTS_API_URL=:3002

CARD_ISSUING_API_URL=:3003

Interactive Simulation

Webhook / Callback Architecture

How inbound provider webhooks are received, routed, and processed securely

External Provider

Flutterwave, Stripe, etc.

Callback Server

AWS EC2 + Elastic IP

Service API

Account Issuing API

Why a Callback Server?

Static IP Requirement

Providers require whitelisted IPs for webhook delivery

AWS EC2 + Elastic IP

Dedicated server with static IP that can be whitelisted

Raw Payload Forwarding

Preserves original body for signature verification

Retry Logic

3 retries with exponential backoff, then dead letter queue

Webhook Processing Flow
Click "Simulate Webhook" to see the flow
Provider Routing Configuration

// callback-server/routes/webhook-receiver.js

const PROVIDER_ROUTES = {

FLW: { serviceUrl: ACCOUNT_ISSUING_API, path: '/webhooks/flutterwave' },

STR: { serviceUrl: ACCOUNT_ISSUING_API, path: '/webhooks/stripe' },

PSP: { serviceUrl: PAYOUTS_API, path: '/webhooks/paystack' },

}

Interactive Simulation

Transaction Consistency

MongoDB transactions with automatic rollback and Slack alerting for failures

Scenario Selection

Choose a scenario to see how the system handles transaction consistency:

Go-Live Strategy

MongoDB Transactions for atomicity
Automatic rollback on failure
Slack alerts for manual intervention
Execution Timeline
Select a scenario to visualize the transaction flow
Section 8

Best Practices

Conventions and guidelines for consistent implementation

ComponentConvention
Service API Reponuvion-[domain]-api
Instructionverb.noun
Versionv[number]
Provider ID3 uppercase letters
Model NamePROVIDER_resource
Spec File[instruction].vsl.js