Offramp - Sell Crypto

Convert cryptocurrency to fiat

Offramp - Sell Cryptocurrency

Convert cryptocurrency to fiat currency in your virtual account.

What is OFFRAMP?

OFFRAMP allows you to sell cryptocurrency and receive fiat funds in your virtual account.

Use cases:

  • Convert crypto holdings to fiat
  • Realize crypto gains
  • Prepare fiat for operations
  • Accept crypto payments and convert to fiat

Deals vs Orders

Important: OFFRAMP operations use the /deals endpoint, not /orders. A deal represents the intent to sell crypto and must be paid completely (no partial payments). The deal creates orders that execute the sale.

Key differences from ONRAMP:

  • Deal: The crypto sale intent (must be funded completely)
  • Order: The actual execution of the sale (created automatically by the deal)
  • No partial payments: OFFRAMP deals must be paid in full, unlike ONRAMP
  • Destination: Deals only need the destination virtual account

Quick Example

Node.js
1// Sell 10 USDC for COP
2
3// 1. Get quote (network required!)
4const quote = await axios.post(
5 `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/quotes`,
6 {
7 type: 'OFFRAMP',
8 originCurrencySymbol: 'USDC',
9 destinationCurrencySymbol: 'COP',
10 amountIn: 10, // 10 USDC
11 network: 'ETHEREUM' // Required for crypto quotes
12 },
13 { headers: { 'Authorization': `Bearer ${token}` } }
14);
15
16console.log('Will receive:', quote.data.amountOut, 'COP'); // e.g., 39,500 COP
17console.log('Quote valid for:', quote.data.validFor || '10-15', 'seconds');
18
19// 2. Create deal (not order!)
20const deal = await axios.post(
21 `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/deals`,
22 {
23 destinationAccountId: 'va_cop_12345', // Your COP virtual account
24 quoteId: quote.data.id
25 },
26 { headers: { 'Authorization': `Bearer ${token}` } }
27);
28
29console.log('Deal created:', deal.data.id);
30console.log('Deal must be paid completely');
31// Funds will be credited to COP virtual account after confirmation

Complete Payment Required: Unlike ONRAMP, OFFRAMP deals must be funded completely. Partial payments are not supported.


Step-by-Step Integration

Step 1: Get Quote

Get Quote
1const quote = await axios.post(
2 `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/quotes`,
3 {
4 type: 'OFFRAMP',
5 originCurrencySymbol: 'USDC',
6 destinationCurrencySymbol: 'COP',
7 amountIn: 10,
8 network: 'ETHEREUM' // Required for crypto quotes
9 },
10 { headers: { 'Authorization': `Bearer ${token}` } }
11);
12
13// Display to user
14console.log('Selling:', quote.data.amountIn, 'USDC');
15console.log('Will receive:', quote.data.amountOut, 'COP');
16console.log('Exchange rate:', quote.data.exchangeRate);
17console.log('Fee:', quote.data.koyweFee, 'COP');
18console.log('Quote expires in:', quote.data.validFor || '10-15', 'seconds');

Step 2: Create Deal

Create Deal
1const deal = await axios.post(
2 `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/deals`,
3 {
4 type: 'OFFRAMP',
5 destinationAccountId: 'va_cop_12345', // Only need destination virtual account
6 quoteId: quote.data.id,
7 externalId: `offramp-${Date.now()}`
8 },
9 { headers: { 'Authorization': `Bearer ${token}` } }
10);
11
12console.log('Deal created:', deal.data.id);
13console.log('Status:', deal.data.status); // "PENDING"
14console.log('Deposit address:', deal.data.depositAddress); // Where to send crypto

Simplified Request: Deals only need the destinationAccountId (virtual account) and quoteId. The crypto amount and currencies are already defined in the quote.

Step 3: Send Cryptocurrency

After creating the deal, send the cryptocurrency to the provided deposit address:

Get Deposit Info
1const dealDetails = await axios.get(
2 `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/deals/${deal.data.id}`,
3 { headers: { 'Authorization': `Bearer ${token}` } }
4);
5
6console.log('Send crypto to:', dealDetails.data.depositAddress);
7console.log('Amount to send:', dealDetails.data.amountIn, dealDetails.data.originCurrencySymbol);
8console.log('Network:', dealDetails.data.network);
9console.log('Must send complete amount - partial payments not allowed');

Step 4: Wait for Confirmation

Monitor via Webhooks
1app.post('/webhooks/koywe', (req, res) => {
2 const event = JSON.parse(req.body);
3
4 if (event.type === 'order.paid' && event.data.type === 'OFFRAMP') {
5 console.log('Crypto received and confirmed!');
6 }
7
8 if (event.type === 'order.completed' && event.data.type === 'OFFRAMP') {
9 console.log('Fiat credited to virtual account!');
10 console.log('Amount:', event.data.amountOut, event.data.destinationCurrencySymbol);
11 }
12
13 res.status(200).send('OK');
14});

Order Flow


Complete Example

Sell USDC
1async function sellUSDC(amount) {
2 try {
3 const token = await authenticate();
4
5 // 1. Get quote
6 const quote = await axios.post(
7 `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/quotes`,
8 {
9 type: 'OFFRAMP',
10 originCurrencySymbol: 'USDC',
11 destinationCurrencySymbol: 'COP',
12 amountIn: amount
13 },
14 { headers: { 'Authorization': `Bearer ${token}` } }
15 );
16
17 console.log(`Selling ${amount} USDC for ${quote.data.amountOut} COP`);
18 console.log(`Rate: 1 USDC = ${quote.data.exchangeRate} COP`);
19
20 // 2. Create offramp order
21 const order = await axios.post(
22 `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/orders`,
23 {
24 type: 'OFFRAMP',
25 originCurrencySymbol: 'USDC',
26 destinationCurrencySymbol: 'COP',
27 amountIn: amount,
28 quoteId: quote.data.id
29 },
30 { headers: { 'Authorization': `Bearer ${token}` } }
31 );
32
33 console.log('โœ“ Offramp order created:', order.data.id);
34 console.log('๐Ÿ“ Send USDC to:', order.data.depositAddress);
35 console.log('๐Ÿ’ฐ Amount:', order.data.amountIn, 'USDC');
36 console.log('๐ŸŒ Network:', order.data.network || 'Ethereum');
37
38 return {
39 orderId: order.data.id,
40 depositAddress: order.data.depositAddress,
41 amount: order.data.amountIn,
42 currency: order.data.originCurrencySymbol
43 };
44
45 } catch (error) {
46 console.error('Error:', error.response?.data || error.message);
47 throw error;
48 }
49}
50
51// Usage
52const offramp = await sellUSDC(10);
53console.log('Send your USDC to the deposit address above');

Important Notes

Blockchain Confirmations: OFFRAMP orders require blockchain confirmations. Settlement time varies by network:

  • Ethereum: 12-15 minutes (12 confirmations)
  • Polygon: 2-5 minutes (128 confirmations)
  • BSC: 3-5 minutes (15 confirmations)
  • Bitcoin: 30-60 minutes (3 confirmations)

One-time Address: Each OFFRAMP order generates a unique deposit address. Donโ€™t reuse addresses from previous orders.


Next Steps