Skip to main content

What is Fundflow?

Fundflow is Venly’s enterprise API platform that enables businesses to seamlessly convert between traditional fiat currency and cryptocurrency through a comprehensive REST API.

On-Ramp

Convert fiat to cryptocurrency via API

Off-Ramp

Convert cryptocurrency to fiat via API

Key Features

πŸ”’ Enterprise-Grade Security

  • OAuth2 authentication
  • KYB (Know Your Business) verification
  • Optimistic locking for concurrent updates
  • Wallet ownership verification
  • Role-based access control

πŸ’° Transparent Pricing

  • Company-specific fee tiers
  • Volume-based discounts
  • Real-time fee calculation API
  • Clear exchange rates

🌍 Multi-Currency Support

Fiat Currencies: EUR, USD, GBP Payment Networks:
  • EUR_SEPA (European SEPA transfers)
  • USD_WIRE, USD_ACH, USD_SWIFT (US transfers)
  • GBP_FPS, GBP_CHAPS (UK transfers)
  • OTHER_SWIFT (International transfers)
Cryptocurrencies:
  • USDC (Ethereum)
  • EURC (Ethereum)
  • USDS (Ethereum)
  • ETH (Ethereum)
  • POL (Polygon)
Blockchain Networks:
  • Ethereum
  • Polygon
  • Base
  • Arbitrum
  • Sui

Prerequisites

Before you begin, ensure you have: βœ… Company Account: Contact Venly to set up your company account
βœ… OAuth2 Credentials: Client ID and secret for authentication
βœ… API Access: Base URL: https://api-fundflow.venly.io
βœ… Development Environment: REST API client or SDK

Integration Steps

1

1. Authentication

Obtain an OAuth2 access token from Venly Identity Platform
POST https://login.venly.io/auth/realms/VenlyFinance/protocol/openid-connect/token

Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
Use the access token in all API requests:
Authorization: Bearer YOUR_ACCESS_TOKEN
2

2. Verify Company Status

Check your company’s KYB verification status
GET /v1/company
Response:
{
  "success": true,
  "result": {
    "id": "company-id",
    "name": "Your Company",
    "kybStatus": "VERIFIED",
    "invoicesUrl": "https://portal.venly.io/invoices"
  }
}
Your company must have kybStatus: "VERIFIED" to create ramp requests.
3

3. Add Bank Accounts

Register company bank accounts for fiat transactions
POST /v1/company-bank-accounts
Content-Type: application/json

{
  "bankAccountType": "EUR_SEPA",
  "name": "Primary EUR Account",
  "bankName": "Deutsche Bank",
  "companyName": "Your Company Ltd",
  "iban": "DE89370400440532013000",
  "bic": "COBADEFFXXX",
  "bankCountry": "DE",
  "beneficiaryAddressLine1": "123 Main Street",
  "beneficiaryCity": "Berlin",
  "beneficiaryPostalCode": "10115",
  "beneficiaryCountry": "DE",
  "supportedRampType": "ON_AND_OFF_RAMP"
}
Status Flow: PENDING β†’ VERIFIED (manual review by Venly)
Bank accounts require manual verification. This process may take 1-2 business days.
4

4. Add Crypto Wallets

Register company cryptocurrency wallets
POST /v1/company-wallets
Content-Type: application/json

{
  "address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
  "chain": "ETHEREUM",
  "description": "Main treasury wallet"
}
Status Flow: PENDING β†’ VERIFIEDComplete the verification process to prove wallet ownership.
5

5. Get Available Currency Pairs

Retrieve supported currency pairs for your operationsFor On-Ramp:
GET /v1/ramp-requests/on-ramp/pairs
For Off-Ramp:
GET /v1/ramp-requests/off-ramp/pairs
Response:
{
  "success": true,
  "result": [
    {
      "from": {
        "id": "eur-id",
        "currency": "EUR",
        "label": "Euro"
      },
      "to": {
        "id": "usdc-id",
        "currency": "USDC",
        "chain": "ETHEREUM",
        "label": "USD Coin"
      }
    }
  ]
}
6

6. Calculate Fees

Calculate fees before creating ramp requests
POST /v1/fees/calculate
Content-Type: application/json

{
  "amount": 1000.00,
  "type": "ON_RAMP"
}
Response:
{
  "success": true,
  "result": {
    "amount": 10.00,
    "percentage": 1.0
  }
}
7

7. Create Ramp Requests

Create on-ramp or off-ramp transactionsOn-Ramp Example:
POST /v1/ramp-requests
Content-Type: application/json

{
  "rampType": "ON_RAMP",
  "amount": 1000.00,
  "fiatCurrencyId": "eur-currency-id",
  "cryptoCurrencyId": "usdc-ethereum-id",
  "companyWalletId": "your-wallet-id"
}
Off-Ramp Example:
POST /v1/ramp-requests
Content-Type: application/json

{
  "rampType": "OFF_RAMP",
  "amount": 0.5,
  "cryptoCurrencyId": "usdc-ethereum-id",
  "fiatCurrencyId": "eur-currency-id",
  "companyBankAccountId": "your-bank-account-id"
}
Request is created in AWAITING_APPROVAL status.
8

8. Approve Ramp Request

Approve the ramp request to proceed
POST /v1/ramp-requests/{id}/approve
Content-Type: application/json

{
  "version": 1
}
Status changes to AWAITING_FUNDS.
  • On-Ramp: Customer sends fiat to provided deposit bank account
  • Off-Ramp: Customer sends crypto to provided deposit wallet
9

9. Monitor Status

Poll or use webhooks to monitor ramp request status
GET /v1/ramp-requests/{id}
Status Flow:
AWAITING_APPROVAL β†’ AWAITING_FUNDS β†’ PROCESSING β†’ SUCCEEDED

User Management

Invite Users

POST /v1/company/users/invite
Content-Type: application/json

{
  "email": "user@example.com",
  "role": "COMPANY_MANAGER",
  "firstName": "John",
  "lastName": "Doe"
}

User Roles

RolePermissions
COMPANY_ADMINFull access including user management
COMPANY_MANAGERCreate and manage ramp requests
COMPANY_VIEWERRead-only access

Update User Role

PUT /v1/company/users/{userId}/role
Content-Type: application/json

{
  "role": "COMPANY_ADMIN"
}

Best Practices

Authentication

Token Management: Implement token refresh logic to handle expired tokens gracefully.
// Example: Token refresh logic
async function getAccessToken() {
  if (tokenExpired()) {
    return await refreshToken();
  }
  return currentToken;
}

Error Handling

Optimistic Locking: Always handle HTTP 409 conflicts by fetching the latest version and retrying.
async function updateResource(id, data) {
  try {
    return await api.patch(`/resource/${id}`, data);
  } catch (error) {
    if (error.status === 409) {
      // Fetch latest version and retry
      const latest = await api.get(`/resource/${id}`);
      data.version = latest.version;
      return await api.patch(`/resource/${id}`, data);
    }
    throw error;
  }
}

Pagination

Efficient Pagination: Use appropriate page sizes and implement cursor-based pagination for large datasets.
GET /v1/ramp-requests?page=1&size=50&sortOn=createdAt&sortOrder=DESC

Webhooks

Real-time Updates: Configure webhooks for real-time notifications instead of polling.
Configure webhooks to receive notifications for:
  • Ramp request status changes
  • Payment received confirmations
  • Transaction completions

Testing

Sandbox Environment

Use the sandbox environment for testing:
  • Test OAuth2 authentication
  • Create test ramp requests
  • Verify webhook integrations
  • Test error scenarios

Test Scenarios

  1. Successful On-Ramp: Create, approve, and complete an on-ramp request
  2. Successful Off-Ramp: Create, approve, and complete an off-ramp request
  3. Cancellation: Create and cancel a ramp request
  4. Rejection: Create and reject a ramp request
  5. Version Conflict: Test optimistic locking behavior

Common Integration Patterns

Pattern 1: Automated On-Ramp

// 1. Create ramp request
const request = await createRampRequest({
  rampType: 'ON_RAMP',
  amount: 1000,
  fiatCurrencyId: eurId,
  cryptoCurrencyId: usdcId,
  companyWalletId: walletId
});

// 2. Auto-approve if within limits
if (request.amount <= autoApprovalLimit) {
  await approveRampRequest(request.id, request.version);
}

// 3. Monitor status via webhook
// Webhook handler will process status updates

Pattern 2: Batch Processing

// Process multiple ramp requests efficiently
const requests = await listRampRequests({
  status: 'AWAITING_APPROVAL',
  page: 1,
  size: 100
});

for (const request of requests.result) {
  if (shouldApprove(request)) {
    await approveRampRequest(request.id, request.version);
  }
}

Security Considerations

Never expose:
  • OAuth2 client secrets
  • Access tokens in client-side code
  • Private keys or seed phrases
  • API credentials in version control

Secure Storage

  • Store credentials in environment variables or secure vaults
  • Use HTTPS for all API communications
  • Implement proper access controls
  • Rotate credentials regularly

API Scopes

Request only the OAuth2 scopes you need:
  • view:ramp-request - View ramp requests
  • create:ramp-request - Create ramp requests
  • approve:ramp-request - Approve ramp requests
  • manage:company-wallet - Manage wallets
  • manage:company-bank-account - Manage bank accounts

Next Steps

API Reference

Explore full API documentation

Accounts Guide

Manage bank accounts & wallets

Transactions

Create and manage ramp requests

Fees

Understand fee structure

Security

Security best practices

Quick Reference

Quick API overview

Support

Need help with integration?