Verification of Payee (VOP) Webhook
Introduction to VOP
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.When you initiate a SEPA transaction (e.g., via the
POST /rest/v1.0/transactions/create endpoint), our system performs this check in real-time. If the VOP verification result is anything other than a full match (MTCH), the transaction is temporarily held and receives a CREATED status.You will then receive a vop object in the transaction details. This object, which is also sent in the payload of the vop.created webhook, includes:match_type: The result of the check (e.g.,NMTCfor "No Match",CMTCfor "Close Match").recipient_matching_name: An optional field provided by the recipient's bank in case of a close match.
vop.created webhook or by calling the PATCH /rest/v1.0/transactions/update/{pid} endpoint.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.The vop Object
The vop object in the transaction response can have the following states:null: VOP is not applicable to this transaction (non-SEPA transfers).- Object with match_type: When VOP is applicable, the object contains:
- match_type (required): One of
MTCH,NMTC,CMTC, orNOAP. - recipient_matching_name (optional): For
CMTCstatus, this field may contain the suggested correct recipient name.
- match_type (required): One of
123456
{ "vop": { "match_type": "CMTC", "recipient_matching_name": "John Smith" }}VOP Transaction Flow
When a VOP check is performed and the result is anything other than
"MTCH", the transaction flow differs from a standard transaction:- The transaction is created with a CREATED status (not
CONFIRMED). - The transaction will not be processed automatically.
- A special webhook event vop.created is sent to your configured webhook endpoint.
- Your system must either respond to the webhook with an acceptance/rejection decision, or use the API endpoint to programmatically accept or reject the transaction.
"MTCH", the transaction proceeds normally to CONFIRMED status without requiring additional confirmation.Configuration Requirement: Public Key
To respond to
vop.created webhooks, you must create a signature using your private key. Narvi will use the public key that you previously uploaded to verify the authenticity of your responses.Method 1: Responding to the vop.created Webhook
This is the preferred, real-time method for handling VOP confirmations.
How It Works
- The webhook payload contains the full transaction details, including the
vopobject. - Your system must respond directly to the incoming HTTP request with a
200 OKstatus and a specific JSON body. - This response must be returned within a few seconds to avoid timeout.
Important Distinction: Response Signature vs. Webhook Verification
Note: This is different from the standard webhook signature verification process:- Standard webhook verification (as described in the Webhook Signature guide): You verify Narvi's signature using the
WEBHOOK-REQUEST-SIGNATUREheader and your webhook secret. - VOP webhook response: You create your own signature using your private key to confirm your decision to Narvi.
vop.created webhook signature as you would for any webhook. The difference is that you must also sign your response.Response Format
12345
{ "accept_vop": true, "nonce": "1678886400000", "signature": "YOUR_BASE64_ENCODED_SIGNATURE_HERE"}Generating the Response Signature
- Create the payload object (without the signature field).
- Convert to canonical JSON (RFC 7159) with keys sorted alphabetically.
- Generate SHA-256 hash of the canonical JSON string.
- Sign the hash using your private key with RSA-SHA256.
- Base64-encode the signature.
- Add the signature field and return the JSON as your 200 OK response.
Error Handling
If your endpoint returns any other response, Narvi will ignore the response and keep the transaction inCREATED status.Method 2: Confirmation via API (PATCH Endpoint)
Send a This
PATCH request to:https://api.narvi.com/rest/v1.0/transactions/update/{transaction_pid}123
{ "accept_vop": true}PATCH request must be authenticated using the standard API request signature mechanism. Generate API-REQUEST-SIGNATURE as described in the Authorization documentation.This endpoint will only work if the transaction is in CREATED status and has a vop.match_type value other than MTCH.Code Examples
12345678910111213141516171819202122232425262728293031323334353637
import base64import canonicaljsonimport timefrom cryptography.hazmat.primitives import hashes, serializationfrom cryptography.hazmat.primitives.asymmetric import paddingfrom cryptography.hazmat.backends import default_backend
private_key_pem = """-----BEGIN PRIVATE KEY-----... (Your private key here) ...-----END PRIVATE KEY-----"""
def sign_vop_response(accept_vop, nonce, private_key_pem): response_payload = { "accept_vop": accept_vop, "nonce": nonce, }
canonical_json = canonicaljson.encode_canonical_json(response_payload)
private_key = serialization.load_pem_private_key( private_key_pem.encode(), password=None, backend=default_backend() )
signature = private_key.sign(canonical_json, padding.PKCS1v15(), hashes.SHA256())
signature_b64 = base64.b64encode(signature).decode("utf-8")
return {**response_payload, "signature": signature_b64}
vop_response = sign_vop_response( accept_vop=True, nonce=str(int(time.time() * 1000)), private_key_pem=private_key_pem)
print("VOP response to send:", vop_response)Summary
- VOP checks verify recipient names on SEPA transfers.
- Non-matching results require confirmation before processing.
- Two confirmation methods: webhook response (preferred) or API PATCH endpoint.
- Upload your public key to the Developer Section; keep your private key secure.
On this page
Narvi Payments Oy Ab is an Authorized Electronic Money Institution (EMI). Narvi’s EMI license is granted by the Finnish Financial Supervisory Authority (FIN FSA) with the registration number 3190214-6. Narvi’s license is Passportised to all European Union countries.
© 2026 Narvi. All Rights Reserved.v1.298.0