> For the complete documentation index, see [llms.txt](https://docs.xyb.co/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.xyb.co/xyb-platform-1/xyb-payments/payment-setup/build-a-customer-facing-fund-transfer-flow.md).

# Build a Customer Facing Fund Transfer Flow

### Overview

This article shows how developers can build a payment flow where end users initiate a fund transfer, and the backend handles validation and moves funds from the sender to the beneficiary.\
By calling XYB’s Payments APIs, developers can retrieve sender and beneficiary information, load dynamic form fields, trigger built-in compliance and validation checks, and rely on the platform to process the payment and update downstream systems.

Here's an overview of a typical payment workflow:

<div data-full-width="true"><figure><img src="https://2629557980-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Ft2bhF7867UQZjmdpxWXV%2Fuploads%2Fjxr48yru9GE9Ja6MeKHd%2Fimage.png?alt=media&amp;token=d28ad7fd-f372-4e59-b701-99aab698cbe0" alt=""><figcaption></figcaption></figure></div>

{% hint style="info" %}
**Use case flexibility**\
You can tailor this workflow for various payment methods, currencies, and compliance requirements by leveraging XYB’s dynamic field specification APIs.
{% endhint %}

***

### Prerequisites

Before you begin, make sure:

* You have an active `identityReference` for the payer (the customer or entity). [Learn more about linking entities.](/xyb-console/understanding-entities-in-xyb.md)
* A beneficiary has been created and linked to the identity. [Learn how to create a beneficiary.](/xyb-platform-1/xyb-payments/payment-setup/add-and-manage-beneficiary-accounts.md)
* Your payment infrastructure is ready (e.g., ledger, workflows, compliance rules are active). [Learn more here](/xyb-platform-1/xyb-payments/getting-started-with-payments/planning-your-payments-infrastructure.md).

{% hint style="warning" %}
**Note:** If any of the above conditions aren’t met, the payment request will fail validation or execution.
{% endhint %}

***

### Step-by-Step Workflow

1. Render a UI in your frontend where the user can select the payer account (linked customer entity as mentioned above) and the beneficiary (already created).
2. Call the following API to get the dynamic fields needed for this specific payment.

   ```http
   GET /api/v1/fields/{identityReference}/payment?beneficiaryAccountIdOptional={uuid}
   ```

   * **Path Parameter**: `identityReference` (payer's entity)
   * **Query Parameter**: `beneficiaryAccountIdOptional` (optional but recommended)

   \
   **Result:** You get a JSON response containing all required field groups, input formats, validation patterns, and visibility conditions for this payment.

<details>

<summary>Sample Response</summary>

```json
{
  "fields": [
    {
      "name": "iban",
      "label": "IBAN",
      "type": "string",
      "required": true,
      "validationPattern": "^[A-Z]{2}\\d{2}[A-Z0-9]{1,30}$",
      "visible": true
    },
    {
      "name": "purpose_code",
      "label": "Purpose",
      "type": "dropdown",
      "required": false,
      "options": ["SALA", "PENS", "GOVT"],
      "visible": true
    },
    {
      "name": "tax_id",
      "label": "Tax ID",
      "type": "string",
      "required": false,
      "visible": false
    }
  ]
}

```

</details>

3. Use the response to build a dynamic form for the user to fill. This form is customer-facing and should allow entry of details like IBAN, routing number, and payment purpose.

{% hint style="info" %}

* Show only the required fields for that scenario
* Apply the field order and input validation (e.g. regex, required flags)
* Implement visibility logic for conditional fields (e.g. show SWIFT fields only when needed)
  {% endhint %}

4. Call the validation API once the customer submits the form to validate all the information provided.&#x20;

```http
POST /api/v1/fields/{identityReference}/payment/validate
```

**Sample Request body:**

```json
{
  "beneficiary_account_uuid": "...",
  "beneficiary_uuid": "...",
  "currency": "EUR",
  "fields": {
    "iban": "DE1234567890",
    "purpose_code": "SALA"
  }
}
```

#### Field Reference

<table><thead><tr><th width="192.615478515625">Field</th><th width="139.967041015625">Type</th><th width="158.0850830078125">Required</th><th>Description</th></tr></thead><tbody><tr><td><code>beneficiary_account_uuid</code></td><td><code>string</code></td><td>Yes</td><td>UUID of the account receiving funds.</td></tr><tr><td><code>beneficiary_uuid</code></td><td><code>string</code></td><td>Yes</td><td>UUID of the recipient party.</td></tr><tr><td><code>currency</code></td><td><code>string</code></td><td>Yes</td><td>ISO 4217 currency code (e.g., <code>EUR</code>, <code>USD</code>).</td></tr><tr><td><code>fields.iban</code></td><td><code>string</code></td><td>Yes</td><td>International Bank Account Number of the recipient.</td></tr><tr><td><code>fields.purpose_code</code></td><td><code>string</code></td><td>Optional/Required (depends on currency &#x26; destination)</td><td>Purpose classification (e.g., <code>SALA</code> for salary).</td></tr></tbody></table>

<details>

<summary>Sample Success and Error Responses</summary>

#### Success Response

```json
{
  "status": "valid",
  "validation_id": "val_abc123",
  "messages": []
}
```

#### Error Response

```json
{
  "status": "invalid",
  "messages": [
    {
      "field": "iban",
      "error": "Invalid IBAN format for the selected country"
    },
    {
      "field": "purpose_code",
      "error": "Missing required field for EUR payments"
    }
  ]
}
```

</details>

{% hint style="success" %}

* Validation is **synchronous** and returns immediately with the validation result.
* This API is typically called **after the customer submits a form** but **before the actual payment request** is made.
* Only proceed if the validation passes. Return error messages to the customer if needed.
  {% endhint %}

***

5. Call the main payment initiation API to initiate a payment request after all validations are complete.&#x20;

   **Endpoint:**

   ```http
   POST /api/payments/
   ```

&#x20;     **Sample Request**

```json
{
  "id": "123e4567-e89b-12d3-a456-426614174000",
  "mandate": "user_001",
  "basis": {
    "from_account": "acc_123",
    "to_account": "acc_456"
  },
  "attributes": {
    "reference": "Invoice #4598",
    "notes": "Urgent payment"
  },
  "party_amount": {
    "value": 250.00,
    "currency": "USD"
  }
}
```

&#x20;    **Request Body Parameters**

<table><thead><tr><th width="181.787353515625">Field</th><th width="154.8533935546875">Type</th><th width="154.752685546875">Required</th><th>Description</th></tr></thead><tbody><tr><td><code>id</code></td><td><code>string</code> (UUID)</td><td>Yes</td><td>Unique identifier for the payment request</td></tr><tr><td><code>mandate</code></td><td><code>string</code></td><td>Yes</td><td>Reference to the user or entity initiating the payment</td></tr><tr><td><code>basis</code></td><td><code>object</code></td><td>Yes</td><td>Details of the party and beneficiary accounts</td></tr><tr><td><code>attributes</code></td><td><code>object</code></td><td>Yes</td><td>Dynamic key-value pairs from your frontend form</td></tr><tr><td><code>party_amount</code></td><td><code>object</code></td><td>Conditional</td><td>Amount to be debited from the initiating party</td></tr><tr><td><code>other_party_amount</code></td><td><code>object</code></td><td>Conditional</td><td>Amount to be credited to the beneficiary</td></tr></tbody></table>

<details>

<summary>Sample Success and Error Responses</summary>

#### Sample Success Response

```json
{
  "payment_id": "pay_abc789",
  "status": "initiated",
  "timestamp": "2025-07-22T10:30:00Z"
}
```

#### Error Response Example

```json
{
  "error": "invalid_mandate",
  "message": "Mandate user_001 does not exist or lacks permissions."
}
```

</details>

***

### Outcome

Once the payment is successfully submitted:

* XYB initiates the fund transfer
* Transaction is routed via the configured adapter (e.g. SEPA, SWIFT, internal)
* Ledger and account balances are updated
* Transaction statuses are reflected in the Console and API responses

**To understand the end-user experience, watch this video demonstration of a payment flow in XYB’s white-labeled mobile banking app.**

{% embed url="<https://youtu.be/hFv_IEzPtAo?si=fy265HeOGORMtZSX>" %}

### Also check out:&#x20;

{% content-ref url="/pages/3aMNMNc9uQh8Ax8l0cx7" %}
[Configure Third-Party Adapter](/xyb-platform-1/xyb-payments/payment-setup/configure-third-party-adapter.md)
{% endcontent-ref %}

{% content-ref url="/pages/3KgQRN6BmkxcSaQwtgw8" %}
[Broken mention](broken://pages/3KgQRN6BmkxcSaQwtgw8)
{% endcontent-ref %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.xyb.co/xyb-platform-1/xyb-payments/payment-setup/build-a-customer-facing-fund-transfer-flow.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
