# Yugo Payments API > Yugo is a hosted payment solution enabling merchants to accept payments (payins) from customers and send funds (payouts) to recipients. Supports multiple payment rails including crypto, card payments, and open banking for both fiat and cryptocurrency transactions. ## Quick Start Base URLs: - Sandbox: https://sandbox-api.yugo.finance/api/v2 - Production: https://api.yugo.finance/api/v2 Authentication: API Key in `X-API-Key` header (contact support@yugo.finance to obtain) ## Glossary | Term | Description | |------|-------------| | Merchant | Business using Yugo's API to process transactions | | Payer | Customer paying the Merchant for goods/services | | Payin | Process of accepting funds from a Payer | | Payin Intent | Merchant's request to create a payin | | Settlement | Transferring payin funds to Merchant's account | | Recipient | Person receiving funds via a Payout | | Payout | Process of sending funds to a Recipient | | Payout Intent | Merchant's request to create a payout | ## Data Types ### MonetaryAmount String with up to 8 decimal places to preserve precision. ``` "5.12" "0.0000385" ``` ### Currency ISO 4217 code for fiat (EUR, USD) or crypto symbol (BTC, USDT, ETH). ### Timestamp ISO 8601 format: `2024-01-15T14:30:00Z` ### UUID Standard UUID format: `123e4567-e89b-12d3-a456-426614174000` --- # API Endpoints ## Payins ### Create Payin `POST /payins` Creates a new payin to accept funds from a payer. **Required Headers:** - `X-API-Key`: Your API key - `Idempotency-Key`: Unique key for safe retries (max 36 chars, UUID recommended) - `Content-Type`: application/json **Request Body (PayinIntent):** ```json { "amount": { "value": "100.00", "currency": "EUR" }, "payer": { "email": "customer@example.com", "first_name": "John", "last_name": "Doe", "country": "DE", "language": "de" }, "payment": { "method": "card" }, "settlement": { "method": "yugo_balance" }, "reference": "order_123", "return_url": "https://merchant.com/checkout/123", "webhook_url": "https://merchant.com/webhooks/payin" } ``` **Payment Methods (payment.method):** - `card` - Credit/debit card - `bank_account` - Open banking (optional: `bank_id` from GET /banks) - `crypto_transfer` - Cryptocurrency transfer - `google_pay` - Google Pay - `apple_pay` - Apple Pay - `yugo_wallet` - Yugo Wallet (requires `email`) **Settlement Methods (settlement.method):** - `yugo_balance` - Settle to merchant's Yugo balance - `bank_account` - Settle to bank account (optional: `iban`) - `crypto_transfer` - Settle to crypto wallet (optional: `address`, `network`) **Response (201 Created):** ```json { "id": "550e8400-e29b-41d4-a716-446655440000", "status": "CREATED", "created_at": "2024-01-15T14:30:00Z", "expires_at": "2024-01-15T15:30:00Z", "amount": { "value": "100.00", "currency": "EUR" }, "payer": { "email": "customer@example.com" }, "reference": "order_123", "return_url": "https://merchant.com/checkout/123" } ``` **Payin Statuses:** - `CREATED` - Payin intent created, awaiting payer - `INITIATED` - Payer landed on Yugo hosted page - `AUTHORIZED` - Payer authorized the payment - `SETTLED` - Funds sent to merchant - `COMPLETED` - Transaction finalized - `DISPUTED` - Payer raised a dispute - `EXPIRED` - Payin expired before completion - `FAILED` - Payin failed ### Get Payin `GET /payins/{id}` Retrieves a specific payin by ID. **Response (200 OK):** Same as Create Payin response ### List Payins `GET /payins` **Query Parameters:** - `page` (integer, default: 1) - Page number - `page_size` (integer, default: 20, max: 100) - Items per page - `reference` (string) - Filter by merchant reference **Response (200 OK):** ```json { "content": [{ /* Payin objects */ }], "page": 1, "page_size": 20, "has_more": true } ``` --- ## Payouts ### Create Payout `POST /payouts` Creates a new payout to send funds to a recipient. **Required Headers:** - `X-API-Key`: Your API key - `Idempotency-Key`: Unique key for safe retries - `Content-Type`: application/json **Request Body (PayoutIntent):** ```json { "amount": { "value": "50.00", "currency": "EUR" }, "recipient": { "country": "DE", "language": "de" }, "payment": { "method": "bank_account", "iban": "DE89370400440532013000" }, "reference": "withdrawal_456", "return_url": "https://merchant.com/withdrawal/456", "webhook_url": "https://merchant.com/webhooks/payout" } ``` **Payment Methods (payment.method):** - `bank_account` - Bank transfer (optional: `iban`) - `crypto_transfer` - Crypto transfer (optional: `address`, `network`) - `yugo_wallet` - Yugo Wallet (optional: `email`) **Response (201 Created):** ```json { "id": "660e8400-e29b-41d4-a716-446655440001", "status": "CREATED", "created_at": "2024-01-15T14:30:00Z", "expires_at": "2024-01-15T15:30:00Z", "amount": { "value": "50.00", "currency": "EUR" }, "reference": "withdrawal_456", "return_url": "https://merchant.com/withdrawal/456" } ``` **Payout Statuses:** - `CREATED` - Payout intent created - `INITIATED` - Payout details gathering initiated - `PROCESSING` - Payout is being processed - `COMPLETED` - Payout successful - `FAILED` - Payout failed ### Get Payout `GET /payouts/{id}` ### List Payouts `GET /payouts` Same pagination parameters as List Payins. --- ## Accounts ### List Accounts `GET /accounts` Retrieves merchant accounts with their balances. **Query Parameters:** - `page`, `page_size` - Pagination - `currency` - Filter by currency code **Response (200 OK):** ```json { "content": [ { "id": "770e8400-e29b-41d4-a716-446655440002", "label": "EUR Balance", "currency": "EUR", "available_balance": "1500.00", "reserved_balance": "100.00" } ], "page": 1, "page_size": 20, "has_more": false } ``` --- ## Banks ### List Banks `GET /banks` Retrieves banks available for open banking payments. **Response (200 OK):** ```json { "content": [ { "id": "880e8400-e29b-41d4-a716-446655440003", "name": "Example Bank", "logo_url": "https://example.com/logos/bank.png" } ], "page": 1, "page_size": 20, "has_more": false } ``` --- # Webhooks Yugo sends HTTP POST requests to your `webhook_url` when payment status changes. **Events:** - Payin Status Changed - Payout Status Changed **Webhook Headers:** ``` POST /your-webhook-endpoint Content-Type: application/json X-API-Key: your_api_key ``` **Verify webhooks** by checking `X-API-Key` matches your API key. **Payload:** Complete Payin or Payout object in JSON. **Requirements:** - Accept POST requests - Return 200-299 status to acknowledge - Respond within 1 second - Use HTTPS in production - Handle duplicates (be idempotent) **Retry behavior:** Exponential backoff for up to 48 hours on failures. --- # Idempotency All POST requests require an `Idempotency-Key` header. **Rules:** - Max 36 characters (UUID recommended) - Same key = same response (no duplicate operations) - Keys expire after 24 hours - Different request body with same key returns original response **Example with retry logic:** ```javascript async function createPayin(payinIntent, idempotencyKey) { const response = await fetch('https://api.yugo.finance/api/v2/payins', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-API-Key': API_KEY, 'Idempotency-Key': idempotencyKey }, body: JSON.stringify(payinIntent) }); return response.json(); } // Safe to retry with same key on network errors const key = `order_${orderId}_payin`; const payin = await createPayin(intent, key); ``` --- # Error Handling Errors follow RFC 9457 Problem Details format. **Response (application/problem+json):** ```json { "type": "https://yugo.finance/problems/validation-error", "title": "Validation Error", "status": 422, "detail": "Request validation failed", "errors": [ { "detail": "must be a positive number", "pointer": "#/amount/value" } ] } ``` **HTTP Status Codes:** - `400` - Bad Request (malformed syntax) - `401` - Unauthorized (invalid/missing API key) - `403` - Forbidden (insufficient permissions) - `404` - Not Found - `422` - Validation Error - `429` - Too Many Requests (rate limited) - `500` - Internal Server Error --- # Code Examples ## Create a Payin (Node.js) ```javascript const response = await fetch('https://sandbox-api.yugo.finance/api/v2/payins', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-API-Key': 'your_api_key', 'Idempotency-Key': crypto.randomUUID() }, body: JSON.stringify({ amount: { value: '100.00', currency: 'EUR' }, payer: { email: 'customer@example.com' }, return_url: 'https://yoursite.com/checkout/complete', webhook_url: 'https://yoursite.com/webhooks/yugo' }) }); const payin = await response.json(); // Redirect customer to Yugo hosted page or handle response ``` ## Create a Payout (Python) ```python import requests import uuid response = requests.post( 'https://sandbox-api.yugo.finance/api/v2/payouts', headers={ 'Content-Type': 'application/json', 'X-API-Key': 'your_api_key', 'Idempotency-Key': str(uuid.uuid4()) }, json={ 'amount': {'value': '50.00', 'currency': 'EUR'}, 'payment': {'method': 'bank_account', 'iban': 'DE89370400440532013000'}, 'return_url': 'https://yoursite.com/withdrawal/complete', 'webhook_url': 'https://yoursite.com/webhooks/yugo' } ) payout = response.json() ``` ## Webhook Handler (Express.js) ```javascript app.post('/webhooks/yugo', (req, res) => { // Verify API key if (req.headers['x-api-key'] !== process.env.YUGO_API_KEY) { return res.status(401).send('Unauthorized'); } const event = req.body; // Handle idempotently (check if already processed) if (await alreadyProcessed(event.id)) { return res.status(200).send('OK'); } // Process based on status if (event.status === 'AUTHORIZED') { await fulfillOrder(event.reference); } else if (event.status === 'FAILED') { await handleFailedPayment(event.reference); } // Acknowledge quickly res.status(200).send('OK'); }); ``` --- # Resources - Full Documentation: https://docs.yugo.finance - OpenAPI Specification: https://docs.yugo.finance/static/openapi/payments.yaml - API Support: support@yugo.finance - Support Portal: https://support.yugo.finance