Open Finance Malaysia - Data Provider Documentation Portal

Download OpenAPI specification:Download

Overview

The PayNet Open Finance Platform (OFP) enables secure, user-consented sharing of financial data between institutions. As a Data Provider, your institution sits at the heart of this ecosystem, you are the source of truth for your customers' financial data.

Party Role
Data Consumer (DC) A third-party application (e.g. a PFM or lending platform) that requests access to a user's financial data
Data Provider (DP) Your institution, you authenticate the user, obtain their consent, and return their financial data when requested
PayNet OFP The intermediary platform that orchestrates consent, authentication, and secure data exchange between DC and DP

How data flows to your institution:

Unlike a DC, which calls PayNet's APIs, as a Data Provider you primarily operate as a server that PayNet calls. PayNet OFP forwards requests to your endpoints (called webhooks) for actions like user authentication, consent notification, and data retrieval. Your responsibility is to implement these webhook endpoints correctly and respond according to the v1.2.2 specification.

PayNet OFP exposes two server components relevant to you:

  • Authorization Server (AS): manages the consent and authentication flow; your institution receives redirect webhooks and consent notifications from this component

  • Resource Server (RS): forwards data requests (accounts, balances, transactions) from DCs to your institution

Understanding the Journey

Before you start, you can simulate the User Experience as an End User starting from DC Simulator, Paynet Aggregator, and DP Simulator, for Consent Initiation up to Retrieve Balance Flow.

DP consent initiation screen

Run this Journey

  1. Access Paynet DC Simulator at https://dc-sim.uat.inet.ofm.my
  2. Start the Linking Account Process as per the UX Flow above
  3. DP Login credentials are:
    • Username: paynet
    • Password: paynet

Configuration & Pre-Requisite as a Data Provider

In this period, PayNet will support manual onboarding for participants into PayNet Open Finance Platform.

Step 1: Submit Your Security Certificates

PayNet OFP enforces financial-grade security protocols. As a DP, you are required to upload certificates for the following two protocols.

Protocol Purpose
mTLS Mutual TLS, establishes authenticated, encrypted communication between your institution and PayNet OFP
JWS JSON Web Signature, signs your API responses so PayNet and DCs can verify the data has not been tampered with

How to Submit the Certificates:

Detailed instructions on how to submit the certificates will be provided during the onboarding process.

Step 2: Register Your API Base URLs

PayNet needs to know where to send requests. You must register the base URLs for both your Authorization Server and Resource Server endpoints.

How to Submit the API Base URL:

Detailed instructions on how to submit the API Base URL will be provided during the onboarding process.

mTLS Requirements by Endpoint

All endpoints marked ✅ require Mutual TLS (mTLS). For outbound calls from your DP to PayNet, present your registered client certificate. For inbound webhook endpoints called by PayNet, your server must require and validate the client certificate presented by PayNet. Access tokens issued over mTLS are sender-constrained, so the same certificate used during token issuance must be presented on protected calls.

Endpoint Method mTLS Required Who Establishes mTLS Notes
/v1/oauth/jwks/paynet GET - Public endpoint
/v1/oauth/authorize GET PayNet -> DP Inbound webhook
/v1/oauth/userinfo GET PayNet -> DP Inbound webhook
/v1/oauth/jwks/{dc_id} GET PayNet -> DP Inbound webhook
/v1/health GET PayNet -> DP Inbound health check
/v1/consents/events POST PayNet -> DP Inbound consent webhook
/v1/accounts/{account_id} GET PayNet -> DP Inbound account webhook
/v1/accounts/{account_id}/balances GET PayNet -> DP Inbound balances webhook
/v1/accounts/{account_id}/transactions GET PayNet -> DP Inbound transactions webhook
/v1/consents/{consent_id} (Update Consent) PATCH DP -> PayNet Outbound to PayNet
/v1/consents/{consent_id} (Retrieve Consent) GET DP -> PayNet Outbound to PayNet
/v1/consents/{consent_id}/revoke POST DP -> PayNet Outbound to PayNet

What You Need to Build

User Interface Requirements

Your institution must provide a user-facing authorization interface, this is the login and consent approval page your customers see when they are redirected from a DC's application.

At minimum, this should include:

  • Login Page: where the user authenticates with their credentials
  • Account Selection Screen: where the user selects which accounts to share with the DC
  • Consent Review Screen: where the user reviews and either approves or rejects the data sharing request
  • Result Screen: confirmation or rejection message after the user makes their decision

Refer to the sample of UI mockup provided below for the expected screen flows as a Data Provider:

DP consent initiation screen

Mandatory Endpoints to Build

As a DP, your role is fundamentally different from a DC. Rather than calling APIs, you are building the APIs that PayNet will call. The table below summarises every endpoint your institution must implement.

  1. All Authorization Server Endpoints
  2. Resource Server Endpoints, for Drop 1:
    • Webhook Consent Event
    • Webhook Account Balance
    • Update Consent (DP call PayNet)

API Integration Guide

Client Authentication

For Authorization Server token issuance, PayNet OFP supports two FAPI 2.0 client authentication methods for Data Providers:

  • private_key_jwt
  • tls_client_auth (Mutual TLS / mTLS)

Method 1: private_key_jwt

Use these parameters when requesting tokens with JWT client authentication.

Parameter Required Description
client_assertion_type Must be urn:ietf:params:oauth:client-assertion-type:jwt-bearer
client_id Registered Data Provider Client ID
client_assertion Signed JWS client assertion

The signed JWS must comply with the following structure.

JWS Header

Element Required Description
alg Must be PS256
kid Base64url-encoded SHA-256 thumbprint (x5t#S256) of your X.509 certificate

JWS Body (Claims)

Claim Required Description
iss Client ID
sub Client ID
aud Authorization Server issuer value from /.well-known/openid-configuration
exp Expiry Unix timestamp (maximum 10 minutes from iat)
iat Issued-at Unix timestamp
jti Unique JWT ID used to prevent replay attacks
nbf Optional Not-before Unix timestamp

Method 2: tls_client_auth

When using mTLS client authentication, your DP establishes mTLS and includes:

Parameter Required Description
client_id Registered Data Provider ID

Endpoint Authentication Summary (DP)

DP → PayNet OFP (Outbound)

Endpoint Auth Required Notes
GET /v1/oauth/jwks ❌ Not Required Public endpoint
OST /token (client credentials) ✅ Required private_key_jwt or tls_client_auth — to obtain client access token
POST /v1/consents/{consent_id} (Update Consent) ❌ Not required at AS level Authenticated via Bearer client access token in Authorization header
GET /v1/consents/{consent_id} (Retrieve Consent) ❌ Not required at AS level Authenticated via Bearer client access token
POST /v1/consents/{consent_id}/revoke (Consent LCM) ❌ Not required at AS level Authenticated via Bearer client access token

PayNet OFP → DP (Inbound Webhooks)

Endpoint Auth Required Notes
GET /v1/oauth/authorize (Webhook Authorization) ❌ Not Required PN presents signature in query param
GET /v1/oauth/userinfo (Webhook User Info) ❌ Not required Protected by mTLS from OFP
GET /v1/health (Health Check) ❌ Not required Called by OFP
POST /v1/consents/events (Consent Event) ❌ Not required Protected by mTLS; DP must verify JWS signature with PN cert
GET /v1/accounts/* (Account Webhooks) ❌ Not required Protected by mTLS; DP must verify JWS x-signature with DC cert

Important for DP webhook endpoints: While these endpoints do not require outbound client authentication by the DP, the DP must protect all webhook endpoints with Mutual TLS and validate the incoming JWS signature using the appropriate certificate (PN cert for consent events; DC cert for account webhooks).

Serving Financial Data (Resource Webhooks)

Once a user has approved consent, a DC can request financial data through PayNet. PayNet forwards these requests to your institution's Resource Server webhooks. Your institution must retrieve the relevant data, encrypt it using the DC's JWE certificate, and return it wrapped inside a JWS-signed response.

Sequence Overview

DP Sequence Overview

Account Balances Webhook

POST https://{DP_URL}/v1/accounts/{account_id}/balances

PayNet forwards a balance request from a DC. Your institution must:

  1. Validate the incoming JWS signature on the request (signed by PayNet using your institution's cert kid)
  2. Look up the balance for the account_id
  3. Encrypt the balance data using the DC's encryption certificate (x-enc-kid)
  4. Return the encrypted payload wrapped in a JWS

Balance data to return:

Field Description
account_id The unique account identifier assigned during authorization
current_balance Real-time balance excluding pending transactions

🔒 This is the request from PayNet to your DP which must be made over mTLS using the certificate bound to your client_id.

curl --location --request GET \
  'https://{DP_URL}/v1/accounts/acc-550e8400-e29b-41d4-a716-446655440010/balances?consent_id=550e8400-e29b-41d4-a716-446655440001' \
  --cert /path/to/paynet-client.crt \
  --key /path/to/paynet-client.key \
  --cacert /path/to/ca.crt \
  --header 'x-fapi-interaction-id: 550e8400-e29b-41d4-a716-446655440000' \
  --header 'x-enc-kid: <base64url-SHA256-thumbprint-of-DC-cert>' \
  --header 'x-fapi-signature: eyJhbGciOiJQUzI1NiIsImtpZCI6IkFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2g....<JWS_COMPACT_SERIALIZATION>'

💡 The same request-validation and JWS-wrapped JWE response pattern applies to the Account and Account Transactions webhooks. Refer to the full DP API Spec v1.2.2 for the complete field definitions.

Security

This section applies to Data Consumers and Data Providers. It summarizes certificate usage, mTLS requirements, message signing, and security-related HTTP headers.

Certificates

Certificate Type Description
PN Signature Certificate PayNet signs payloads; receivers verify using PayNet public key from JWKS (use = sig).
DC Signature Certificate DC signs applicable requests; receivers verify using DC public key from JWKS (use = sig).
DP Signature Certificate DP signs responses; receivers verify using DP public key from JWKS (use = sig).
DC Encryption Certificate DP encrypts payloads for DC using x-enc-kid; DC decrypts with matching private key (use = enc).

During certificate rotation, old and new keys may coexist with different kid values. Cache JWKS responses for up to 15 minutes.

Mutual TLS (mTLS)

mTLS is mandatory for protected integration paths.

  • Outbound DP calls to PayNet must present your registered client certificate.
  • Inbound webhook calls from PayNet must be protected by server-side mTLS certificate validation.
  • Sender-constrained tokens require using the same certificate across token issuance and protected API calls.

mTLS Requirements by Endpoint (DP)

Endpoint Method mTLS Required Caller Direction
/v1/oauth/jwks/paynet GET Public
/v1/oauth/authorize GET PayNet -> DP
/v1/oauth/userinfo GET PayNet -> DP
/v1/oauth/jwks/{dc_id} GET PayNet -> DP
/v1/health GET PayNet -> DP
/v1/consents/events POST PayNet -> DP
/v1/accounts/{account_id} GET PayNet -> DP
/v1/accounts/{account_id}/balances GET PayNet -> DP
/v1/accounts/{account_id}/transactions GET PayNet -> DP
/v1/consents/{consent_id} PATCH DP -> PayNet
/v1/consents/{consent_id} GET DP -> PayNet
/v1/consents/{consent_id}/revoke POST DP -> PayNet

JWS Message Signing

JWS protects message integrity and provides non-repudiation.

  • Use PS256 for signatures.
  • Set kid to the certificate thumbprint (x5t#S256) used to sign payloads.
  • Validate iat/nbf/exp and replay-sensitive jti.

Relevant HTTP Headers

Header Purpose
x-signature JWS signature for message integrity and verification.
x-enc-kid Indicates DC encryption key for DP response payload encryption.
x-fapi-interaction-id Correlation ID for end-to-end tracing and troubleshooting.
Authorization Bearer access token for protected endpoints.
Content-Type application/jwt for JWS payloads (and JWE-wrapped response content when applicable).

Testing Guide

Test Your DP Against Mock Data Consumer

This is your primary integration test which will be initiated from Mock Data Consumer.

Pre-work Checklist

Before signalling readiness to test, confirm the following:

  • All prerequisites steps are complete (certificates uploaded, base URLs registered)
  • All mandatory webhook endpoints are implemented and accessible
  • Your authorization UI (login, account selection, consent approval) is functional
  • Your endpoints are protected by mTLS and return correctly signed/encrypted responses

Backend Initiated Test

  1. Inform PayNet that your DP implementation is ready for testing. PayNet will coordinate directly with you to initiate the test.
  2. PayNet will share a PyTest suite to initiate DC call with mock DC credentials setup
  3. Update the API Base URL and Certificates to direct PayNet OFP calls into your DP

End-to-End Test Journey

The following table describes each step of the test, which party drives it, and the expected outcomes as per UI, Backend API, and API Integration Guide in the previous sections. You can focus on the bold rows for your DP testing purpose.

Step Actor Action UI Expected Outcome DP Backend Expected Outcome
1 Mock DC User navigates to the account linking screen Linking screen displayed -
2 Mock DC User selects a Data Provider from the list DP selection -
3 Mock DC User reviews consent details on DC UI Consent review screen displayed as per request -
4 Mock DC User confirms and submits consent User is redirected to Mock DP UI -
5 Real DP User is redirected to the Mock DP login page Mock DP login screen displayed Expose: /consents/events and /authorize
6a Real DP User logs in with valid preset credentials (positive) Login succeeds; account selection screen displayed DP internal implementation
6b Real DP User enters incorrect password (negative) Login fails; error message displayed DP internal implementation
7 Real DP User selects one or more accounts to link Accounts selected DP internal implementation
8 Real DP User reviews consent at the DP side Consent review screen displayed DP internal implementation
9a Real DP User approves consent (positive) User redirected to DP success page Call Update Consent consents/{consent_id} with positive status
9b Real DP User rejects consent (negative) User redirected back to DC with rejection error Call Update Consent consents/{consent_id} with negative status
10 Real DP User gets Success confirmation and click Back to DC User redirected back to DC with authorization_code -
11a Mock DC Consent approved callback received DC retrieves and displays account balance Expose /balance
11b Mock DC Consent rejected callback received DC displays "Account not linked" message to user -

Definition of Done

Your build is considered complete for this phase when all of the following have been demonstrated with your Certificates and Base URL setup:

  • Consent handled successfully: Your DP exposes the Consent Event endpoint (POST /v1/consents/events), validates the incoming JWS signature, and returns the correct response
  • User authenticated properly: Your DP exposes the Authorize endpoint (GET /v1/oauth/authorize), and your end user is correctly redirected through the DP authentication flow through to the point of consent approval or rejection
  • PayNet updated: Your DP calls Update Consent (PATCH /v1/consents/{consent_id}) to PayNet appropriately, with a positive status on approval and a negative status on rejection
  • Resource API functional: Your DP's Get Balance endpoint (GET /v1/accounts/{account_id}/balances) is functional and returns the correct encrypted and signed response

Test Your DP Against a Real Data Consumer

This phase verifies interoperability between your institution and a live DC in a controlled bilateral pairing session.

⚠️ Prerequisite: Your institution must have **passed all tests as a DP** before this phase can begin.

How to proceed:

Contact PayNet to schedule a bilateral testing session with a Real DC. PayNet will identify a suitable DC partner, facilitate the pairing, and provide guidance on the specific scenarios to execute together.

Error Codes

HTTP Status Codes

Code Description
200 OK
201 Created
204 No Content
303 Redirect
400 Bad Request
401 Unauthorized
403 Forbidden
404 Not Found
405 Method Not Allowed
429 Too Many Requests
500 Internal Server Error
503 Service Unavailable

OAuth 2.0 Error Codes

Returned in error responses from authorization and token endpoints.

Code Description
invalid_request Missing or invalid parameter.
invalid_client Client authentication failed.
invalid_grant Invalid, expired, or revoked grant/code.
unauthorized_client Client not authorized for this grant type.
unsupported_grant_type Grant type not supported.
access_denied Resource owner or AS denied the request.
invalid_scope Invalid or unknown scope.
server_error Unexpected server-side condition.
temporarily_unavailable Server overloaded or in maintenance.

Account & Application Error Codes

Code Description
Consent.AccountTemporarilyBlocked Account temporarily blocked by DP business rule.
Consent.PermanentAccountAccessFailure Account permanently unavailable.
Consent.TransientAccountAccessFailure Account unavailable due to transient failure.
AccessToken.InvalidScope Token does not have required scope.
Consent.Invalid Consent is in an invalid state.
Consent.BusinessRuleViolation DP business rule prevents the operation.
JWS.InvalidSignature JWS signature verification failed.
JWS.InvalidClaim One or more JWS claims failed validation.
JWE.DecryptionError JWE decryption failure.

Error Response Format

Error Response Body

{
  "error": "invalid_grant",
  "error_description": "The authorization code has expired."
}

Authorization Server

Webhook – Authorization

Invoked by PN (PayNet) to obtain authorization; DP responds with 303 redirect.

query Parameters
consent_id
required
string <= 36 characters

Unique identification as assigned to identify the consent.

redirect_uri
required
string <= 300 characters

PN redirection URI to which the response will be sent.

signature
required
string

JWS message signing (JWS) signed by PN private key with consent_id as the jws-payload.

Responses

JSON Web Key Set (PayNet)

Returns the JSON Web Key Set for PayNet.

Responses

Response samples

Content type
application/json
{
  • "keys": [
    ]
}

JSON Web Key Set (DC)

Returns the JSON Web Key Set for the given Distribution Partner (DC).

path Parameters
dc_id
required
string

Distribution Partner (DC) identifier

Responses

Response samples

Content type
application/json
{
  • "keys": [
    ]
}

Webhook – User Info

Invoked by the AS to retrieve end-user info.

query Parameters
consent_id
required
string

Unique identification as assigned to identify the consent.

header Parameters
x-fapi-signature
required
string

JWS message signing (JWS) compact serialization detached signed by sender's private key.

x-fapi-interaction-id
required
string <uuid>

An UUID used as a correlation id.

Responses

Response samples

Content type
application/json
{
  • "sub": "string",
  • "name": "string",
  • "given_name": "string",
  • "family_name": "string",
  • "preferred_username": "string",
  • "picture": "string",
  • "email": "string",
  • "email_verified": true,
  • "id_type": "nric",
  • "hashed_id_number": "string"
}

Resource Server

Account Balances

PayNet retrieves an account balances information from DP.

path Parameters
account_id
required
string

AccountID is the account identifier (path).

Responses

Response samples

Content type
application/json
{
  • "status": "string",
  • "error_message": "string",
  • "data": "string"
}

Consent Event

Description: PayNet notifies DP when consent is created or updated.

Request Body schema: application/json
event_type
string
Default: "consent_event_type_unspecified"
Enum: "consent_event_type_unspecified" "consent_created" "consent_updated" "consent_status_updated"

EventType is the consent event type (PayNet section 13).

object

Data is the consent object.

Responses

Request samples

Content type
application/json
{
  • "event_type": "consent_event_type_unspecified",
  • "data": {
    }
}

Response samples

Content type
application/json
{ }

Update Consent

DP updates consent status and user info after the user authorizes the consent.

path Parameters
consent_id
required
string

ConsentID is the consent identifier (from path parameter).

Request Body schema: application/json
consent_id
string

ConsentID is the consent identifier (from path parameter).

status
string

Status is the consent status (32 chars, required).

id_token
string

IDToken is the JWT issued by the Data Provider (3000 chars, required if status = Authorized).

object

UserIdentity is the user identity object (required if status = Authorized).

Array of objects

Accounts is the list of consent account objects (required if status = Authorized).

object

StatusReason is required when status is Rejected (§13). Omit when status is Authorized.

Responses

Request samples

Content type
application/json
{
  • "consent_id": "string",
  • "status": "string",
  • "id_token": "string",
  • "user_identity": {
    },
  • "accounts": [
    ],
  • "status_reason": {
    }
}

Response samples

Content type
application/json
{ }