Introduction

Olympus Pay System Documentation

Olympus Pay is a neobank platform for African SMBs, built on Supabase (Postgres + Edge Functions + Auth) and operating under the supervision of the Bank of Botswana Regulatory Sandbox. This document covers architecture, data models, security, provider integrations, and deployment.

Production Status
Core banking, KYC, payments, travel, messaging, and file storage are live in production across all supported regions.

At a Glance

Platform
Expo 56 (React Native 0.85.3 + Web)
Backend
Supabase (PostgreSQL 15, Deno Edge Functions, GoTrue Auth)
API Gateway
Kong (embedded in Supabase) — JWT validation, CORS, TLS, rate limiting
Banking Rails
Zenus / TUUM — accounts, payments (LOCAL/ACH/SWIFT/BOOK), cards
Storage
Cloudflare R2 (S3-compatible), presigned URL upload/download
KYC Provider
DIDIT — liveness + document verification + AML screening
Project ID
hzxxenidupmnrpatbniq (eu-west-1)
Regulatory Status
Bank of Botswana Regulatory Sandbox — cross-border banking delivered via Zenus / TUUM partnership
Web
olympuspay.co

Architecture

Olympus Pay uses a serverless, edge-first architecture. All client requests pass through Supabase's embedded Kong API Gateway before reaching edge functions or the PostgREST database layer.

Mobile / Web App (Expo)
        ↓ HTTPS
Kong API Gateway  ←── JWT validation, CORS, rate limiting, TLS
        ↓
  ┌─────┴──────────────────────────┐
  │                                │
PostgREST                  Edge Functions (Deno)
(tables, RPCs)              (business logic)
  │                                │
  └────────┬───────────────────────┘
           │
      PostgreSQL 15 (RLS enforced)
           │
    ┌──────┴──────────────────────────────────────────┐
    │                                                  │
External Providers                            Cloudflare R2
(Zenus, DIDIT, Duffel,                       (file storage)
 Flutterwave, Africa's Talking,
 Documenso, Resend, HotelBeds)

Request Flow

1

Client sends request

Expo app sends HTTPS request with Authorization: Bearer JWT and apikey: anon_key headers.

2

Kong validates JWT

Kong verifies the JWT signature, extracts sub (user ID), and forwards the request with the identity attached.

3

Edge Function runs

Deno function validates the token again via resolveUser() from _shared/security.ts, checks rate limits, then processes the request.

4

Database write (if needed)

All DB operations use the service-role client inside edge functions. RLS policies are still evaluated for PostgREST calls from the client.

5

Provider call (if needed)

Edge function calls the appropriate provider (Zenus, Flutterwave, etc.) with credentials from Supabase Vault.

6

Response

Function returns JSON. All responses include CORS headers. Rate-limited responses return 429.

Technology Stack

LayerTechnologyVersion / Notes
Mobile AppExpo / React NativeSDK 56, RN 0.85.3
Web AppExpo Router (web)Hosted on Vercel
NavigationExpo Router v4File-based routing
StateZustandGlobal auth + UI state
BackendSupabasePostgreSQL 15 + Deno Edge Functions
API GatewayKongEmbedded in Supabase
AuthSupabase GoTrueJWT, OTP, OAuth-ready
StorageCloudflare R2S3-compatible, presigned URLs
BankingZenus / TUUMREST API v2
KYCDIDITLiveness + AML
PaymentsFlutterwavev3 API, OAuth2
TravelDuffelv2 API
MessagingAfrica's TalkingSMS, WhatsApp, USSD
E-SignDocumensoREST API
EmailResendTransactional email

Database Schema

All tables live in the public schema of a PostgreSQL 15 database. Row-Level Security (RLS) is enabled on every table. The auth.uid() function identifies the current user.

Core Tables

TableDescriptionKey Columns
profilesOne row per auth user. Extended user data.id (FK auth.users), full_name, phone, avatar_url, kyc_status, account_tier
business_profilesCompany details for business accounts.user_id, legal_name, trading_name, entity_type, reg_number, tax_id
accountsBank account records linked to Zenus.user_id, currency, balance, available_balance, account_number, sort_code, zenus_account_id
transactionsAll debit/credit events.user_id, type, amount, currency, status, recipient_name, payment_rail, zenus_payment_id
cardsVirtual and physical card records.user_id, card_type, display_name, last_four, status, monthly_limit, pin_set, zenus_card_id
beneficiariesSaved payment recipients.user_id, beneficiary_name, account_number, bank_code, payment_rail
invoicesInvoice headers.user_id, invoice_number, client_name, client_email, status, total, due_date
invoice_itemsLine items for invoices.invoice_id, description, quantity, unit_price, subtotal
payment_requestsMoney-request records.from_user_id, to_email, amount, currency, status, payment_link
scheduled_paymentsRecurring payment schedules.user_id, amount, frequency, next_run_date, payment_method
notificationsIn-app notification feed.user_id, type, title, body, is_read, metadata
kyc_verificationsDIDIT session records.user_id, session_id, status, entity_type, liveness_score, aml_hits
ubo_declarationsUltimate Beneficial Owner filings.user_id, beneficial_owners (JSONB)
compliance_alertsAML / OFAC flags.user_id, alert_type, severity, resolved
travel_bookingsFlight and hotel bookings.user_id, booking_type, provider, provider_order_id, status, total_amount
travel_passengersSaved passenger profiles.user_id, is_default, given_name, family_name, passport_number
webhook_subscriptionsOutbound webhook config.user_id, event_type, url, secret, is_active
statementsMonthly statement PDF references.user_id, period_start, period_end, file_key

Row-Level Security

Every table has RLS enabled. The general policy is: a user can only read and write their own rows. Financial write operations additionally require KYC approval.

KYC Gate Policy

Sensitive tables like transactions, cards, and scheduled_payments use an additional policy function:

CREATE POLICY "kyc_required" ON transactions
  FOR INSERT TO authenticated
  USING (is_kyc_approved(auth.uid()));

CREATE FUNCTION is_kyc_approved(uid uuid) RETURNS boolean AS $$
  SELECT kyc_status = 'approved'
  FROM profiles WHERE id = uid;
$$ LANGUAGE sql SECURITY DEFINER;
Access Control
The compliance_alerts and audit_logs tables are restricted to the service_role key and are not accessible from client-facing requests.

File Storage (Cloudflare R2)

Olympus Pay uses Cloudflare R2 for all file storage. Files are uploaded directly via presigned URLs, keeping storage credentials server-side at all times.

Upload Flow

1

Request presigned URL

POST /functions/v1/cf-upload with file_type and content_type. Returns { presigned_url, key }.

2

PUT file directly to R2

Client sends the file bytes directly to the presigned URL. No auth header on this request.

3

Store the key

Save the returned key in the database (e.g., in profiles.avatar_key or transactions.receipt_key).

4

Retrieve via signed URL

GET /functions/v1/cf-file?key=... returns a signed URL valid for 1 hour.

Storage Buckets (Key Prefixes)

avatars/
Profile pictures — avatars/{user_id}.jpg
receipts/
Transaction receipts — receipts/{user_id}/{txn_id}.jpg
docs/
KYC and legal documents
statements/
Monthly PDF statements
invoices/
Generated invoice PDFs

Authentication

Olympus Pay uses Supabase GoTrue for authentication. All sessions are token-based — access tokens are short-lived (1 hour) and are refreshed silently using a long-lived refresh token (30 days). There are no cookies or server-side sessions.

Sign Up

POST /auth/v1/signup — creates a new user and returns an active session immediately. A confirmation email is sent if email confirmation is enabled.

{
  "email": "user@example.com",
  "password": "••••••••",
  "data": {
    "full_name": "Kefilwe Moagi",
    "phone": "+26771234567"
  }
}

Sign In

POST /auth/v1/token?grant_type=password — authenticates with email and password. Returns access_token, refresh_token, and the user object.

{
  "email": "user@example.com",
  "password": "••••••••"
}

// Response
{
  "access_token": "eyJhbGci...",
  "refresh_token": "v1:...",
  "expires_in": 3600,
  "token_type": "bearer",
  "user": { "id": "uuid", "email": "...", "role": "authenticated" }
}

Refresh Token

POST /auth/v1/token?grant_type=refresh_token — exchanges a refresh token for a new access token. The Supabase JS and React Native clients handle this automatically.

{
  "refresh_token": "v1:..."
}

Token Structure

Every access token is a signed JWT. The claims most relevant to edge functions:

sub
User UUID — maps to auth.users.id and profiles.id
role
authenticated for signed-in users, anon for unauthenticated
exp
Unix timestamp — token is invalid after this value (3600s from issue)
iss
Your Supabase project URL — used by Kong to verify token origin
aud
authenticated

Required Headers

Every API request must carry both headers. Kong rejects requests missing either one.

Authorization: Bearer <access_token>
apikey: <supabase_anon_key>
Why two headers?
apikey identifies the Supabase project at the Kong gateway layer. Authorization identifies the individual user within that project. Both are required — one without the other returns 401.

Auth Errors

StatusCause
400Malformed request body or missing required fields
401Missing or invalid Authorization header, or expired access token
403Valid token but insufficient permissions (RLS policy denied access)
422Email already registered, or password too short

KYC Flow

Identity verification is a hard gate on all financial operations — sending money, issuing cards, bulk payments, and scheduled payments all require kyc_status = 'approved'. This is enforced both at the RLS level in the database and within edge functions before any external call is made.

Verification is handled by DIDIT and covers three layers: liveness detection (biometric selfie check), document verification (passport, national ID, or driver's licence via OCR + authenticity checks), and AML screening (global sanctions, PEP, and adverse media checks).

Entity Types

Entity TypeDocuments RequiredAdditional Step
individualGovernment-issued photo ID + liveness selfie
businessDirector ID + liveness + company registration documentsUBO Declaration (all beneficial owners ≥ 10%)

Verification Flow

1

Create a session

POST /functions/v1/didit-session with entity_type (individual or business) and country (ISO 3166-1 alpha-2). Returns session_id, session_url, and expiry timestamp. profiles.kyc_status is set to pending.

2

Open the session URL

Redirect the user to session_url — either in an in-app WebView or the system browser. DIDIT's hosted flow guides the user through liveness capture and document upload. Sessions expire after 30 minutes.

3

Receive the decision

DIDIT sends a signed POST to /functions/v1/didit-webhook on completion. The signature is verified via HMAC-SHA256 before any processing occurs. Alternatively, poll POST /functions/v1/didit-decision with { "session_id": "..." }.

4

Profile updated

The webhook handler writes the final status to profiles.kyc_status and inserts a full record into kyc_verifications — including liveness score, document type, and AML hit count. RLS policies on financial tables evaluate is_kyc_approved(auth.uid()) on every write.

5

Business accounts — UBO Declaration

Business entity verification also triggers a UBO Declaration requirement. POST /functions/v1/zenus-ubo-declare must be called with a list of all beneficial owners holding ≥ 10% equity before financial access is fully unlocked.

Session Request

POST /functions/v1/didit-session
{
  "entity_type": "individual",  // or "business"
  "country": "BW"               // ISO 3166-1 alpha-2
}

// Response
{
  "session_id": "did_sess_...",
  "session_url": "https://verify.didit.me/session/...",
  "expires_at": "2026-06-15T22:00:00Z"
}

Webhook Payload

POST /functions/v1/didit-webhook
Headers: x-didit-signature: sha256=...

{
  "event": "session.completed",
  "session_id": "did_sess_...",
  "status": "approved",
  "liveness_score": 0.99,
  "document_type": "PASSPORT",
  "document_country": "BW",
  "aml_hits": 0,
  "completed_at": "2026-06-15T21:47:33Z"
}

KYC Status Reference

StatusDescriptionFinancial Access
not_startedNo session has been created for this userRead-only — can view balances and history
pendingSession created and in progressRead-only — session URL still active
approvedIdentity verified — all checks passedFull access to all financial operations
rejectedVerification failed — liveness, document, or AML checkRead-only — a new session can be initiated

AML & Screening

DIDIT runs AML checks against the following sources as part of every verification session:

  • OFAC Specially Designated Nationals (SDN) list
  • UN Security Council consolidated sanctions list
  • EU and UK financial sanctions registers
  • Politically Exposed Persons (PEP) global database
  • Adverse media screening (negative news)

An aml_hits count greater than zero is recorded in kyc_verifications and triggers a compliance_alerts entry for manual review. The user's kyc_status is set to rejected until the alert is resolved.

Security
Never trust the client to report KYC status. Always read profiles.kyc_status server-side. Edge functions call resolveUser() and then check KYC status against the database before executing any financial operation.

Account Tiers

Every account operates within a tier that defines transaction limits and feature access. Tier limits are enforced inside edge functions before any call is made to Zenus — a payment that would breach a tier limit is rejected at the application layer, not the banking rail.

TierDaily LimitMonthly LimitFeatures
StarterBWP 5,000BWP 20,000Basic transfers, 1 virtual card
PersonalBWP 25,000BWP 100,000All payment rails, 2 cards, scheduled payments
BusinessBWP 100,000BWP 500,000Bulk payments, invoicing, payroll, multi-user access
EnterpriseNegotiatedNegotiatedCustom limits, dedicated support, API access

Tier Upgrades

Tier changes are applied via the set_account_tier RPC. Upgrades require a verified identity (kyc_status = 'approved'); downgrades take effect immediately.

POST /rest/v1/rpc/set_account_tier
{
  "user_id": "uuid",
  "tier": "business"
}

Compliance

Olympus Pay is a regulated financial institution operating under the supervision of the Bank of Botswana Regulatory Sandbox. Compliance controls are embedded at every layer of the stack — from database policies to edge function logic to third-party provider checks.

Controls

ControlWhere EnforcedDetail
Identity verificationRLS + edge functionsKYC gate on all financial writes via is_kyc_approved()
AML screeningDIDIT (KYC) + Zenus (ongoing)OFAC, UN, EU, UK sanctions + PEP + adverse media
UBO DeclarationBusiness onboardingAll beneficial owners ≥ 10% must be declared before financial access
Transaction limitsEdge functionsDaily and monthly caps enforced per account tier before Zenus is called
Transaction monitoringZenus webhook + compliance_alerts tableUnusual activity flagged and surfaced for review
Webhook integrityAll inbound webhooksHMAC-SHA256 signature verified before any payload is processed
Audit trailDatabase triggersEvery financial mutation recorded with user ID, timestamp, and originating IP
Data retentionPolicyTransaction records retained for 7 years per Bank of Botswana Regulatory Sandbox requirements

Suspicious Activity

Transactions that trigger a compliance flag from Zenus or exceed monitored thresholds result in a record in compliance_alerts with a severity level (low, medium, high). High-severity alerts are escalated to Suspicious Activity Reports (SARs) and filed with the Bank of Botswana in accordance with applicable financial intelligence obligations.

Edge Functions Overview

53 Deno edge functions handle all business logic. They run on Supabase's global edge network and share common utilities from supabase/functions/_shared/.

CategoryCountFunctions
Zenus Banking13create-person, open-account, payment, cancel-payment, bulk-payment, card-issue, card-manage, card-pin, sync-balance, statement, compliance-check, ubo-declare, webhook
Travel — Duffel10airports, search, offer, book, orders, cancel, stays-search, stays-book, webhook
KYC — DIDIT3session, decision, webhook
Flutterwave5transfer, airtime, bills, payment-link
Africa's Talking4sms, whatsapp, airtime, ussd
File Storage4cf-upload, cf-file, cf-manage, cf-dns
HotelBeds3hotels, activities, transfers
Documenso3send, status, webhook
Core Platform5initiate-deposit, send-payment-request, payment-request-checkout, support-chat, ai-insights
AI / Tools3scan-receipt, auto-fill-business, nvidia-ai

Shared Utilities

All edge functions import from supabase/functions/_shared/.

_shared/security.ts

resolveUser()
Extracts and validates the JWT from the Authorization header. Returns the Supabase user object or throws 401.
rateLimit()
Sliding-window rate limiter backed by the rate_limits table. Returns 429 when exceeded.
verifyHmacSignature()
Validates HMAC-SHA256 signatures on inbound webhooks (DIDIT, Zenus, Duffel, Documenso).
corsHeaders
Standard CORS headers allowing all origins. All functions prepend these to responses.
securityHeaders
X-Content-Type-Options, X-Frame-Options, Referrer-Policy.

_shared/flutterwave.ts

Handles Flutterwave OAuth2 client credentials flow. getFWToken() fetches and caches a bearer token using FW_CLIENT_ID and FW_CLIENT_SECRET from Vault.

_shared/zenus.ts

Zenus API client. Handles authentication with ZENUS_BEARER_TOKEN and ZENUS_API_KEY. Provides typed request/response interfaces for all Zenus operations.

Banking

Olympus Pay is a regulated financial institution operating under the supervision of the Bank of Botswana Regulatory Sandbox. Cross-border payments, multi-currency accounts, and card issuance are delivered through our partnership with Zenus / TUUM — giving African SMBs access to global payment rails from a single platform.

Banking Structure

Regulator
Bank of Botswana (BoB) — Regulatory Sandbox
Cross-Border Partner
Zenus / TUUM — multi-currency accounts, global payment rails, card issuance
AML / Compliance
OFAC and PEP screening on all users and beneficiaries; AML checks at identity verification
Identity Gate
All financial operations require a verified identity, enforced at the database level

Payment Rails

RailUse CaseSettlementCurrency
LOCALDomestic EFT (Botswana)Same dayBWP
ACHUS bank transfers2-3 business daysUSD
SWIFTInternational wire1-5 business daysAny
BOOK_TRANSFERInternal (Zenus to Zenus)InstantAny

Card Lifecycle

1

Issue

zenus-card-issue — creates virtual or physical card, returns card_id.

2

Activate

zenus-card-pin — set a 4-digit PIN (required for physical cards).

3

Manage

zenus-card-manage — freeze, unfreeze, cancel, update limit, or request replacement.

4

Monitor

Zenus webhooks fire on authorization events and are processed by zenus-webhook.

Payments

Send Payment Request

The send-payment-request function creates a Flutterwave payment link and emails it to the recipient via Resend. A hosted payment page at olympuspay.co/pay-request?id=... is also generated for each request.

Bulk Payments (Payroll)

zenus-bulk-payment processes multiple recipients in a single batch call. Each recipient is processed individually and results are returned per-entry. The batch is recorded in the bulk_payments table.

Scheduled Payments

Scheduled payments are stored in scheduled_payments and triggered by a Supabase cron job (pg_cron) that runs daily at 06:00 UTC. The cron job calls the process_scheduled_payments RPC for any payments due that day.

KYC — DIDIT

Three functions handle the full identity verification lifecycle:

didit-session
Creates a DIDIT verification session. Supports individual and business entity types. Business sessions also validate company name and type.
didit-decision
Polls a session for the final decision. Updates profiles.kyc_status and inserts a record into kyc_verifications.
didit-webhook
Inbound webhook registered with DIDIT. Verifies HMAC-SHA256 signature before processing. Updates user status and triggers post-KYC actions (account provisioning, email).

Travel — Duffel

Flight search, booking, and management via Duffel API v2. All requests include the Duffel-Version: v2 header.

Flight Booking Flow

1

Search airports

GET /functions/v1/duffel-airports?q=gaborone — autocomplete IATA codes.

2

Search flights

POST /functions/v1/duffel-search — returns offers. Save offer_request_id and offer_id.

3

Get offer details

POST /functions/v1/duffel-offer — retrieves baggage, fare rules, and final price.

4

Book

POST /functions/v1/duffel-book with passenger details. Returns order_id and booking_reference.

5

Cancel (if needed)

POST /functions/v1/duffel-cancel with order_id. Refund processed per airline policy.

Messaging — Africa's Talking

FunctionChannelNotes
at-smsSMSTransactional payment notifications
at-whatsappWhatsAppTemplate messages via AT WhatsApp API
at-airtimeAirtimeAirtime disbursement (alternative to Flutterwave)
at-ussdUSSDStateful session. Authenticated via ?secret= query param. Returns CON (continue) or END responses.

Storage — Cloudflare R2

cf-upload
Returns a presigned PUT URL valid for 15 minutes. Accepts file_type (avatar, receipt, doc, statement, invoice) and content_type.
cf-file
Returns a presigned GET URL valid for 1 hour for a given object key.
cf-manage
Deletes an object by key. Only the owning user can delete their own files (validated via JWT).
cf-dns
Admin function to manage Cloudflare DNS records for custom domains.

AI & Tools

scan-receipt
Accepts a multipart image upload. Uses Claude (via nvidia-ai fallback) to extract merchant, amount, date, and line items.
ai-insights
Aggregates the user's transaction history and generates natural-language spending summaries and savings suggestions.
support-chat
AI-powered customer support. Answers questions about the app, escalates to human support for account issues.
auto-fill-business
Looks up company details by registration number and returns pre-filled BusinessProfile fields.

Provider Integration Map

Zenus / TUUM Live
Core banking — accounts, payments, cards, compliance, statements
13 edge functions · REST v2
DIDIT Live
KYC — liveness check, document OCR, AML screening
3 edge functions · HMAC webhook
Flutterwave Live
Mobile money (Orange/Mascom), airtime, bills, payment links
5 edge functions · OAuth2
Duffel Live
Flights, stays booking and management
10 edge functions · v2 API
Africa's Talking Live
SMS, WhatsApp, USSD, airtime
4 edge functions
Cloudflare R2 Live
Object storage — avatars, receipts, statements
4 edge functions · presigned URLs
Documenso Live
e-Signature for Terms of Service agreements
3 edge functions · HMAC webhook
Resend Live
Transactional email for payment requests and notifications
REST API · olympuspay.co sender domain
HotelBeds Live
Hotels, activities, and airport transfers
3 edge functions · REST API

Webhooks

All inbound webhooks are verified with HMAC-SHA256 using secrets stored in Supabase Vault. Requests with invalid signatures return 403 Forbidden.

ProviderEndpointSignature HeaderEvents
DIDIT/functions/v1/didit-webhookx-didit-signaturesession.completed, session.failed
Zenus/functions/v1/zenus-webhookx-zenus-signaturePAYMENT_COMPLETED, CARD_FROZEN, COMPLIANCE_FLAGGED
Duffel/functions/v1/duffel-webhookx-duffel-signatureorder.updated, order.cancelled
Documenso/functions/v1/documenso-webhookx-documenso-signaturedocument.signed, document.declined
Africa's Talking/functions/v1/at-ussd?secret= query paramAll USSD sessions

Environment Variables

All secrets are managed via Supabase Vault and injected into edge functions at runtime.

Core (Required)

SUPABASE_URL
Project URL (auto-set by Supabase)
SUPABASE_SERVICE_ROLE_KEY
Service role JWT — used inside edge functions only
SUPABASE_ANON_KEY
Public anon key — safe to expose in client apps

Banking

ZENUS_BEARER_TOKEN
Zenus API access token
ZENUS_API_KEY
Zenus API key
ZENUS_WEBHOOK_SECRET
HMAC secret for Zenus webhook verification

KYC

DIDIT_CLIENT_ID
DIDIT OAuth client ID
DIDIT_CLIENT_SECRET
DIDIT OAuth client secret
DIDIT_WEBHOOK_SECRET
HMAC secret for webhook verification

Payments & Messaging

FW_CLIENT_ID
Flutterwave OAuth2 client ID
FW_CLIENT_SECRET
Flutterwave OAuth2 client secret
AT_API_KEY
Africa's Talking API key
AT_USERNAME
Africa's Talking username
AT_USSD_SECRET
Secret for USSD callback authentication
RESEND_API_KEY
Resend API key for transactional email

Storage & Travel

CF_ACCOUNT_ID
Cloudflare account ID
CF_R2_ACCESS_KEY
R2 S3-compatible access key
CF_R2_SECRET_KEY
R2 S3-compatible secret key
CF_R2_BUCKET
R2 bucket name
DUFFEL_ACCESS_TOKEN
Duffel API token
HOTELBEDS_API_KEY
HotelBeds API key
HOTELBEDS_API_SECRET
HotelBeds API secret

Deploy Guide

Edge Functions

# Deploy all edge functions
supabase functions deploy --no-verify-jwt zenus-webhook didit-webhook duffel-webhook documenso-webhook

# Deploy a single function (most functions verify JWT inside the handler)
supabase functions deploy zenus-payment

# Set secrets (from .env file)
supabase secrets set --env-file .env

Database Migrations

# Apply pending migrations
supabase db push

# Generate migration from schema changes
supabase db diff --schema public -f migration_name

Web App (Vercel)

# Build Expo for web
npx expo export --platform web

# Deploy (from project root)
vercel --prod

Local Development

# 1. Clone and install
git clone git@github.com:olympuspay/olympus-app.git
cd olympus-app
npm install

# 2. Start Supabase locally
supabase start

# 3. Copy environment
cp .env.example .env
# Fill in your API keys

# 4. Start the app
npx expo start

# 5. Serve edge functions locally
supabase functions serve
Local Supabase
Running supabase start spins up local Postgres, GoTrue Auth, Kong, and the edge function runtime. Local URLs are printed on startup. Use the Supabase Studio at http://localhost:54323 to inspect data.

Regulatory

Olympus Pay (Botswana) is a regulated financial institution operating under the supervision of the Bank of Botswana Regulatory Sandbox. All platform operations, integrations, and data handling practices are designed and maintained in alignment with the obligations set forth under this regulatory framework.

Compliance Obligations

ObligationScope
Identity VerificationMandatory for all users prior to any financial transaction. Enforced at the database and application layers.
Ultimate Beneficial Owner (UBO) DeclarationRequired for all business account holders. All beneficial owners holding 10% or greater equity must be declared before financial access is granted.
AML & Sanctions ScreeningAll users and beneficiaries are screened against OFAC, UN, EU, and UK sanctions registers, as well as PEP databases, at onboarding and on an ongoing basis.
Transaction Record RetentionAll financial transaction records are retained for a minimum of seven years.
Suspicious Activity ReportingHigh-severity compliance alerts are escalated and reported in accordance with applicable financial intelligence obligations.