Skip to main content
POST
/
api
/
v2.1
/
fintrans
/
{accountId}
/
types
/
{operationType}
/
prepare
Prepare financial operation
curl --request POST \
  --url https://sandbox.finhub.cloud/api/v2.1/fintrans/{accountId}/types/{operationType}/prepare \
  --header 'Content-Type: application/json' \
  --header 'X-Tenant-ID: <x-tenant-id>' \
  --data '
{
  "sourceAccount": {
    "walletId": "<string>",
    "iban": "<string>",
    "name": "<string>"
  },
  "destinationAccount": {
    "walletId": "<string>",
    "iban": "<string>",
    "name": "<string>"
  },
  "target": {
    "walletId": "<string>",
    "iban": "<string>",
    "name": "<string>"
  },
  "amount": {
    "value": "<string>",
    "scale": 123,
    "currency": "<string>"
  },
  "beneficiaryId": "<string>",
  "beneficiaryIban": "<string>",
  "beneficiaryName": "<string>",
  "reference": "<string>",
  "description": "<string>",
  "currency": "<string>",
  "type": "<string>",
  "consent": {
    "consentReference": "<string>"
  },
  "merchantDetails": {
    "merchantId": "<string>",
    "merchantName": "<string>",
    "merchantCategory": "<string>"
  },
  "customerDetails": {
    "customerId": "<string>",
    "customerName": "<string>",
    "customerEmail": "<string>"
  },
  "assetId": "<string>",
  "assetSubUnitId": "<string>"
}
'
{
  "success": true,
  "data": {
    "accounts": [
      {
        "accountId": "69a7d5b0-58f0-4394-a3fc-4d33058dc89e",
        "assetId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "assetSubUnitId": "dd35508b-7529-49b8-ae56-fafd523f953f",
        "balance": "50000.00",
        "currency": "EUR",
        "iban": "FI2112345600000785"
      }
    ],
    "beneficiaries": [
      {
        "beneficiaryId": "ben_12345",
        "walletId": "f1e2d3c4-b5a6-9807-fedc-ba0987654321",
        "name": "John Doe",
        "iban": "DE89370400440532013000",
        "kind": "EXTERNAL"
      }
    ],
    "operations": [
      {
        "opType": "sepa_transfer_internal",
        "fromAccountId": "69a7d5b0-58f0-4394-a3fc-4d33058dc89e",
        "fromAssetId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "toRefId": "f1e2d3c4-b5a6-9807-fedc-ba0987654321"
      },
      {
        "opType": "sepa_transfer_external",
        "fromAccountId": "69a7d5b0-58f0-4394-a3fc-4d33058dc89e",
        "fromAssetId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "toRefId": ""
      }
    ],
    "limits": {
      "daily": {
        "value": 50000.00,
        "currency": "EUR",
        "used": 1000.00,
        "remaining": 49000.00
      },
      "perTransaction": {
        "value": 10000.00,
        "currency": "EUR"
      }
    },
    "fees": {
      "INTERNAL": {"value": 0, "currency": "EUR"},
      "SEPA": {"value": 1.50, "currency": "EUR"},
      "SEPA_INSTANT": {"value": 2.50, "currency": "EUR"},
      "SWIFT": {"value": 25.00, "currency": "EUR"}
    }
  }
}

Transfers & Payments API

APIs for the three-step transfer workflow: prepare, execute, and monitor transfers.
Base URL: https://sandbox.finhub.cloud/api/v2.1/fintrans
For complete details on authentication and headers, refer to the Standard HTTP Headers reference documentation.

Transfer Prerequisites Checklist

Before executing transfers:
  • Account ACTIVATED
  • Wallet ACTIVE with sufficient balance
  • Beneficiary pre-registered (recommended)
  • Payment consent created (if required by category)
  • Approval workflow configured (for high-value transfers)

Complete Transfer Flow

3-Step Process

Step 1: Prepare Transfer Order

  • Validates transfer details and beneficiary
  • Calculates fees and total debit amount
  • Reserves funds in the source account
  • Returns preparedOrderId with validUntil timestamp
  • Critical: Order expires after 15 minutes and must be executed before validUntil

Step 2: Execute Transfer Order

  • Confirms payment consent (if required)
  • Processes multi-level approvals (for high-value transactions)
  • Attaches supporting documents (for transactions above threshold)
  • Executes the actual payment
  • Returns executionId and transaction reference

Step 3: Monitor Status

  • Track execution progress (PENDING → PROCESSING → COMPLETED)
  • View state transition history
  • Check settlement status
  • Download transaction receipt

Two-Phase Pattern Explained

15-Minute Expiration: Prepared orders are only valid for 15 minutes from creation. You must execute the order before the validUntil timestamp or the order will expire and need to be prepared again.

Why Two Phases?

The prepare/execute pattern provides several benefits:
  1. Pre-Validation - Catch errors before committing funds
  2. Fee Transparency - Show exact fees before execution
  3. Balance Reservation - Prevent overdrafts during execution
  4. Compliance Window - Allow time for high-value transaction document upload
  5. User Confirmation - Give users time to review and confirm
  6. Idempotency - Prevent duplicate transfers

Timing Example

// Prepare at 10:00:00
const prepared = await prepareTransfer(accountId, {
  amount: { value: '10000', scale: 2, currency: 'EUR' },
  target: { walletId: 'ben_123' },
  beneficiaryId: 'ben_123',
  type: 'TRANSFER'
});

console.log('Prepared Order ID:', prepared.preparedOrderId);
console.log('Valid Until:', prepared.validUntil); // 2026-01-13T10:15:00Z

// You have until 10:15:00 to execute (15 minutes)
// After 10:15:00, the order expires and returns error:
// "Prepared order expired or not found"

// Execute before expiration
if (Date.now() < new Date(prepared.validUntil).getTime()) {
  const result = await executeTransfer(accountId, prepared.preparedOrderId);
  console.log('Executed!', result.executionId);
} else {
  console.error('Order expired - prepare again');
}

High-Value Transaction Flow

For transactions above the threshold (typically €10,000), additional documents are required:
// 1. Prepare high-value transfer
const prepared = await prepareTransfer(accountId, {
  amount: { value: '1500000', scale: 2, currency: 'EUR' } // €15,000
});

// 2. Upload supporting documents (BEFORE execute)
const documents = [
  { type: 'PROOF_OF_FUNDS', content: proofOfFundsBase64 },
  { type: 'INVOICE', content: invoiceBase64 },
  { type: 'CONTRACT', content: contractBase64 }
];

for (const doc of documents) {
  await uploadPaymentDocument(walletId, prepared.preparedOrderId, doc);
}

// 3. Execute with consent confirmation
await executeTransfer(accountId, prepared.preparedOrderId, {
  consentConfirmation: {
    consentId: 'consent_abc123',
    confirmed: true,
    timestamp: new Date().toISOString(),
    channel: 'WEB',
    signature: 'user_digital_signature'
  },
  authenticationCode: '123456', // 2FA code
  supportingDocuments: documents.map(d => d.documentId)
});

Get Allowed Operations

Returns available transfer types, saved beneficiaries, current limits, and applicable fees.

Request

accountId
string
required
Source account ID for the transfer
Authorization
string
required
Bearer token for authentication
X-Tenant-ID
string
required
Tenant identifier
X-Session-Id
string
Active session ID (optional)

Code Examples

curl -X GET "https://sandbox.finhub.cloud/api/v2.1/fintrans/acc_12345/allowed-operations" \
  -H "Accept: application/json, text/plain, */*" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "X-Tenant-ID: 97e7ff29-15f3-49ef-9681-3bbfcce4f6cd" \
  -H "X-Forwarded-From: e2e-test" \
  -H "platform: web" \
  -H "deviceId: 356938035643809"

Response

accounts
array
Source accounts with asset IDs, balance, currency, and IBAN. Each entry provides the assetId and assetSubUnitId needed for the PrepareOrder call.
beneficiaries
array
Registered beneficiaries with kind (B2B, B2C, EXTERNAL, INTERNAL, C2B), walletId/assetId, iban, and name.
operations
array
Available operation types with opType, fromAccountId, fromAssetId, and toRefId (destination asset reference).
limits
object
Current transaction limits and usage
fees
object
Fee structure per transfer type
Consent model configuration (if applicable)
sessionId
string
Active session ID (if applicable)
{
  "success": true,
  "data": {
    "accounts": [
      {
        "accountId": "69a7d5b0-58f0-4394-a3fc-4d33058dc89e",
        "assetId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "assetSubUnitId": "dd35508b-7529-49b8-ae56-fafd523f953f",
        "balance": "50000.00",
        "currency": "EUR",
        "iban": "FI2112345600000785"
      }
    ],
    "beneficiaries": [
      {
        "beneficiaryId": "ben_12345",
        "walletId": "f1e2d3c4-b5a6-9807-fedc-ba0987654321",
        "name": "John Doe",
        "iban": "DE89370400440532013000",
        "kind": "EXTERNAL"
      }
    ],
    "operations": [
      {
        "opType": "sepa_transfer_internal",
        "fromAccountId": "69a7d5b0-58f0-4394-a3fc-4d33058dc89e",
        "fromAssetId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "toRefId": "f1e2d3c4-b5a6-9807-fedc-ba0987654321"
      },
      {
        "opType": "sepa_transfer_external",
        "fromAccountId": "69a7d5b0-58f0-4394-a3fc-4d33058dc89e",
        "fromAssetId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "toRefId": ""
      }
    ],
    "limits": {
      "daily": {
        "value": 50000.00,
        "currency": "EUR",
        "used": 1000.00,
        "remaining": 49000.00
      },
      "perTransaction": {
        "value": 10000.00,
        "currency": "EUR"
      }
    },
    "fees": {
      "INTERNAL": {"value": 0, "currency": "EUR"},
      "SEPA": {"value": 1.50, "currency": "EUR"},
      "SEPA_INSTANT": {"value": 2.50, "currency": "EUR"},
      "SWIFT": {"value": 25.00, "currency": "EUR"}
    }
  }
}
Asset IDs for PrepareOrder: Use accounts[0].assetId as assetId, accounts[0].assetSubUnitId as assetSubUnitId, and operations[0].toRefId as beneficiaryId (destination asset) in the PrepareOrder request. The opType from operations determines the URL path segment (e.g., sepa_transfer_internal).

Prepare Transfer

Validates transfer details and stages the order for execution. Returns fees and estimated arrival.

Request

accountId
string
required
Source account ID for the transfer
Authorization
string
required
Bearer token for authentication
X-Session-Id
string
required
Active session ID
X-Tenant-ID
string
required
Tenant identifier
source
object
Source account reference
target
object
Destination account reference
amount
object
required
Transfer amount (AmountRequest)
currency
string
Top-level currency (must match amount.currency)
assetId
string
Source asset ID from /allowed-operations response (accounts[0].assetId). Required in INTEGRATION mode.
assetSubUnitId
string
Asset sub-unit ID from /allowed-operations response (accounts[0].assetSubUnitId). Required in INTEGRATION mode.
beneficiaryId
string
Destination asset ID from /allowed-operations response (operations[0].toRefId or beneficiaries[0].walletId). In INTEGRATION mode, this must be the WSO2 asset ID, not the beneficiary UUID.
beneficiaryIban
string
IBAN of the beneficiary
beneficiaryName
string
Name of the beneficiary
reference
string
Payment reference (max 140 characters)
description
string
Internal description for the transfer
Consent reference (if payment consent is required)

Code Examples

curl -X POST "https://sandbox.finhub.cloud/api/v2.1/fintrans/acc_12345/types/TRANSFER/prepare" \
  -H "Accept: application/json, text/plain, */*" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "X-Tenant-ID: 97e7ff29-15f3-49ef-9681-3bbfcce4f6cd" \
  -H "X-Session-Id: YOUR_SESSION_ID" \
  -H "X-Forwarded-From: e2e-test" \
  -H "platform: web" \
  -H "deviceId: 356938035643809" \
  -d '{
    "source": { "walletId": "acc_12345" },
    "target": { "iban": "DE89370400440532013000", "name": "Acme Corp" },
    "amount": { "value": "50000", "scale": 2, "currency": "EUR" },
    "currency": "EUR",
    "assetId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "assetSubUnitId": "dd35508b-7529-49b8-ae56-fafd523f953f",
    "beneficiaryId": "f1e2d3c4-b5a6-9807-fedc-ba0987654321",
    "beneficiaryIban": "DE89370400440532013000",
    "beneficiaryName": "Acme Corp",
    "reference": "Invoice Payment",
    "description": "Payment for services"
  }'

Response

orderId
string
Unique identifier for the prepared order
status
string
Order status (PREPARED)
amount
object
Transfer amount
fees
object
Applicable fees for this transfer
totalDebit
object
Total amount to be debited (amount + fees)
estimatedArrival
string
Estimated arrival date
expiresAt
string
Order expiration timestamp (must execute before this time)
{
  "success": true,
  "data": {
    "orderId": "ord_12345",
    "status": "PREPARED",
    "amount": {
      "value": 500.00,
      "currency": "EUR"
    },
    "fees": {
      "value": 1.50,
      "currency": "EUR"
    },
    "totalDebit": {
      "value": 501.50,
      "currency": "EUR"
    },
    "estimatedArrival": "2024-01-17",
    "expiresAt": "2024-01-15T11:00:00Z"
  }
}

Execute Transfer

Executes a prepared transfer order. The order must be executed before it expires.

Request

accountId
string
required
Source account ID
Authorization
string
required
Bearer token for authentication
X-Session-Id
string
required
Active session ID
X-Tenant-ID
string
required
Tenant identifier
preparedOrderId
string
required
Prepared order ID from the prepare step
authenticationCode
string
Authentication/2FA code (e.g., "427934")
Consent confirmation (if payment consent was used during prepare)
executionMetadata
object
Optional metadata for the execution (empty object {} if not needed)

Code Examples

curl -X POST "https://sandbox.finhub.cloud/api/v2.1/fintrans/acc_12345/types/TRANSFER/execute" \
  -H "Accept: application/json, text/plain, */*" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "X-Tenant-ID: 97e7ff29-15f3-49ef-9681-3bbfcce4f6cd" \
  -H "X-Session-Id: YOUR_SESSION_ID" \
  -H "X-Forwarded-From: e2e-test" \
  -H "platform: web" \
  -H "deviceId: 356938035643809" \
  -d '{
    "preparedOrderId": "ord_12345",
    "authenticationCode": "427934",
    "consentConfirmation": {
      "consentId": "consent_abc123",
      "confirmed": true,
      "channel": "WEB",
      "signature": ""
    },
    "executionMetadata": {}
  }'

Response

transactionId
string
Unique transaction identifier for tracking
orderId
string
Original order ID
status
string
Transaction status (PROCESSING, COMPLETED, FAILED)
executedAt
string
ISO 8601 timestamp of execution
estimatedCompletion
string
Estimated completion timestamp
{
  "success": true,
  "data": {
    "transactionId": "txn_67890",
    "orderId": "ord_12345",
    "status": "PROCESSING",
    "executedAt": "2024-01-15T10:35:00Z",
    "estimatedCompletion": "2024-01-17T12:00:00Z"
  }
}

Transfer Types

INTERNAL

Speed: Instant
Fee: Free
Between FinHub accounts

SEPA

Speed: 1-2 business days
Fee: €1.50
Eurozone bank transfers

SEPA_INSTANT

Speed: Under 10 seconds
Fee: €2.50
Real-time Eurozone transfers

SWIFT

Speed: 2-5 business days
Fee: €25.00
International wire transfers

Direct Transfer Operations

Not Yet Implemented — The direct transfer endpoints below (/transfers/types.topup, /transfers/types.withdraw, etc.) are registered in the BFF but currently return HTTP 501 Not Implemented.Use the prepare-execute workflow above instead:
  • POST /fintrans/{accountId}/types/{operationType}/prepare
  • POST /fintrans/{accountId}/types/{operationType}/execute

Planned Direct Endpoints

These endpoints will bypass the two-step workflow once implemented:
POST /api/v2.1/fintrans/{accountId}/transfers/types.topup      → 501 Not Implemented
POST /api/v2.1/fintrans/{accountId}/transfers/types.withdraw    → 501 Not Implemented
POST /api/v2.1/fintrans/{accountId}/transfers/types.transfer    → 501 Not Implemented
POST /api/v2.1/fintrans/{accountId}/transfers/types.purchase    → 501 Not Implemented
POST /api/v2.1/fintrans/{accountId}/transfers/types.sale        → 501 Not Implemented

Muse-Proxy Compatibility Aliases

The TransferResource provides convenience aliases that delegate to the same prepare-execute logic in FinTransResource. These exist for backward compatibility with the muse-proxy API.

Prepare Transfer (Alias)

POST /api/v2.1/transfers/{walletId}/prepare
Delegates to POST /api/v2.1/fintrans/{walletId}/types/{operationType}/prepare. The operation type is inferred from the request body.

Execute Transfer (Alias)

POST /api/v2.1/transfers/{walletId}/execute
Delegates to POST /api/v2.1/fintrans/{walletId}/types/{operationType}/execute.

Order Wizard Aliases (via WalletResource)

These convenience endpoints are used by the Order Review Widget (step 7) and delegate to FinTransResource:
POST /api/v2.1/wallets/orders/prepare     → delegates to FinTransResource.prepareOperation
POST /api/v2.1/wallets/orders/execute     → delegates to FinTransResource.executeOperation
Request body for /wallets/orders/prepare:
{
  "walletId": "69a7d5b0-58f0-4394-a3fc-4d33058dc89e",
  "operationType": "SEPA_CREDIT_TRANSFER",
  "amount": "500.00",
  "currency": "EUR",
  "beneficiaryId": "ben_123",
  "beneficiaryIban": "DE89370400440532013000",
  "beneficiaryName": "Acme Corp",
  "description": "Invoice payment",
  "e2eReference": "INV-2026-001",
  "consentId": "consent_abc123"
}
Request body for /wallets/orders/execute:
{
  "walletId": "69a7d5b0-58f0-4394-a3fc-4d33058dc89e",
  "operationType": "SEPA_CREDIT_TRANSFER",
  "orderId": "ord_12345",
  "otp": "123456",
  "consentId": "consent_abc123"
}

Operation Types Summary

TypeDescriptionUse CaseStatus
topupAdd fundsDeposits, incoming transfers✅ via prepare/execute
withdrawRemove fundsBank withdrawals✅ via prepare/execute
transferMove between accountsP2P, internal transfers✅ via prepare/execute
sepa_transfer_externalExternal SEPA transferCross-bank payments✅ via prepare/execute
sepa_instant_paymentInstant SEPA paymentReal-time payments✅ via prepare/execute
sepa_transfer_internalInternal SEPA transferSame-bank transfers✅ via prepare/execute
purchaseDebit for purchaseMerchant payments🔜 Planned
saleCredit from saleRevenue recognition🔜 Planned

Transfer Status Flow

StatusDescriptionNext Step
PREPAREDOrder validated, funds reservedExecute within 15 min
EXECUTINGPayment being processedWait for completion
COMPLETEDTransfer successfulNone
FAILEDTransfer failedReview error, retry
CANCELLEDManually cancelledCreate new order

Idempotency (Prevent Duplicates)

Use X-Idempotency-Key header to prevent duplicate transfers:
const idempotencyKey = `transfer-${Date.now()}-${Math.random()}`;

await fetch(url, {
  method: 'POST',
  headers: {
    'X-Idempotency-Key': idempotencyKey,
    ...otherHeaders
  },
  body: JSON.stringify(transferData)
});
Important: Same key within 24 hours = same response (no duplicate charge)

Response Codes

CodeDescription
200Transfer status retrieved successfully
201Transfer prepared/executed successfully
400Invalid request data or prepared order expired (>15 min)
403Insufficient funds or limits exceeded
404Account, order, or beneficiary not found
409Duplicate idempotency key
422Missing consent or approval required
500Internal server error

API Schema Reference

For the complete OpenAPI schema specification, see the API Schema Mapping document:

Changelog

VersionDateChanges
v1.02026-01-13Comprehensive transfer operations documentation

Headers

X-Tenant-ID
string
required

Tenant identifier

Example:

"97e7ff29-15f3-49ef-9681-3bbfcce4f6cd"

X-User-ID
string

Authenticated user identifier

Example:

"87b3af37-4ac1-402b-a0ea-53cfdc695e02"

Path Parameters

accountId
string
required
operationType
string
required

Body

application/json
sourceAccount
object
destinationAccount
object
target
object
amount
object
beneficiaryId
string
beneficiaryIban
string
beneficiaryName
string
reference
string
description
string
currency
string
type
string
merchantDetails
object
customerDetails
object
assetId
string
assetSubUnitId
string

Response

200

OK