> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qonto.com/llms.txt
> Use this file to discover all available pages before exploring further.

# How to send a SEPA transfer to a trusted beneficiary

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`

<Warning>
  Beneficiaries can only be trusted through the Qonto web app, unless you are are an [Embed](/qonto-embed/qonto-embed) partner with the `beneficary.trust` scope. Learn more about [sensitive scopes](/get-started/general/developer-guidelines#sensitive-scopes).
</Warning>

<Steps>
  <Step title="List SEPA beneficiaries" titleSize="h3">
    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](/api-reference/business-api/payments-transfers/sepa-transfers/beneficiaries/sepa-beneficiaries/index)

    <Info>
      **OAuth scope required:** `organization.read`
    </Info>

    <Tabs>
      <Tab title="Python">
        ```python theme={null}
        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})")
        ```
      </Tab>

      <Tab title="Node.js">
        ```javascript theme={null}
        const BASE_URL = "https://thirdparty.qonto.com/v2";
        const headers = { Authorization: "Bearer {your_access_token}" };

        const params = new URLSearchParams();
        params.append("iban[]", "FR7616798000010000005663951"); // Filter by IBAN
        params.append("status[]", "validated");
        params.append("per_page", 25);

        const response = await fetch(`${BASE_URL}/sepa/beneficiaries?${params}`, { headers });
        if (!response.ok) throw new Error(`HTTP ${response.status}`);

        const { beneficiaries } = await response.json();
        const beneficiary = beneficiaries[0];
        const beneficiaryId = beneficiary.id;
        const beneficiaryName = beneficiary.name;
        console.log(`Found beneficiary: ${beneficiaryName} (${beneficiaryId})`);
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Verify the SEPA payee (VoP)" titleSize="h3">
    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](/api-reference/business-api/payments-transfers/sepa-transfers/verify-payee/index)

    <Info>
      **OAuth scope required:** `payment.write`
    </Info>

    <Warning>
      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.
    </Warning>

    <Tabs>
      <Tab title="Python">
        ```python theme={null}
        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}")
        ```
      </Tab>

      <Tab title="Node.js">
        ```javascript theme={null}
        const verifyResponse = await fetch(`${BASE_URL}/sepa/verify_payee`, {
          method: "POST",
          headers: { ...headers, "Content-Type": "application/json" },
          body: JSON.stringify({
            iban: "FR7616958000014849440866435",
            beneficiary_name: beneficiaryName,
          }),
        });
        if (!verifyResponse.ok) throw new Error(`HTTP ${verifyResponse.status}`);

        const response = await verifyResponse.json();
        const proofToken = response.proof_token.token;
        const matchResult = response.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
        console.log(`Verification result: ${matchResult}`);
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Create the SEPA transfer" titleSize="h3">
    Submit the transfer using the `beneficiary_id` from Step 1 and the `proof_token` from Step 2.

    Endpoint: [Create a SEPA transfer](/api-reference/business-api/payments-transfers/sepa-transfers/sepa-transfers/create)

    <Info>
      **OAuth scope required:** `payment.write`
    </Info>

    <Info>
      Do not forget to include the `X-Qonto-Idempotency-Key` header to prevent duplicate transfers in case of network errors. See [Idempotent requests](/get-started/general/idempotent-requests).
    </Info>

    <Info>
      To retrieve your `bank_account_id`, needed in this request, call [`GET /v2/organization`](/api-reference/business-api/accounts-organizations/organizations/retrieve-the-authenticated-organization-and-list-bank-accounts) or [`GET /v2/banks_accounts`](/api-reference/business-api/accounts-organizations/business-accounts/list), the responses include a `bank_accounts` array, each with an `id` field.
    </Info>

    <Warning>
      Transfers above **€30,000** require at least one attachment. Upload the attachment first via [`POST /v2/attachments`](/api-reference/business-api/expense-management/attachments/upload-an-attachment) and include its ID in the request.
    </Warning>

    <Tabs>
      <Tab title="Python">
        ```python {11, 16} theme={null}
        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']}")
        ```
      </Tab>

      <Tab title="Node.js">
        ```javascript {11, 16} theme={null}
        const { randomUUID } = await import("node:crypto");

        const transferResponse = await fetch(`${BASE_URL}/sepa/transfers`, {
          method: "POST",
          headers: {
            ...headers,
            "Content-Type": "application/json",
            "X-Qonto-Idempotency-Key": randomUUID(),
          },
          body: JSON.stringify({
            vop_proof_token: proofToken,
            transfer: {
              bank_account_id: "{your_bank_account_id}",
              reference: "Invoice payment INV-001",
              amount: "1100.50",
              beneficiary_id: beneficiaryId,
              // scheduled_date: "2026-04-01",  // Optional: ISO 8601 date
              // attachment_ids: ["uuid-1"],     // Required if amount > €30,000
            },
          }),
        });
        if (!transferResponse.ok) throw new Error(`HTTP ${transferResponse.status}`);

        const { transfer } = await transferResponse.json();
        console.log(`Transfer created: ${transfer.id} — status: ${transfer.status}`);
        ```
      </Tab>
    </Tabs>

    <Tip>
      **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.
    </Tip>
  </Step>
</Steps>

**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
```

<Check>
  We now have a submitted SEPA transfer. The transfer `id` and `status` in the response confirm it has been accepted for processing.
</Check>

***
