Trusted payments

This guide details how to implement Digiteal's Trusted Payment (Escrow) system. This flow is built for integrators and platforms that want to utilize a regulated, neutral escrow system to secure funds between buyers and sellers. This significantly reduces your administrative overhead, manual reconciliation efforts, and compliance liability.

🎯 The Trusted Payment Workflow

The Scenario: You run a platform or software that facilitates financial transactions between two or more parties. The Solution: Instead of receiving funds into your own accounts, your system opens an automated "Escrow Container" for the transaction. Clients pay directly into this secure transit account. Your platform can dynamically adjust payment splits and trigger partial or full payouts to the seller, while retaining full control over when the funds are ultimately released.


🛠 Phase 1: Onboarding Users (KYC)

Before a seller or creditor can receive payouts, they must be registered and verified within Digiteal’s ecosystem.

  • Endpoints: Use POST /api/v1/kyc/company (for registered businesses)
  • The Process: Pre-register the company via the API so they can legally receive funds.
  • Low Volume: If the company expects to receive < €3,000 annually, the standard API pre-registration is usually sufficient to begin.
  • High Volume: If they exceed compliance thresholds, you must prompt them to upload identification documents using POST /api/v1/kyc/document

🧳 Phase 2: Creating the Escrow "Wallet" & Setting Permissions

For each new transaction, project, or billing cycle, you must create a confirmation-based transfer. This acts as the legal escrow container.

Strategy:

  • Capacity: Set the amountInCents within the transferPayments array to an arbitrarily high number. This ensures the escrow container can accommodate the total expected volume without hitting a restrictive ceiling.
  • The decide Flag (Crucial): Configure the decide flag within the actors array to enforce strict escrow rules. For example, the integrator (_3RD_PARTY) and the buyer (BUYER) should have decide: true so they can authorize the release, while the seller (SELLER) must be set to decide: false so they cannot release funds to themselves prematurely.

Example Payload:

{
  "projectName": "Project - Order #1234",
  "transferPayments": [
    {
      "amountInCents": 15000, 
      "communication": "Payout for Order #1234",
      "creditorEmail": "[email protected]",
      "reference": "PAY-REF-01" 
    }
  ],
  "actors": [
    {
      "type": "BUYER",
      "email": "[email protected]",
      "decide": true 
    },
    {
      "type": "_3RD_PARTY",
      "vatNumber": "BE0123456789",
      "decide": true 
    },
    {
      "type": "SELLER",
      "email": "[email protected]",
      "decide": false 
    }
  ]
}

Note: Save the transferID (UUID) returned in the 200 OK response. You will need it for all subsequent steps.


💳 Phase 3: Collecting Funds (Pay-Ins) & Generating Payment Links

When a transaction is initiated, you need to route the client's money into the escrow. To prevent malicious users from tampering with parameters (like lowering the payment amount), you must secure the payment links.

Approach A: Construct a payment link (GET method)

Construct the Raw Execution URL

Build the raw URL targeting the /api/v1/pay-button/execute endpoint, injecting the trustedPaymentUUID from Phase 2.

https://app.digiteal.eu/api/v1/payment-request/pay-button/execute?trustedPaymentUUID=e529f8b4-790f-11e7-b5a5-be2e44b06b52&amountInCents=15000&qrCode=true&confirmationURL=https://yourplatform.com/payment/success&errorURL=https://yourplatform.com/payment/error

(Setting qrCode=true renders a scannable Bancontact/Payconiq code for in-person or "Soft POS" scenarios).

Secure it with the Short Link API

Pass the raw URL to the POST /api/v1/shortLink endpoint to lock the parameters in place.

Example Payload:

{
  "longURL": "https://app.digiteal.eu/api/v1/payment-request/pay-button/execute?trustedPaymentUUID=e529f8b4-790f-11e7-b5a5-be2e44b06b52&amountInCents=15000&qrCode=true&confirmationURL=https://yourplatform.com/payment/success&errorURL=https://yourplatform.com/payment/error"
}

Response:

{
  "shortURL": "https://app.digiteal.eu/p/abcde"
}

Action: Present this shortURL to the customer (via email, SMS, or displayed as a QR code).

Approach B: Trusted Payment Link Generation (POST - Recommended)

Endpoint: POST [/api/v1/payment-request/trustedPayment](createtrustedpaymentcollectionrequest)

This endpoint provides a dedicated Trusted Payment specific counterpart to standard payment requests. Instead of passing standard merchant details, you link the payment directly to the pre-created Trusted Payment transfer IDs or creditor references. This is the recommended server-side approach for marketplaces wanting to securely generate payment links explicitly tied to their escrow containers.

Base Parameters

Send a POST request with the following JSON body parameters. To identify which trusted payment(s) you are collecting funds for, you must use one of the identifier methods (transferId, transferIds, creditorReference, creditorReferences, or contributions).

Note: If you provide multiple identification types, they are processed in order of priority: contributions > transferIds > transferId > creditorReferences > creditorReference.

ParameterTypeRequiredDescription
amountInCentsintegerNoThe amount to charge in cents (e.g., 1234 for 12.34). If not provided for a confirmation-based trusted payment, the total remaining amount of the trusted payment will be requested automatically.
confirmationURLstringYesThe URL where the user is redirected after a successful payment (Max 255 chars).
errorURLstringYesThe URL where the user is redirected if an error occurs during the payment (Max 255 chars).
cancelURLstringNoThe URL where the user is redirected if they cancel the payment. If omitted, the user is sent to the errorURL.
languagestringNoThe language of the checkout interface. Accepted values are NL, FR, or EN.

Trusted Payment Identifiers (Choose One)

ParameterTypeDescription
transferIdstring (uuid)The Digiteal UUID of a single trusted payment transfer.
transferIdsarray of uuidsAn array of Digiteal UUIDs for multiple trusted payment transfers you want to collect at once.
creditorReferencestringThe single creditor reference associated with the trusted payment.
creditorReferencesarray of stringsAn array of creditor references for multiple trusted payments.
contributionsarray of objectsSpecific contributions to the trusted payments

Example Request

Because the payment URLs are returned in the headers instead of the body, be sure your client is configured to read the HTTP response headers.

curl -i -X POST [https://test.digiteal.eu/api/v1/payment-request/trustedPayment](https://test.digiteal.eu/api/v1/payment-request/trustedPayment) \
  -H "Authorization: Basic YOUR_BASE64_CREDENTIALS" \
  -H "Content-Type: application/json" \
  -d '{
    "transferId": "48e382de-1740-40e6-9902-b3bd3ead8e62",
    "amountInCents": 15000,
    "confirmationURL": "[https://yourmarketplace.com/checkout/success](https://yourmarketplace.com/checkout/success)",
    "errorURL": "[https://yourmarketplace.com/checkout/error](https://yourmarketplace.com/checkout/error)",
    "cancelURL": "[https://yourmarketplace.com/checkout/cancel](https://yourmarketplace.com/checkout/cancel)",
    "language": "EN"
  }'

📡 Phase 4: Event Monitoring (The Complete Webhook Lifecycle)

To automate the workflow without relying on frontend redirects, your backend server must listen to Digiteal's webhooks.

1. The Buyer Pay-In Flow (Payment Webhooks)

These events indicate what is happening when the buyer interacts with the payment link. 📖 Learn more: Read the full Payment Webhooks guide

  • PAYMENT_INITIATED_V2: Triggered when the buyer officially initiates the payment (e.g., authenticates their banking app).
  • PAYMENT_INITIATION_ERROR_V2: Triggered if the payment fails on the buyer's side. Integrator Action: Prompt the buyer to try another payment method.
  • PAYMENT_RECEIVED_IN_TRANSIT: Triggered when the money physically arrives in Digiteal's secure transit account.

2. The Escrow Lifecycle (Transfer Webhooks)

These core events dictate your business logic and indicate when funds are secured or released. 📖 Learn more: Read the full Trusted Payment Webhooks guide

  • TRANSFER_CREATED: A trusted payment (escrow container) has been created. Integrator Action: Link the transferId to your internal transaction ID.
  • TRANSFER_PAYMENT_RECEIVED: A payment awaiting confirmation has been received into the escrow. Integrator Action: This is the green light. The funds are 100% secured and locked; the service or product delivery can commence.
  • TRANSFER_PAYMENT_STARTED: A trusted payment execution has started. The money transfer order to the creditor will soon be executed.
  • TRANSFER_PAYMENT_COMPLETED: The transfer has been completed successfully. Integrator Action: The funds have settled in the respective bank accounts. Mark the transaction as complete.

If a transaction is disputed or canceled after the payout, you can track the lifecycle of the money flowing back to the buyer.

  • REIMBURSEMENT_RECEIVED_FROM_CREDITOR: Confirmation that Digiteal received the funds back from a specific creditor (sent per creditor involved in the refund). The payload contains the payment info and the transfer reference.
  • TRANSFER_REIMBURSEMENT_STARTED: Triggered once Digiteal has successfully retrieved all funds from all requested creditors and is about to send the full amount as a unique payment back to the debtor.
  • TRANSFER_REIMBURSEMENT_COMPLETED: The debtor has successfully received the refund payment from Digiteal. This officially ends the refund process.

✂️ Phase 5: Managing, Splitting, and Releasing Funds

The integrator dictates when and how the secured funds are disbursed. Because of the decide flag set in Phase 2, the execution endpoints will only work if called by authorized actors.

5a. Update the Split (Dynamic Fees/Commissions)

  • Endpoint: POST /api/v1/transfers/confirmation-based/uuid/payments
  • Usage: Modify the escrow parameters dynamically. Update the transferPayments array to designate the final creditorIBAN and optionally deduct an integrator fee by targeting the reference established in Phase 2.

Example Payload:

{
  "updates": [
    {
      "reference": "PAY-REF-01",
      "amountInCents": 12000, 
      "communication": "Final payout minus service fee"
    },
    {
      "reference": "PAY-REF-01",
      "subReference": "FEE-01",
      "amountInCents": 3000,
      "communication": "Integrator Fee Job #1234",
      "creditorIBAN": "BE12345678901234"
    }
  ]
}

5b. Execute the Payout

Once conditions are met (e.g., the buyer confirms receipt), your backend makes this call to release the money.

Example Payload:

{
  "transferID": "e529f8b4-790f-11e7-b5a5-be2e44b06b52",
  "validate": true,
  "comment": "Transaction verified. Releasing funds."
}

Note: Setting validate: true performs a full release of all secured funds and closes the escrow container. For ongoing, long-living escrows, use POST /api/v1/transfers/confirmation-based/{uuid}/partialExecution instead.


⏪ Phase 6: Handling Disputes and Refunds

If a transaction is canceled or a dispute arises after an execution has already taken place, you can request to pull the funds back from the seller(s) and refund the buyer.

  • Endpoint: POST /api/v1/payments/paymentId/transfers/transferId/refund
  • How it Works: Digiteal retrieves the funds from the creditor(s) via Direct Debit (SDD). Once all requested funds are secured, Digiteal issues a refund to the debtor via Bank Transfer (SCT).
  • Multiple Transfers: If the original payment funded multiple transfers, you must make a separate API call for each specific transferId.
  • Response: Look in the headers of the 200 OK response for the UUID of the refund payment to track its status.

6a. Full Refunds

A full refund is executed by leaving the list of contributions empty. Digiteal will retrieve the full amount of all the payments made to all creditors associated with the transfer.

Example Payload (Full Refund):

{  
  "communication": "Refund from payment cart-1234 of 15/05/2023"
}

6b. Partial Refunds

To request a partial refund, you use the contributions attribute (refundContributions). Each contribution defines the specific amount to be retrieved from a specific creditor linked to the transfer. Only the contributions defined in the request are refunded.

  • Rules: The amount of each contribution must be positive and must not exceed the amount that was originally paid to that specific creditor.

Example Payload (Partial Refund):

{  
  "communication": "Refund from payment cart-1234 of 15/05/2023",  
  "refundContributions": [  
    {  
      "contributorIban": "ES0720951914701193632422",  
      "amountInCents": "9250",  
      "currency": "EUR",  
      "communication": "Refund from payment cart-1234 of 15/05/2023",  
      "reference": "REFERENCE_ID1"  
    },  
    {  
      "contributorIban": "ES1401827984057893687272",  
      "amountInCents": "750",  
      "currency": "EUR",  
      "communication": "Refund from payment cart-1234 of 15/05/2023",  
      "reference": "REFERENCE_ID2"  
    }  
  ]  
}