Business Banking API documentation
Download OpenAPI specification:Download
We use cryptographic signature to authorize API requests.
To configure your API keys for selected entity please login to our banking app Developer Section.
You have to configure your whitelisted IPs and public key which will be used for request signature verification.
Do not share your private key with anybody. We never asks you for private key.
Please note that we use api.narvi.com fully qualified domain to interact with your integration. All your api requests should use this domain to communicate with our REST API.
Each request needs to have the following headers:
- API-KEY-ID - api key id gathered from configured api key Developer Section
- API-REQUEST-ID - valid UUID or timestamp, can't be duplicated across requests
- API-REQUEST-SIGNATURE - request signature
API-REQUEST-ID (Request ID)
- valid UUID or timestamp,
- it can't be duplicated across requests
API-REQUEST-SIGNATURE (Request signature) Request signature is the signature of sha256 of the concatenated following items (request descriptor)
- the absolute request url without query params (e.g. http://api.narvi.com/rest/v1.0/transactions/create)
- the uppercase request method (e.g. POST, GET, PUT, DELETE)
- request ID - valid UUID, can't be duplicated across requests
- query params encoded in JSON canonical form - RFC 7159 JSON (The order of JSON key-value pairs is very important. Please double-check that it is in the correct canonical form. All query parameters keys and values must have the string type. Use an empty string instead if there are no query parameters).
- payload encoded in JSON canonical form - RFC 7159 JSON (The order of JSON key-value pairs is very important. Please double-check that it is in the correct canonical form. Use an empty string instead if there is no payload).
- if payload contains file object use sha256 of the file content to create payload canonical form for request descriptor
Signature example For GET request https://api.narvi.com/?account_pid=KFGKJ5L27ASGTZAO&kind=CREDIT the signature should be created as follow:
- generate a request ID: e.g. da43520e-800b-41c5-a4a9-7287a64c87fa (valid UUID, can't be duplicated across requests)
- generate request descriptor: https://api.narvi.com/rest/v1.0/transactions/listGET1693416230449{"\account_pid":"KFGKJ5L27ASGTZAO","kind":"CREDIT"}
- generate sha256 of the request descriptor
- generate signature with hashing algorithm sha256 of the generated sha256 above
- encode the signature with base64
For POST request https://api.narvi.com/rest/v1.0/transactions/create with the payload {"account_pid": "KFGKJ5L27ASGTZAO" ,"recipient": {"name": "John Doe", "number": "FI8379600186405354" ,"bic": "NARIFXX", "country": "FI"}, "currency": "EUR","amount": 100, "remittance_information":{"ustrd": "test transfer"}} the signature should be created as follow:
- generate a request ID: e.g. da43520e-800b-41c5-a4a9-7287a64c87fa (valid UUID, can't be duplicated across requests)
- generate request descriptor: https://api.narvi.com/rest/v1.0/transactions/createPOST1693416796324{"account_pid":"KFGKJ5L27ASGTZAO","amount":"100","currency":"EUR","recipient":{"bic":"NARIFXX","country":"FI","name":"John Doe","number":"FI8379600186405354"},"remittance_information":{"ustrd":"test transfer"}}
- generate sha256 of the request descriptor
- generate signature with hashing algorithm sha256 of the generated sha256 above
- encode the signature with base64
To enable webhooks, please login to Developer Section and configure webhook endpoints for selected entity. After you enable them, we will push real-time event data to your application's webhook endpoint when events happen in your banking account. We use HTTPS to send webhook events to your app as a JSON payload that includes an Event object.
We attempt to deliver the event to your webhook endpoint for up to 3 days with an exponential back off. In the log section of the Dashboard, you can view when the next retry will occur. If your endpoint has been disabled or deleted when we attempt a retry, future retries are cancelled.
Your endpoint must quickly return a successful status code (2xx) prior to any complex logic that could cause a timeout. For example, you must return a 200 response before updating a customer’s balance.
HTTP payloads that are delivered to your webhook's configured URL endpoint will contain several special headers:
- USER-AGENT - always equal 'webhook'
- WEBHOOK-REQUEST-TIMESTAMP - timestamp in millisecond when webhook action occured
- WEBHOOK-REQUEST-EVENT-TYPE - the event type
- WEBHOOK-REQUEST-EVENT-PID - event public id
- WEBHOOK-REQUEST-SIGNATURE - This is the sha256 hex digest of the request body and parameters
Webhook signature must be checked by integrated application before processing the webhook data.
Webhook signature is the sha256 hex digest of the concatenated following items (request descriptor)
- the absolute webhook endpoint without query params (e.g. https://example.com/webhook/handler)
- the uppercase request method (e.g. POST, GET, PUT, DELETE)
- current timestamp in microseconds (taken from request header WEBHOOK-REQUEST-TIMESTAMP)
- event type (taken from request header WEBHOOK-REQUEST-EVENT-TYPE)
- event public id (taken from request header WEBHOOK-REQUEST-EVENT-PID)
- query params encoded in JSON canonical form - RFC 7159 JSON (The order of JSON key-value pairs is very important. Please double-check that it is in the correct canonical form. All query parameters keys and values must have the string type. Use an empty string instead if there are no query parameters).
- payload encoded in JSON canonical form - RFC 7159 JSON (The order of JSON key-value pairs is very important. Please double-check that it is in the correct canonical form. Use an empty string instead if there is no payload).
- webhook secret taken from developer panel
Verification of Payee (VOP) is a mechanism that checks if the recipient's name on a SEPA transfer matches the details held by the recipient's bank. This helps prevent payment fraud and misdirected payments by verifying the account holder's name before the transaction is processed.
The VOP scheme and its technical specifications are defined by the European Payments Council (EPC). The official scheme documentation can be found here: Verification Of Payee Scheme Inter-PSP API Specifications.
VOP Transaction Flow
When you initiate a SEPA transaction (e.g., via POST https://api.narvi.com/rest/v1.0/transactions/create), a VOP check is performed. Transaction object
now has vop field which contains the result of the check:
null: VOP was not applicable to this transaction (e.g., non-SEPA transfers).- Object: When VOP is applicable, the object contains:
match_type(required): One of the following values:"MTCH": (Match) The recipient name exactly matches the bank's records."NMTC": (No Match) The recipient name does not match."CMTC": (Close Match) The recipient name is similar but not identical."NOAP": (Not Applicable) VOP could not be performed by the recipient's bank.
recipient_matching_name(optional): ForCMTCstatus, this field may contain the suggested correct recipient name from the bank's records.
Example vop object:
{
"vop": {
"match_type": "CMTC",
"recipient_matching_name": "John Smith"
}
}
If the result is a perfect match ("MTCH"), the transaction proceeds to CONFIRMED status as normal.
However, if the VOP result is not a match ("NMTC", "CMTC", or "NOAP"), the flow is interrupted and requires your action:
- The transaction is created with a
CREATEDstatus (notCONFIRMED). - The transaction will not be processed until it is confirmed or canceled.
- A
vop.createdwebhook event is sent to your configured endpoint. - Your system must then approve or reject the transaction using one of two methods described below.
Method 1: Respond to the vop.created Webhook (Recommended)
This is the primary method for handling VOP-pending transactions. You must respond directly to the webhook request with a 200 OK status and a specific, signed JSON body.
Configuration
To use this method, you must first upload your public key in the Developer Section. We will use this key to verify the signature of your response.
Note: This is different from the standard webhook signature verification.
- You verify our incoming webhooks using the
WEBHOOK-REQUEST-SIGNATUREheader and your Webhook Secret. - You sign your response to the
vop.createdwebhook using your private key.
Response Body
Your response must be a JSON object containing accept_vop, nonce, and signature.
accept_vop(boolean):trueto accept the VOP findings and proceed with the transaction.falseto cancel the transaction.nonce(string): A unique identifier for this response (e.g., a timestamp or UUID) to prevent replay attacks.signature(string): The Base64-encoded RSA-SHA256 signature.
Important: If your response body is empty, improperly formatted, or has an invalid signature, it will be ignored. The transaction will remain in CREATED status.
Response Signature Generation
To generate the signature:
- Create the JSON payload without the signature field:
{ "accept_vop": true, "nonce": "1678886400000" } - Convert this object to its canonical JSON string representation (RFC 7159, keys sorted alphabetically).
- Generate a SHA-256 hash of the canonical JSON string.
- Sign the resulting hash using your private key with the RSA-SHA256 algorithm.
- Base64-encode the binary signature.
- Add this Base64-encoded string as the
signaturevalue to your JSON payload.
Final JSON Response Body:
{
"accept_vop": true,
"nonce": "1678886400000",
"signature": "YOUR_BASE64_ENCODED_SIGNATURE_HERE"
}
Method 2: Use the Update Transaction API Endpoint
As an alternative, or if your webhook response fails, you can programmatically approve or reject the transaction by calling:
PATCH /rest/v1.0/transactions/update/{pid}
This endpoint uses standard API authentication (as described in the Authorization tag).
To confirm or cancel the transaction, send the following payload:
{
"accept_vop": true
}
accept_vop(boolean):trueto approve,falseto cancel.- This operation is only valid while the transaction is in the
CREATEDstatus.
Retrieve Account Details
Retrieves Account details
path Parameters
| pid required | string A unique value identifying this sepa account. |
Responses
Response samples
- 200
{- "pid": "KFGKJ5L27ASGTZAO",
- "number": "FI2279600000000000",
- "balance": 9997246,
- "currency": "EUR",
- "name": "EUR Account",
- "kind": "PRIVATE"
}List User Accounts
Returns paginated list of user accounts.
query Parameters
| cursor | string The pagination cursor value. |
Responses
Response samples
- 200
{- "next": "string",
- "previous": "string",
- "results": [
- {
- "pid": "KFGKJ5L27ASGTZAO",
- "number": "FI2279600000000000",
- "balance": 9997246,
- "currency": "EUR",
- "name": "EUR Account",
- "kind": "PRIVATE"
}
]
}Create Transaction
Create User Transaction. If the transaction is for a SEPA payment and results in a Verification of Payee (VOP) status other than 'MTCH', the transaction will be created with a 'CREATED' status and await confirmation via the vop.created webhook or the PATCH /rest/v1.0/transactions/update/{pid} endpoint. Otherwise, it will proceed to 'CONFIRMED' status as usual.
Request Body schema:
| account_pid required | string Account public id. |
| amount required | integer >= 0 Transaction amount in cents. |
| currency required | string Value: "EUR" |
required | object |
required | object Remittance information object. |
Responses
Request samples
- Payload
{- "account_pid": "KFGKJ5L27ASGTZAO",
- "amount": 100,
- "currency": "EUR",
- "recipient": {
- "number": "DK5000400440116243",
- "name": "Thoma Navn",
- "address": "Byvej 2A, 1. tv 0012",
- "city": "Tune",
- "zip_code": "4000",
- "country": "string"
}, - "remittance_information": {
- "ustrd": "Testing transaction"
}
}Response samples
- 201
{- "pid": "UXNZ6IWJ2JESLXP3",
- "account_pid": "KFGKJ5L27ASGTZAO",
- "amount": 1485,
- "fee": 15,
- "currency": "EUR",
- "added": "1698062541.845098",
- "sender": {
- "number": "PL69291000060000000000039586",
- "name": "John Doe",
- "address": "Przylaszczkowa 148",
- "city": "Warsaw",
- "zip_code": "string",
- "country": "string"
}, - "recipient": {
- "number": "FI2279600000000000",
- "name": "Sara Conor",
- "address": "",
- "city": "",
- "zip_code": "",
- "country": "string"
}, - "remittance_information": {
- "ustrd": "INV202350"
}, - "source": "WEB",
- "kind": "CREDIT",
- "status": "DONE",
- "vop": {
- "match_type": "MTCH",
- "recipient_matching_name": "string"
}, - "orgnl_tx": {
- "rjct_reason_cd": "AC04",
- "rjct_reason": "Account number specified has been closed",
- "pid": "UXNZ6IWJ2JESLXP3"
}
}Retrieve Transaction Details
Returns transaction details.
path Parameters
| pid required | string |
Responses
Response samples
- 200
{- "pid": "UXNZ6IWJ2JESLXP3",
- "account_pid": "KFGKJ5L27ASGTZAO",
- "amount": 1485,
- "fee": 15,
- "currency": "EUR",
- "added": "1698062541.845098",
- "sender": {
- "number": "PL69291000060000000000039586",
- "name": "John Doe",
- "address": "Przylaszczkowa 148",
- "city": "Warsaw",
- "zip_code": "string",
- "country": "string"
}, - "recipient": {
- "number": "FI2279600000000000",
- "name": "Sara Conor",
- "address": "",
- "city": "",
- "zip_code": "",
- "country": "string"
}, - "remittance_information": {
- "ustrd": "INV202350"
}, - "source": "WEB",
- "kind": "CREDIT",
- "status": "DONE",
- "vop": {
- "match_type": "MTCH",
- "recipient_matching_name": "string"
}, - "orgnl_tx": {
- "rjct_reason_cd": "AC04",
- "rjct_reason": "Account number specified has been closed",
- "pid": "UXNZ6IWJ2JESLXP3"
}
}List Account Transactions
Returns paginated list of transactions for specific account with account_pid.
query Parameters
| cursor | string The pagination cursor value. |
| account_pid required | string Account public id. |
| kind | string Enum: "CREDIT" "DEBIT" "FEE" kind |
| added__lte | string Transaction added timestamp filter (in milliseconds). |
| added__gte | string Transaction added timestamp filter (in milliseconds). |
Responses
Response samples
- 200
{- "next": "string",
- "previous": "string",
- "results": [
- {
- "pid": "UXNZ6IWJ2JESLXP3",
- "account_pid": "KFGKJ5L27ASGTZAO",
- "amount": 1485,
- "fee": 15,
- "currency": "EUR",
- "added": "1698062541.845098",
- "sender": {
- "number": "PL69291000060000000000039586",
- "name": "John Doe",
- "address": "Przylaszczkowa 148",
- "city": "Warsaw",
- "zip_code": "string",
- "country": "string"
}, - "recipient": {
- "number": "FI2279600000000000",
- "name": "Sara Conor",
- "address": "",
- "city": "",
- "zip_code": "",
- "country": "string"
}, - "remittance_information": {
- "ustrd": "INV202350"
}, - "source": "WEB",
- "kind": "CREDIT",
- "status": "DONE",
- "vop": {
- "match_type": "MTCH",
- "recipient_matching_name": "string"
}, - "orgnl_tx": {
- "rjct_reason_cd": "AC04",
- "rjct_reason": "Account number specified has been closed",
- "pid": "UXNZ6IWJ2JESLXP3"
}
}
]
}Update Transaction
Update properties of a transaction. This endpoint can be used to programmatically accept or reject a transaction pending VOP confirmation. This action is only possible if the transaction is in 'CREATED' status and has a VOP match_type other than 'MTCH'.
path Parameters
| pid required | string The public ID of the transaction to update. |
Request Body schema: application/json
| accept_vop | boolean Set to 'true' to accept the VOP result and proceed with the transaction, or 'false' to cancel it. |
Responses
Request samples
- Payload
{- "accept_vop": true
}Response samples
- 200
{- "pid": "UXNZ6IWJ2JESLXP3",
- "account_pid": "KFGKJ5L27ASGTZAO",
- "amount": 1485,
- "fee": 15,
- "currency": "EUR",
- "added": "1698062541.845098",
- "sender": {
- "number": "PL69291000060000000000039586",
- "name": "John Doe",
- "address": "Przylaszczkowa 148",
- "city": "Warsaw",
- "zip_code": "string",
- "country": "string"
}, - "recipient": {
- "number": "FI2279600000000000",
- "name": "Sara Conor",
- "address": "",
- "city": "",
- "zip_code": "",
- "country": "string"
}, - "remittance_information": {
- "ustrd": "INV202350"
}, - "source": "WEB",
- "kind": "CREDIT",
- "status": "DONE",
- "vop": {
- "match_type": "MTCH",
- "recipient_matching_name": "string"
}, - "orgnl_tx": {
- "rjct_reason_cd": "AC04",
- "rjct_reason": "Account number specified has been closed",
- "pid": "UXNZ6IWJ2JESLXP3"
}
}transaction.created Webhook
Request Body schema: application/json
Occurs when transaction is created in the system.
| pid required | string |
| account_pid required | string Account public id. |
| amount required | integer >= 0 Transaction amount in cents. |
| fee required | integer |
| currency required | string Value: "EUR" |
| added required | string <date-time> |
object or null May be null for returned or fee transactions. | |
object or null May be null for fee transactions. | |
required | object Remittance information object. |
| source required | string Enum: "WEB" "APP" "ACCOUNT_API" "BAAS_API" "CARD" |
| kind required | string Enum: "CREDIT" "DEBIT" "FEE" |
| status required | string Enum: "PENDING" "DONE" "REJECTED" "CANCELLED" |
object or null Verification of Payee (VOP) check result. Null if VOP is not applicable. | |
object or null Information about original transaction in case this is a returned/rejected transaction. Null if not applicable. |
Responses
Request samples
- Payload
{- "pid": "UXNZ6IWJ2JESLXP3",
- "account_pid": "KFGKJ5L27ASGTZAO",
- "amount": 1485,
- "fee": 15,
- "currency": "EUR",
- "added": "1698062541.845098",
- "sender": {
- "number": "PL69291000060000000000039586",
- "name": "John Doe",
- "address": "Przylaszczkowa 148",
- "city": "Warsaw",
- "zip_code": "string",
- "country": "string"
}, - "recipient": {
- "number": "FI2279600000000000",
- "name": "Sara Conor",
- "address": "",
- "city": "",
- "zip_code": "",
- "country": "string"
}, - "remittance_information": {
- "ustrd": "INV202350"
}, - "source": "WEB",
- "kind": "CREDIT",
- "status": "DONE",
- "vop": {
- "match_type": "MTCH",
- "recipient_matching_name": "string"
}, - "orgnl_tx": {
- "rjct_reason_cd": "AC04",
- "rjct_reason": "Account number specified has been closed",
- "pid": "UXNZ6IWJ2JESLXP3"
}
}transaction.updated Webhook
Request Body schema: application/json
Occurs when a transaction status updated.
| pid required | string |
| account_pid required | string Account public id. |
| amount required | integer >= 0 Transaction amount in cents. |
| fee required | integer |
| currency required | string Value: "EUR" |
| added required | string <date-time> |
object or null May be null for returned or fee transactions. | |
object or null May be null for fee transactions. | |
required | object Remittance information object. |
| source required | string Enum: "WEB" "APP" "ACCOUNT_API" "BAAS_API" "CARD" |
| kind required | string Enum: "CREDIT" "DEBIT" "FEE" |
| status required | string Enum: "PENDING" "DONE" "REJECTED" "CANCELLED" |
object or null Verification of Payee (VOP) check result. Null if VOP is not applicable. | |
object or null Information about original transaction in case this is a returned/rejected transaction. Null if not applicable. |
Responses
Request samples
- Payload
{- "pid": "UXNZ6IWJ2JESLXP3",
- "account_pid": "KFGKJ5L27ASGTZAO",
- "amount": 1485,
- "fee": 15,
- "currency": "EUR",
- "added": "1698062541.845098",
- "sender": {
- "number": "PL69291000060000000000039586",
- "name": "John Doe",
- "address": "Przylaszczkowa 148",
- "city": "Warsaw",
- "zip_code": "string",
- "country": "string"
}, - "recipient": {
- "number": "FI2279600000000000",
- "name": "Sara Conor",
- "address": "",
- "city": "",
- "zip_code": "",
- "country": "string"
}, - "remittance_information": {
- "ustrd": "INV202350"
}, - "source": "WEB",
- "kind": "CREDIT",
- "status": "DONE",
- "vop": {
- "match_type": "MTCH",
- "recipient_matching_name": "string"
}, - "orgnl_tx": {
- "rjct_reason_cd": "AC04",
- "rjct_reason": "Account number specified has been closed",
- "pid": "UXNZ6IWJ2JESLXP3"
}
}vop.created Webhook
Request Body schema: application/json
Occurs when a transaction is created and requires Verification of Payee (VOP) confirmation.
| pid required | string |
| account_pid required | string Account public id. |
| amount required | integer >= 0 Transaction amount in cents. |
| fee required | integer |
| currency required | string Value: "EUR" |
| added required | string <date-time> |
object or null May be null for returned or fee transactions. | |
object or null May be null for fee transactions. | |
required | object Remittance information object. |
| source required | string Enum: "WEB" "APP" "ACCOUNT_API" "BAAS_API" "CARD" |
| kind required | string Enum: "CREDIT" "DEBIT" "FEE" |
| status required | string Enum: "PENDING" "DONE" "REJECTED" "CANCELLED" |
object or null Verification of Payee (VOP) check result. Null if VOP is not applicable. | |
object or null Information about original transaction in case this is a returned/rejected transaction. Null if not applicable. |
Responses
Request samples
- Payload
{- "pid": "UXNZ6IWJ2JESLXP3",
- "account_pid": "KFGKJ5L27ASGTZAO",
- "amount": 1485,
- "fee": 15,
- "currency": "EUR",
- "added": "1698062541.845098",
- "sender": {
- "number": "PL69291000060000000000039586",
- "name": "John Doe",
- "address": "Przylaszczkowa 148",
- "city": "Warsaw",
- "zip_code": "string",
- "country": "string"
}, - "recipient": {
- "number": "FI2279600000000000",
- "name": "Sara Conor",
- "address": "",
- "city": "",
- "zip_code": "",
- "country": "string"
}, - "remittance_information": {
- "ustrd": "INV202350"
}, - "source": "WEB",
- "kind": "CREDIT",
- "status": "DONE",
- "vop": {
- "match_type": "MTCH",
- "recipient_matching_name": "string"
}, - "orgnl_tx": {
- "rjct_reason_cd": "AC04",
- "rjct_reason": "Account number specified has been closed",
- "pid": "UXNZ6IWJ2JESLXP3"
}
}Response samples
- 200
{- "accept_vop": true,
- "nonce": "string",
- "signature": "string"
}