Skip to main content

Saudi open banking: running the bank-side API layer inside the Kingdom

What the SAMA framework asks of a bank platform team for Saudi open banking, and how to run the AIS and PIS API layer, logs and audit trail inside the Kingdom.

  • open-banking
  • banking
  • compliance
  • gcc
Zerq team

Saudi open banking has moved from policy to supervised practice. SAMA issued its Open Banking Policy in January 2021, announced the Open Banking Framework in November 2022 with account information services (AIS) first, announced the payment initiation services (PIS) release in September 2024, and began licensing fintechs in March 2026 after the regulatory sandbox phase. For a bank's platform team, that ends in a concrete inbox: fintechs asking for production access, a CISO asking where every component runs, and compliance asking how you will prove which fintech read which account, under which consent.

The SAMA open banking framework, made up of a Glossary, Use Cases, Business Rules, and Technical Standards, is available only on request from SAMA's Open Banking Team. This post covers what the public record implies for the bank's API layer, and how to run that layer inside the Kingdom.

Why the usual gateway choices get awkward in the Kingdom

Familiar gateways cause friction in two places: where the control plane lives, and where the open banking logic ends up. Apigee keeps its management plane in Google Cloud even when the runtime runs in your cluster. Azure API Management's self-hosted gateway still takes its configuration from the Azure-hosted service. AWS API Gateway is a managed regional service, with authorization logic usually pushed into Lambda authorizers. SAMA's Cyber Security Framework says that, in principle, only cloud services located in Saudi Arabia should be used, and that public or hybrid cloud use needs SAMA approval. A vendor-operated control plane turns a gateway choice into an approval file.

Kong can run fully self-managed, and MuleSoft offers a self-hosted platform edition, which settles residency, but the open banking specifics land in custom code: a Kong plugin your team maintains for the consent check, or Mule flows whose consent rules change only through a redeploy, which the bank's change records for SAMA would then have to track. Both work, but the consent logic and its change history then live in code your team owns rather than in gateway configuration.

What does SAMA require from banks for open banking?

The first theme is consent. The Open Banking Policy says customers grant third-party providers access through explicit and informed consent. In the KSA certification test flow, an account access consent resource creates a ConsentId before authorisation, and the ConsentId travels in the request object to the pushed authorization request (PAR) endpoint. Consent is granted once; your APIs honour it on every call.

The second is security. The Saudi profile is FAPI 1 Advanced, with PAR mandatory. Banks are expected to always certify for mTLS client authentication at the authorization server, and individual Saudi banks appear as certified OpenID Providers against the KSA profile, which points to each bank running its own authorization server. FAPI 1 Advanced also requires MTLS sender-constrained access tokens, so every fintech resource call arrives with a client certificate, and the resource layer is the natural place to check that the access token belongs to the certificate presenting it.

The third is readiness: SAMA's Open Banking Lab provides a sandbox simulating a bank's APIs and conformance suites to certify against the Framework, and licensed fintechs must show adherence on API performance, data security, and consent management, so expect fintechs to ask about your API availability and latency.

The fourth is residency. SAMA's Rules on Outsourcing require a written no objection for material outsourcing, and an overseas provider also needs a legal opinion confirming SAMA's right of access. Where no adequacy decision applies, the Personal Data Protection Law's transfer rules call for SDAIA safeguards such as its standard contractual clauses, and the law keeps applying after the data leaves. Running every component, log, and key inside the Kingdom removes the overseas-outsourcing and cross-border-transfer steps; running it on the bank's own infrastructure or private cloud also stays outside the CSF's cloud approval requirement. Our UAE data residency post runs the same component-by-component analysis for the CBUAE.

Running the Saudi open banking API layer inside the Kingdom

Zerq's gateway core is a single Go binary serving the gateway runtime, management API, and MCP endpoints; the management UI and Developer Portal are Next.js applications. Configuration, request logs, and audit logs live in your MongoDB, Redis handles caching and multi-pod coordination, and staff sign in through your OIDC provider. There is no vendor-hosted control plane; the component model is on the architecture page.

The in-Kingdom request path, hop by hop

Follow one account information call from a licensed fintech:

  1. The fintech completes the FAPI flow with your authorization server, which issues an access token bound to the fintech's client certificate. That server is yours, not Zerq.
  2. Your ingress tier terminates mutual TLS and forwards the client certificate in the X-SSL-Client-Cert header, which Zerq reads through the MTLS_CLIENT_CERT_HEADER setting.
  3. Zerq checks the client's policy, keyed on X-Client-ID, and returns 429 for a call over its limit, before authenticating.
  4. Zerq resolves the fintech from X-Client-ID and X-Profile-ID, validates the token against your authorization server's issuer, audience, and JWKS, and checks that its cnf.x5t#S256 thumbprint matches the forwarded certificate. A valid token with another certificate, or none, gets a 401.
  5. Zerq applies any IP allowlist (useful only for the ingress's own address) and allowed methods (405), and confirms the route is in one of the client's collections (404 otherwise).
  6. The proxy's workflow runs the consent check, then forwards to your AIS backend, and the request log entry lands in your MongoDB.

Zerq verifies only RS256-family JWT access tokens (no PS256, ES256 or opaque tokens) and rejects a token whose client_id claim differs from the Zerq client ID, so test one of your authorization server's tokens before go-live.

X-Client-ID and X-Profile-ID are Zerq headers, not part of the KSA specification, so either issue them to each fintech at onboarding or have the ingress map each validated certificate to that fintech's Zerq client and profile IDs with a lookup (Zerq IDs are 24-character ObjectIDs, so forward the mapped value, not the subject's CN or OU), and overwrite any client-supplied values. Either way, the ingress should strip any caller-sent X-Proxy-ID header, which Zerq treats as a test-console call and leaves out of request logs.

Because the gateway trusts the forwarded certificate header, put it on a network segment only the ingress can reach.

One client per licensed fintech, with AIS and PIS separated

Model each licensed fintech as a Zerq client and each service as a collection. The licences announced so far cover account information services, so a fintech gets the AIS collection only. When payment initiation in Saudi Arabia reaches licensing for a fintech, assigning the PIS collection is one change, recorded in the audit log. A collection in draft hides all its proxies, so PIS APIs can be staged before any fintech can reach them.

Gateway settings first. With Docker Compose they go in deploy/.env; on Kubernetes, set GATEWAY_OIDC_ENABLED, GATEWAY_OIDC_ISSUER_URL, GATEWAY_OIDC_AUDIENCE, MTLS_CLIENT_CERT_HEADER and GATEWAY_ENABLE_CACHE directly in the backend environment.

GATEWAY_OIDC_ENABLED=true
# your authorization server's issuer, in-Kingdom
BACKEND_GATEWAY_OIDC_ISSUER_URL=https://auth.bank.example/realms/openbanking   # Compose maps this to GATEWAY_OIDC_ISSUER_URL
GATEWAY_OIDC_AUDIENCE=ob-resource-apis
# set by the ingress; also pass it to the backend service environment
MTLS_CLIENT_CERT_HEADER=X-SSL-Client-Cert
GATEWAY_ENABLE_CACHE=false   # the shipped default caches GET responses ahead of auth, consent workflows and logging

Then the policy, client, and profile, shown as YAML for readability; send each as a JSON request body to the management API:

# POST /api/v1/policies
name: fintech-standard
rate_limit_requests: 600
rate_limit_interval: "1m"       # fixed window
quota_requests: 3000000
quota_interval: "30d"           # resets 1st of month, 00:00 UTC
active: true
---
# POST /api/v1/clients  (one per licensed fintech)
name: fintech-aggregator-017
collections: ["<ksa-ais collection id>"]   # add PIS only once licensed
policyId: "<fintech-standard policy id>"   # shared by all active profiles
active: true
---
# POST /api/v1/clients/<clientId>/profiles
name: production
authType: oidc                       # token from your authorization server
requireCertificateBoundToken: true   # RFC 8705 binding; set via API or MCP, no UI toggle yet
allowedMethods: ["GET", "POST"]      # narrow to what the AIS specification uses
allowedIPs: []                       # Zerq sees the ingress address; enforce fintech egress ranges at the ingress
active: true

An mtls profile authenticates only the connection. Zerq does not parse the certificate or validate the access token for that auth type, so the ingress must validate the chain, and the workflow must verify the token with jwt_node in verify mode (jwks) instead of decode, or your backend must validate it. The security model covers how these checks fit together. Our TPP onboarding guide walks the same client, profile and certificate-bound token setup step by step.

Consent-shaped checks in the workflow

Zerq does not store consents: consent lives with your authorization server and consent service, where the customer granted it. The gateway's job is to refuse a call whose consent is no longer good. Open the AIS collection, click into the proxy, and choose Edit Workflow.

A practical shape: http_trigger receives the call, jwt_node in decode mode reads the already-validated token's claims for the consent reference, http_request_node asks your consent service for its status, and condition_node routes on the answer. An authorised consent continues to a proxy_node that forwards to the AIS backend; anything else ends at a response_node returning 403. Conditions are plain JavaScript over $json, so the step can also compare the requested account with the accounts the consent covers. Where the consent reference sits depends on your authorization server and the KSA API specification. The open banking use case shows the pattern. For PIS, duplicate-submission protection belongs in your payment backend; Zerq does not offer payment-grade idempotency.

Evidence: request logs, audit logs, and the auditor role

Request logs answer what a fintech did: every call with its client, profile, collection, status, latency, headers and bodies. Every field except the headers can be filtered, and bodies are searched through the payload filter. Audit logs answer who configured it: for every change to a client, profile, policy, or credential, they record the actor ID from the OIDC token, the action, the resource type, the management URL (which carries the resource ID), and the request body. Only the Auditor role sees audit logs, so compliance reviews changes it cannot make (the shipped config also maps admin into OIDC_AUDITOR_ROLES; remove it for strict separation). Request logs capture bodies, which for AIS means account data, and Zerq does not mask them, so treat that MongoDB as customer data under PDPL and enforce retention there yourself (a TTL index or archival job), since Zerq has no retention setting. The observability page shows the filters.

Restricted networks and what stays out of scope

Restricted zones can run from transferred images with pinned tags (see the air-gapped path in our UAE data residency post); air-gapped deployment carries no extra licence charge. Zerq Copilot sends tool results to whichever LLM provider you configure, so point it at a local model through Ollama or leave AI_MODELS unset.

Zerq is not your authorization server, does not run the Lab's conformance suites, holds no FAPI certification, and does not support DPoP. Your authorization server certifies against the KSA profile; Zerq enforces the resource side.

How this differs from the UAE model

The UAE routes open finance traffic through one central API Hub managed by Nebras, with a Trust Framework providing the participant directory and certificates. Saudi Arabia's public materials describe a central rulebook, technical standards, a conformance Lab, and SAMA licensing, but no central traffic hub. A Saudi bank owns more of the stack and should plan for each licensed fintech to appear as its own caller at the edge. Our UAE LFI implementation guide covers the hub model.

A readiness checklist for the API layer

  • Do you have the Framework documents and Lab access from SAMA's Open Banking Team?
  • Is your authorization server certified against the KSA FAPI profile with mTLS client authentication and PAR?
  • Has a test token shown that the gateway can verify your access tokens (JWT, RSA-signed, any client_id claim matching the Zerq client ID)?
  • Does the ingress terminate mutual TLS, forward the client certificate, and form the only path to the gateway?
  • Does the ingress strip any caller-sent X-Proxy-ID header, so every fintech call reaches the request log?
  • Does each licensed fintech have its own client, with PIS assigned only where licensed?
  • Do production profiles require certificate-bound tokens, proven by a deny test returning 401?
  • Does a revoked consent stop the call before the core sees it?
  • Does compliance hold the Auditor role on in-Kingdom logs?
  • Are the gateway, MongoDB, Redis, identity provider, and any Copilot model all inside the Kingdom?

What this looks like in practice

Illustrative scenario, not a specific customer deployment.

A Saudi bank ran its AIS APIs on an API product whose control plane sat in a vendor cloud. The consent check lived inside the AIS backend, and showing what one fintech accessed meant joining ingress logs, a vendor analytics export, and backend traces. When licensing began, the CISO asked for a diagram with every component inside the Kingdom; the vendor control plane could not be placed there.

The platform team deployed Zerq on its in-Kingdom Kubernetes cluster with its own MongoDB and Redis and pointed the gateway at the bank's FAPI authorization server. Each licensed fintech became a client with a certificate-bound OIDC profile, the AIS collection, and a policy, and the consent check moved into a workflow. A question about one fintech's week is now a request log filter on its Client ID; a question about who widened its policy is an audit log entry. The PIS collection sits in draft until payment initiation go-live.

Summary

Saudi open banking gives the bank more of the stack to own than a hub model does, plus SAMA's expectations on where all of it runs. Fintech identity, certificate binding, consent checks, limits, and evidence can all be expressed as gateway configuration that runs and is logged inside the Kingdom.


Zerq is an enterprise API gateway built for regulated industries — one platform for API management, AI agent access, compliance audit, and developer portal, running entirely in your own infrastructure. See how it works or request a demo to walk through your specific requirements.