Skip to main content
Automating payments, such as supplier payouts, salary payments, or refunds to eliminate manual processing time and reduces the risk of human error. In this guide, we will list beneficiaries to find the right recipient, verify the payee identity through the Verification of Payee (VoP) service, and submit the transfer.
Example: A freelance management platform automatically pays contractors every Friday based on approved timesheets, without anyone logging into Qonto manually.
Prerequisites:
  • At least one beneficiary with status: validated.
  • Scopes: organization.read, payment.write
Beneficiaries can only be trusted through the Qonto web app, unless you are are an Embed partner with the beneficary.trust scope. Learn more about sensitive scopes.
1

List SEPA beneficiaries

Retrieve the list of validated beneficiaries and find the one you want to pay. You can filter by IBAN or name to narrow down the results.Endpoint: List SEPA beneficiaries
OAuth scope required: organization.read
import requests

BASE_URL = "https://thirdparty.qonto.com/v2"
headers = {"Authorization": "Bearer {your_access_token}"}

response = requests.get(
    f"{BASE_URL}/sepa/beneficiaries",
    headers=headers,
    params={
        "iban[]": "FR7616798000010000005663951",  # Filter by IBAN
        "status[]": "validated",
        "per_page": 25,
    },
)
response.raise_for_status()

beneficiaries = response.json()["beneficiaries"]
beneficiary = beneficiaries[0]
beneficiary_id = beneficiary["id"]
beneficiary_name = beneficiary["name"]
print(f"Found beneficiary: {beneficiary['name']} ({beneficiary_id})")
2

Verify the SEPA payee (VoP)

Before creating a transfer, you must verify the payee through Verification of Payee (VoP). This returns a proof_token that you will include in the transfer request.Endpoint: Verify a SEPA payee
OAuth scope required: payment.write
The proof_token is valid for 23 hours only. Always verify immediately before creating the transfer. Excessive verifications not followed by a transfer may be rate-limited.
response = requests.post(
    f"{BASE_URL}/sepa/verify_payee",
    headers={**headers, "Content-Type": "application/json"},
    json={
        "iban": "FR7616958000014849440866435",
        "beneficiary_name": beneficiary_name,
    },
)
response.raise_for_status()

data = response.json()
proof_token = data["proof_token"]["token"]
match_result = data["match_result"]

# match_result values:
# MATCH_RESULT_MATCH       → proceed with confidence
# MATCH_RESULT_CLOSE_MATCH → consider reviewing the name
# MATCH_RESULT_NO_MATCH    → caution, consider skipping transfer
# MATCH_RESULT_NOT_POSSIBLE → verification unavailable for this IBAN
print(f"Verification result: {match_result}")
3

Create the SEPA transfer

Submit the transfer using the beneficiary_id from Step 1 and the proof_token from Step 2.Endpoint: Create a SEPA transfer
OAuth scope required: payment.write
Do not forget to include the X-Qonto-Idempotency-Key header to prevent duplicate transfers in case of network errors. See Idempotent requests.
To retrieve your bank_account_id, needed in this request, call GET /v2/organization or GET /v2/banks_accounts, the responses include a bank_accounts array, each with an id field.
Transfers above €30,000 require at least one attachment. Upload the attachment first via POST /v2/attachments and include its ID in the request.
import uuid

response = requests.post(
    f"{BASE_URL}/sepa/transfers",
    headers={
        **headers,
        "Content-Type": "application/json",
        "X-Qonto-Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "vop_proof_token": proof_token,
        "transfer": {
            "bank_account_id": "{your_bank_account_id}",
            "reference": "Invoice payment INV-001",
            "amount": "1100.50",
            "beneficiary_id": beneficiary_id,
            # "scheduled_date": "2026-04-01",  # Optional: ISO 8601 date
            # "attachment_ids": ["uuid-1"],     # Required if amount > €30,000
        },
    },
)
response.raise_for_status()

transfer = response.json()["transfer"]
print(f"Transfer created: {transfer['id']} — status: {transfer['status']}")
Instant transfer limits: Instant transfers fall back to standard SEPA if the amount exceeds the limit. For trusted beneficiaries: €10,000 per transfer or €50,000 within 24h.
Example output:
[Step 1] GET /sepa/beneficiaries
  Found beneficiary: Admin (0199cd7a-xxxx-xxxx-xxxx-xxxxxxxxxxxx)

[Step 2] POST /sepa/verify_payee
  Verification result: MATCH_RESULT_MATCH
  proof_token: 1|1|1773938795|MEUCI… (valid 23h)

[Step 3] POST /sepa/transfers
  Transfer created: 019d06fd-xxxx-xxxx-xxxx-xxxxxxxxxxxx — status: pending
We now have a submitted SEPA transfer. The transfer id and status in the response confirm it has been accepted for processing.