High-Level System Architecture
Architectural Principles
The Gravv platform is built on the following architectural principles:
Service-oriented. The platform is decomposed into bounded microservices organised around product and regulatory concerns (identity, customers, accounts, transfers, transactions, payees, FX, billing, onramp, risk, webhooks, audit, crypto custody), rather than a monolith.
Single entry point. All client traffic — dashboard users, API-key merchants, and provider webhooks — terminates at one API gateway that applies authentication, rate limiting, and idempotency before fanning out to internal gRPC services.
Separation of money movement and user experience. The transfer orchestrator, transaction record, and compliance services are isolated from the consumer-facing application layer so that user-facing changes do not affect money-movement guarantees.
Provider abstraction. External payment and banking providers are wrapped behind dedicated integration layers (a stateless provider gateway plus per-service integration crates), so that corridor routing and provider failover are platform decisions, not client concerns.
Event-driven coordination. Money-movement stages, provider webhooks, status updates, and audit events flow over Kafka topics with a consistent naming vocabulary (
web3.transfers.*,transactions.update.status,webhooks.inbound.events,audit.events.log).Defence in depth. Security is enforced at the edge (authentication, rate limiting, IP whitelisting), in transit (TLS, pinned CA bundles, Kafka mTLS), at rest (field-level AES encryption of sensitive columns), and operationally (audit trails, dual authorization for high-value operations).
Observability by default. Every service emits structured logs (zap / zerolog / tracing), health endpoints, and audit traces; every money-movement event is independently auditable through the audit service.
System Layers
The platform can be understood in six layers:
Layer |
Responsibility |
Components |
|---|---|---|
Client layer |
User-facing applications |
Gravv dashboard (Angular), admin console, public stablecoin payment pages (stables.gravv.xyz), tenant REST API integrations. |
Edge & API gateway |
TLS termination, authentication, rate limiting, idempotency, request routing, webhook ingestion |
API gateway (Go / Gin), JWT and API-key middleware, Redis-backed idempotency and rate limiting, provider webhook endpoints. |
Application services |
Product logic and user journeys |
Identity (auth), Customers, Internal Accounts, Transfers, Transactions, Payees, FX, Cards, Onramp, Billing, Payment Links, Savings (OpenTrade). |
Core platform services |
Cross-cutting capabilities used by application services |
Risk (KYC/KYB), Webhooks (outbound delivery), Audit, Web3 custody. |
Integration layer |
Adapters to third-party providers and payment rails |
Integrations microservice (14+ provider clients), banking-integrations service, per-service integration crates (Rust), Dfns custody adapter. |
Data & infrastructure |
Storage, messaging, compute, and observability |
PostgreSQL per service, Redis, Kafka, MongoDB (session/audit logs), GCP Secret Manager, container platform, structured logging. |
Conceptual Transaction Flow
The following describes the conceptual flow of a typical tenant-initiated cross-border transfer (e.g., sending USD to a recipient in Nigeria):
The tenant submits an authenticated request to the API gateway (API key or dashboard JWT). The gateway validates credentials, applies per-tenant rate limiting, records the idempotency key in Redis, and forwards the request to the Transfer service over gRPC with tenant context metadata.
The Transfer service validates the payee via the Payees service (which holds verified beneficiary details and per-payee provider routing), obtains exchange rates and computes fees, and creates a transfer workflow record.
The Risk service evaluates transaction-monitoring rules over Kafka (
transactions.monitoring.initiate→passed/failed); KYC/KYB status and feature eligibility gate the operation.The Transactions service records the customer-visible transaction; the Billing service calculates and charges applicable fees.
For crypto-settled corridors, the Transfer service publishes
web3.transfers.initiateto Kafka; the Web3 service executes the on-chain leg through Dfns MPC wallets (with fee sponsorship) and reportsweb3.transfers.completedorweb3.transfers.failed.The fiat payout leg is routed to the appropriate provider — either directly through the Transfer service’s provider integrations (Thunes, Yellowcard, Dlocal, Bridge, Fincra, and others) or through the Integrations microservice facade.
The provider confirms settlement via webhook; the gateway ingests it, publishes it to
webhooks.inbound.events, and the Transfer service finalises the workflow, updates the Transactions service (transactions.update.status), and emits a merchant-facing event towebhooks.outbound.events.The Webhooks service signs (HMAC-SHA256) and delivers the event to the tenant’s configured endpoint with retries; the Audit service persists the complete event trail from
audit.events.log.
This pattern — client → gateway → product service → core services → integration layer → partner rail — is consistent across all money-movement flows on the platform.