# Convert API

> Converteer cryptovaluta rechtstreeks vanuit uw handelssaldo — ontvang een live koers en voer uit tegen de marktprijs.

Met de Convert API kunt u wisselen tussen de valuta's in uw handelssaldo tegen de huidige marktprijs — dezelfde engine die het tabblad **Swap** in het handelsdashboard aandrijft, nu aan te roepen vanuit uw backend.

> **WARNING:** Convert-endpoints worden ondertekend met uw **reguliere API-sleutel** — dezelfde die wordt gebruikt voor [Payment API](/docs/payments)-verzoeken, **niet** de Payout API-sleutel. Het uitvoeren van een conversie debiteert en crediteert onmiddellijk uw handelssaldo; behandel deze sleutel dus met dezelfde zorg als elke referentie die geld verplaatst.

## Conversieprijs opvragen

Geeft een indicatieve koers voor een conversie tegen de huidige marktprijs — de effectieve koers en de resulterende bedragen. Er wordt niets gedebiteerd of gereserveerd; roep dit zo vaak aan als nodig voordat u uitvoert.

`POST /v1/convert/price`

### Verzoekparameters

| Veld | Type | Verplicht | Beschrijving | Waarde |
|------|------|-----------|--------------|--------|
| `from_currency` | string | ja | Bronvaluta | `BTC`, `ETH`, `USDT`, `USDC`, `TRX`, `BNB`, `GRAM`, `SOL`, `POL`, `LTC`, `DASH`, `DOGE`, `ZEC`, `XRP`, `XMR` |
| `to_currency` | string | ja | Doelvaluta. Moet verschillen van `from_currency` | `USDT`, `USDC`, `BTC`, `ETH`, `TRX`, `BNB`, `GRAM`, `SOL`, `POL`, `LTC`, `DASH`, `DOGE`, `ZEC`, `XRP`, `XMR` |
| `amount` | decimal | ja | Te converteren bedrag, groter dan `0` |  |
| `amount_type` | string | ja | Op welke kant `amount` betrekking heeft | `from`, `to` |

> **INFO:** `amount_type=from` besteedt precies `amount` aan `from_currency`. `amount_type=to` ontvangt precies `amount` aan `to_currency`.

**🟢 200 OK** · `application/json`

```json
{
  "state": 0,
  "result": {
    "success": true,
    "from_currency": "BTC",
    "to_currency": "USDT",
    "amount_type": "from",
    "from_amount": "0.01000000",
    "to_amount": "947.86690000",
    "effective_rate": "94786.69000000",
    "from_amount_usd": "947.87",
    "to_amount_usd": "947.87"
  }
}
```

#### Responsvelden

| Veld | Type | Beschrijving |
|------|------|--------------|
| `success` | boolean | Of de koers succesvol is berekend |
| `from_currency` | string | Bronvaluta |
| `to_currency` | string | Doelvaluta |
| `amount_type` | string | Weerspiegelt de `amount_type` van het verzoek |
| `from_amount` | string | Bedrag dat gedebiteerd zou worden in `from_currency` |
| `to_amount` | string | Bedrag dat gecrediteerd zou worden in `to_currency` |
| `effective_rate` | string | Koers toegepast op deze koersaanvraag — 1 eenheid `from_currency` in `to_currency` (bevat al de prijsstelling van het platform) |
| `from_amount_usd` | string \| null | USD-equivalent van `from_amount` |
| `to_amount_usd` | string \| null | USD-equivalent van `to_amount` |

- De koers is **puur indicatief** — de marktprijs kan veranderen tussen de koersaanvraag en de uitvoeringsaanroep.
- Deze aanroep debiteert of reserveert geen saldo.

> Use your project UUID and the endpoint-appropriate API key from the merchant dashboard.

#### Interactive request: `POST /v1/convert/price`
  - `from_currency` (enum, required): BTC,ETH,USDT,USDC,TRX,BNB,GRAM,SOL,POL,LTC,DASH,DOGE,ZEC,XRP,XMR
  - `to_currency` (enum, required): USDT,USDC,BTC,ETH,TRX,BNB,GRAM,SOL,POL,LTC,DASH,DOGE,ZEC,XRP,XMR
  - `amount` (decimal, required)
  - `amount_type` (enum, required): from,to

## Conversie uitvoeren

Voert een conversie uit tegen de huidige marktprijs en werkt uw handelssaldo bij. Er is geen aparte stap om "een koers te bevestigen" — roep dit endpoint direct aan met het bedrag dat u wilt converteren.

`POST /v1/convert`

> **INFO:** **Idempotentie.** Het herhalen van exact hetzelfde verzoek (dezelfde `from_currency`, `to_currency`, `amount`, `amount_type`) binnen ongeveer een minuut na de eerste aanroep geeft de bestaande conversie terug in plaats van een tweede aan te maken. Na dat venster wordt een identiek verzoek behandeld als een nieuwe conversie — probeer bij een time-out niet blindelings opnieuw zonder eerst het vorige resultaat te controleren.

> **WARNING:** Dit endpoint is beperkt tot **10 verzoeken per minuut** per aanroeper — strenger dan de algemene API-limiet — omdat elke aanroep echt saldo verplaatst.

### Verzoekparameters

| Veld | Type | Verplicht | Beschrijving | Waarde |
|------|------|-----------|--------------|--------|
| `from_currency` | string | ja | Bronvaluta | `BTC`, `ETH`, `USDT`, `USDC`, `TRX`, `BNB`, `GRAM`, `SOL`, `POL`, `LTC`, `DASH`, `DOGE`, `ZEC`, `XRP`, `XMR` |
| `to_currency` | string | ja | Doelvaluta. Moet verschillen van `from_currency` | `USDT`, `USDC`, `BTC`, `ETH`, `TRX`, `BNB`, `GRAM`, `SOL`, `POL`, `LTC`, `DASH`, `DOGE`, `ZEC`, `XRP`, `XMR` |
| `amount` | decimal | ja | Te converteren bedrag, groter dan `0` |  |
| `amount_type` | string | ja | Op welke kant `amount` betrekking heeft | `from`, `to` |

**🟢 200 OK** · `application/json`

```json
{
  "state": 0,
  "result": {
    "id": 12345,
    "type": "manual",
    "status": "completed",
    "from_currency": "BTC",
    "to_currency": "USDT",
    "from_amount": "0.01000000",
    "requested_from_amount": "0.01000000",
    "refund_amount": null,
    "to_amount": "947.86690000",
    "exchange_rate": "94786.69000000",
    "fee_amount": "0.00000000",
    "from_amount_usd": "947.87",
    "to_amount_usd": "947.87",
    "processed_at": "2026-01-20T15:30:24Z",
    "created_at": "2026-01-20T15:30:22Z"
  }
}
```

#### Responsvelden

| Veld | Type | Beschrijving |
|------|------|--------------|
| `id` | int | Door het systeem toegewezen conversieorder-ID |
| `type` | string | Altijd `manual` voor deze API |
| `status` | string | Huidige status (zie «Conversiestatussen» hieronder) |
| `from_currency` | string | Bronvaluta |
| `to_currency` | string | Doelvaluta |
| `from_amount` | string | Gedebiteerd bedrag in `from_currency` |
| `requested_from_amount` | string \| null | Uw oorspronkelijk gevraagde bronbedrag wanneer `amount_type = from`. `null` wanneer `amount_type = to` |
| `refund_amount` | string \| null | Deel van het vooraf gedebiteerde bedrag dat aan u is terugbetaald na een gedeeltelijke uitvoering. `null` als de order volledig is uitgevoerd |
| `to_amount` | string | Gecrediteerd bedrag in `to_currency` |
| `exchange_rate` | string | Koers die daadwerkelijk op deze conversie is toegepast — 1 eenheid `from_currency` in `to_currency` (bevat al de prijsstelling van het platform) |
| `fee_amount` | string | Platformkosten in rekening gebracht voor deze conversie, uitgedrukt in `from_currency` of `to_currency` afhankelijk van de handelsrichting. Al verwerkt in `exchange_rate` — hier getoond voor transparantie |
| `from_amount_usd` | string \| null | USD-equivalent van `from_amount` |
| `to_amount_usd` | string \| null | USD-equivalent van `to_amount` |
| `processed_at` | string (ISO 8601) \| null | Moment waarop de conversie klaar was met uitvoeren. `null` zolang deze nog wordt verwerkt |
| `created_at` | string (ISO 8601) | Moment waarop de conversieorder is aangemaakt |

#### Conversiestatussen

| Status | Beschrijving |
|--------|--------------|
| `pending` | Aangemaakt, nog niet naar de markt gestuurd |
| `processing` | Saldo vergrendeld, order op de markt geplaatst |
| `completed` | Volledig uitgevoerd — `to_amount` is bijgeschreven op uw saldo |
| `failed` | Kon niet worden uitgevoerd — een eventueel vooraf gedebiteerd bedrag is automatisch terugbetaald |
| `partially_completed` | Alleen voor valutaparen zonder directe markt (gerouteerd via een tussenliggende valuta): de eerste stap is voltooid maar de tweede is mislukt. U wordt gecrediteerd in de tussenliggende valuta in plaats van `to_currency` — converteer opnieuw vanaf daar om uw oorspronkelijke doel te bereiken |

#### Interactive request: `POST /v1/convert`
  - `from_currency` (enum, required): BTC,ETH,USDT,USDC,TRX,BNB,GRAM,SOL,POL,LTC,DASH,DOGE,ZEC,XRP,XMR
  - `to_currency` (enum, required): USDT,USDC,BTC,ETH,TRX,BNB,GRAM,SOL,POL,LTC,DASH,DOGE,ZEC,XRP,XMR
  - `amount` (decimal, required)
  - `amount_type` (enum, required): from,to

## Fouten

Bij een fout heeft de respons `state: 1` en een `error_code` — gedeeld door `/v1/convert/price` en `/v1/convert`:

**🔴 422 / 400** · `application/json`

```json
{
  "state": 1,
  "error_code": "amount_too_small",
  "errors": {
    "amount": "Amount is too small for this conversion. Please increase the amount and try again."
  }
}
```

| `error_code` | HTTP-status | Beschrijving |
|--------------|-------------|--------------|
| `validation_failed` | 422 | Ongeldige of ontbrekende parameters, of afwijzing door een bedrijfsregel (bijv. onvoldoende saldo) — zie het veld `errors` voor details |
| `amount_too_small` | 422 | `amount` ligt onder de minimaal verhandelbare grootte voor dit valutapaar |
| `convert_unavailable` | 400 | De conversie kon nu niet worden uitgevoerd (marktgegevens niet beschikbaar of geen route tussen de twee valuta's) — probeer het straks opnieuw |
| `internal_error` | 400 | Onverwachte interne serverfout tijdens het verwerken van het verzoek |

## Automatische conversie van inkomende betalingen

Automatisch converteren is een projectinstelling voor inkomende facturen en statische portemonnee-credits. Het wordt geconfigureerd in het merchant dashboard, niet door velden toe te voegen aan `/v1/payment`. Elke regel selecteert één of meer bronvaluta's en een doelvaluta.

Wanneer de conversie is voltooid, kunnen betalingsinformatie en merchant webhooks het volgende bevatten:

```json
{
  "payment_amount": "0.14800000",
  "merchant_amount": "0.146520000000000000",
  "payer_currency": "XMR",
  "convert": {
    "to_currency": "USDT",
    "commission": "0.09000000",
    "rate": "323.21000000",
    "amount": "47.262015740000000000"
  }
}
```

De bedrag-domeinen zijn opzettelijk gescheiden:

- `payment_amount` — wat op de blockchain is gedetecteerd in de bronbetalingsvaluta;
- `merchant_amount` — het netto-bronbedrag dat aan de merchant kan worden toegeschreven vóór conversie;
- `convert.amount` — het bedrag dat is bijgeschreven in `convert.to_currency`;
- `convert.rate` en `convert.commission` — het uitgevoerde conversieresultaat, niet een prijs die u lokaal zou moeten herberekenen.

> **WARNING:** Het ontbreken van `convert` is betekenisvol: conversie is mogelijk niet voltooid, mogelijk niet geconfigureerd voor die bron, of kan zijn teruggevallen op bronvalutakrediet. Bedenk nooit een doelbedrag op basis van `/exchange-rates` of een openbare marktprijs.

### Automatische conversiefout en terugval

Conversie vindt plaats na het ontvangen van de blockchain-betaling. Marktbeschikbaarheid, minimale ordergroottes, precisielimieten, time-outs bij beurzen en onvoldoende uitvoerbare liquiditeit kunnen conversie vertragen of verhinderen.

- Stortingen onder de globale/projectminimum worden omzeild in de conversiepijplijn en worden in de bronvaluta bijgeschreven.
- Tijdelijke fouten kunnen asynchroon opnieuw worden geprobeerd.
- Grote of niet verhandelbare stortingen kunnen terugvallen op een bronvalutakrediet nadat het herproefbeleid is uitgeput.
- Een betaling kan daarom geldig zijn, zelfs wanneer de gewenste conversie naar de doelvaluta niet heeft plaatsgevonden.

Uw integratie moet eerst de geverifieerde betaling opslaan en vervolgens de daadwerkelijk bijgeschreven valuta reconciliëren aan de hand van betalingsinformatie, het optionele `convert`-blok en de saldi van de handelaar. Blokkeer de bevestiging van de betalingswebhook niet terwijl u wacht op uw eigen analyse- of notificatiesystemen.

### Automatische conversie acceptatietests

Test ten minste: succesvolle directe conversie, brug/multi-hop conversie, stof onder minimum, tijdelijke retry, terugval naar bronvaluta, onderbetaling, overbetaling, dubbele webhook, ontbrekende `convert`, en reconciliatie na een ambigu timeout.

## Handmatige conversie edge cases

- `/v1/convert/price` is een indicatieve preview; marktbeweging kan het uitvoeringsresultaat veranderen.
- `amount_type: from` corrigeert het verzoek aan de bronzijde, terwijl `amount_type: to` een bedrag aan de doelzijde aanvraagt. Verwissel de betekenis niet bij het tonen van de bevestigings-UI.
- Een paar zonder directe markt kan via een tussenliggende valuta worden geleid. Als slechts één been voltooid is, rapporteert `partially_completed` de tussenliggende credit.
- Als een execute-aanroep time-out, reconcileer dan voordat u het opnieuw probeert. Een marktorder kan worden uitgevoerd, zelfs wanneer de HTTP-respons ervan verloren gaat.
- Behandel `failed` als een toestand om te reconciliëren, niet als toestemming om een lokale compenserende balansboeking toe te passen; het platform is eigenaar van debet/vergoedingsboekhouding.