Skip to main content

What is a Ramp?

A Ramp is a transaction that converts between fiat currency and cryptocurrency. KillB supports both on-ramps (fiat → crypto) and off-ramps (crypto → fiat).
Think of ramps as the bridge between traditional banking and cryptocurrency. They handle the entire conversion process from quote to settlement.

Ramp Types

Fiat → CryptocurrencyConvert local currency (COP, MXN, USD) into stablecoins (USDC, USDT).Flow:
  1. User gets a quote (e.g., 100,000 COP → 23.8 USDC)
  2. User creates ramp with wallet address
  3. User pays via PSE/SPEI/ACH
  4. KillB processes conversion
  5. USDC/USDT sent to user’s wallet
Common Use Cases:
  • Buying crypto with local currency
  • Funding DeFi positions
  • Cross-border remittances
  • Crypto investing

Ramp Lifecycle

A ramp goes through multiple status stages during processing:

Ramp Status

Processing Statuses

CREATED
  • Ramp initialized, awaiting payment
  • Payment instructions provided to user
CASH_IN_REQUEST / CASH_IN_REQUESTED
  • Payment request sent to provider
  • Awaiting user payment
CASH_IN_PROCESSING
  • Payment received, being verified
  • Confirmation in progress
CASH_IN_COMPLETED
  • Payment confirmed
  • Ready for conversion
CONVERSION_PROCESSING
  • Converting fiat ↔ crypto
  • Executing trade
CONVERSION_COMPLETED
  • Conversion finished
  • Ready for disbursement
CASH_OUT_PROCESSING
  • Sending funds to destination
  • Transaction in progress
CASH_OUT_COMPLETED
  • Funds sent to destination
  • Awaiting final confirmation
COMPLETED
  • Transaction fully completed
  • Funds delivered to user
  • Receipt available
FAILED
  • Transaction failed at some stage
  • Check details field for reason
  • May be eligible for retry
CANCELED 🚫
  • Canceled by user or system
  • No funds transferred
  • Refund initiated if applicable
REJECTED
  • Rejected by compliance or provider
  • Check note for details
  • May require additional verification
ERROR ⚠️
  • System error occurred
  • Contact support with ramp ID
  • Will be investigated and resolved

Creating a Ramp

Prerequisites

Before creating a ramp, you need:
1

User

A verified user with appropriate KYC level
2

Account

An active account (bank or wallet) as destination
3

Quotation

A valid, non-expired quotation

Basic Ramp Creation

POST /api/v2/ramps
Request:
{
  "quotationId": "quot-9f8e7d6c-5b4a-3c2d-1e0f",
  "userId": "4d23aa52-1b40-4584-a8ea-58aba6099c5c",
  "accountId": "7c8b9a3d-2f1e-4b5c-9d8e-1a2b3c4d5e6f"
}
Response:
{
  "id": "ramp-1a2b3c4d-5e6f-7g8h-9i0j",
  "status": "CREATED",
  "type": "ON",
  "fromCurrency": "COP",
  "toCurrency": "USDC",
  "fromAmount": 100000,
  "toAmount": 23.81,
  "cashInMethod": "PSE",
  "cashOutMethod": "POLYGON",
  "paymentInfo": [{
    "url": "https://checkout.pse.com.co/payment/123456"
  }],
  "isPreFunded": false,
  "externalId": null,
  "createdAt": "2024-01-15T10:30:00.000Z"
}

Multiple Destination Accounts

You can split a ramp across multiple destination accounts:
{
  "quotationId": "quot-id",
  "userId": "user-id",
  "accounts": [
    {
      "id": "account-1",
      "amount": 50
    },
    {
      "id": "account-2",
      "amount": 50
    }
  ]
}
Useful for splitting payments, diversifying across wallets, or managing multiple beneficiaries.

Payment Information

Based on the payment method, different payment information is returned:
{
  "paymentInfo": [{
    "url": "https://checkout.pse.com.co/payment/abc123"
  }]
}
  • Redirect user to the url
  • User completes payment through PSE
  • Webhook notifies of payment completion

Refund Instructions

For on-ramps, provide refund instructions in case of failure:
{
  "quotationId": "quot-id",
  "userId": "user-id",
  "accountId": "account-id",
  "refundInstructions": {
    "clabe": "012345678901234567",
    "beneficiary": "Juan García"
  }
}
Refund instructions must match the cash-in method (SPEI requires CLABE, crypto requires wallet address).

External ID

Use externalId to prevent duplicate ramps and track transactions:
{
  "quotationId": "quot-id",
  "userId": "user-id",
  "accountId": "account-id",
  "externalId": "order-12345-from-my-system"
}
Benefits:
  • Prevent duplicate submissions
  • Track ramps in your system
  • Idempotency for retries
  • Easier reconciliation

Monitoring Ramps

Get Ramp by ID

GET /api/v2/ramps/{rampId}

Query Ramps

GET /api/v2/ramps?userId=user-id&status=PROCESSING
Filter Options:
  • id - Specific ramp ID
  • externalId - Your system ID
  • status - Filter by status
  • limit, page - Pagination

Status History

Track all status changes:
GET /api/v2/ramps/{rampId}/status-history
Returns chronological list of all status transitions.

Ramp Receipts

Get transaction receipts in multiple formats:
GET /api/v2/ramps/{rampId}/receipt
Returns HTML receipt suitable for displaying in browser or email.

Pre-Funded Ramps

Pre-funded ramps execute instantly:
{
  "quotationId": "quot-id",
  "userId": "user-id",
  "accountId": "account-id"
}
When quotation uses PRE_FUND or PRE_FUND_* methods:
  • No payment confirmation needed
  • Instant execution
  • Immediate status progression
  • Faster completion (minutes vs hours)
Status Flow: CREATEDCONVERSION_PROCESSINGCASH_OUT_PROCESSINGCOMPLETED

Handling Failures

Common Failure Reasons

ReasonDescriptionSolution
INSUFFICIENT_FUNDSNot enough balance in sourceUser needs to fund account
INVALID_ACCOUNTDestination account invalidVerify account details
COMPLIANCE_HOLDCompliance review requiredWait for manual review
PROVIDER_ERRORExternal provider issueRetry or contact support
EXPIRED_QUOTEQuotation expiredCreate new quotation

Checking Failure Details

{
  "id": "ramp-id",
  "status": "FAILED",
  "details": "INSUFFICIENT_FUNDS: Not enough balance in pre-fund account",
  "transferProof": null
}

Error Handling Guide

Learn best practices for handling ramp failures

Webhooks for Ramps

Subscribe to ramp events for real-time updates: Event Type: RAMP Actions:
  • CREATE - Ramp initialized
  • UPDATE - Ramp status changed (includes all status transitions)
  • DELETE - Ramp canceled (rare)
Common Status Updates:
  • Payment received (CASH_IN_COMPLETED)
  • Conversion finished (CONVERSION_COMPLETED)
  • Ramp fully completed (COMPLETED)
  • Ramp failed (FAILED)
  • Ramp canceled (CANCELED)
Webhook Payload Example
{
  "id": "evt_a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
  "event": "RAMP",
  "action": "UPDATE",
  "data": {
    "id": "be4d353b-00a2-4309-9ef1-594f37dfb1fd",
    "userId": "2bc703f2-1c54-4cbb-a144-993e1d957688",
    "accountId": "f7df00af-5d12-4b33-b5ab-e2b32290ebad",
    "quotationId": "a656a475-0d53-479e-8f30-91582ecf450b",
    "type": "ON",
    "status": "COMPLETED",
    "cashInMethod": "PSE",
    "cashOutMethod": "POLYGON",
    "fromCurrency": "COP",
    "toCurrency": "USDC",
    "fromAmount": 100000,
    "toAmount": 23.81,
    "transferProof": "0x8e2b1f4645ebc8b6f658c860980567a63d283a42735be7401a7950306a2539b0",
    "isPreFunded": false,
    "active": true,
    "accounts": [
      {
        "id": "f7df00af-5d12-4b33-b5ab-e2b32290ebad",
        "amount": 23.81
      }
    ],
    "createdAt": "2025-01-15T23:46:10.226Z",
    "updatedAt": "2025-01-16T00:29:06.813Z"
  },
  "createdAt": "2025-01-16T00:29:06.813Z",
  "updatedAt": "2025-01-16T00:29:06.813Z",
  "attempts": 0
}
You’ll receive webhook events for each status change. Filter by data.status to handle specific transitions like COMPLETED or FAILED.

Ramp Updates

Update ramp information (limited scenarios):
PATCH /api/v2/ramps/{rampId}
Updatable:
  • Destination accounts (before payment)
  • Account amounts distribution
Ramps cannot be modified after payment has been received.

Performance Considerations

Transaction Times

MethodTypical TimeNetwork Dependent
PSE5-30 minutes✅ Yes
SPEI10-60 minutes✅ Yes
ACH1-3 business days✅ Yes
Wire1 business day✅ Yes
Crypto (Polygon)2-5 minutes⛓️ Blockchain
Crypto (Solana)1-2 minutes⛓️ Blockchain
Pre-Funded< 5 minutes❌ No
For the best user experience, use Polygon for crypto transactions and pre-funded accounts for instant execution.

Best Practices

  • Never hardcode exchange rates
  • Create fresh quotation for each ramp
  • Respect quotation expiry (30 seconds)
  • Show users the exact amounts
  • Poll ramp status every 10-30 seconds
  • Use webhooks as primary notification
  • Polling as backup mechanism
  • Show users current status
  • Payment takes longer than expected
  • User closes browser during payment
  • Network connectivity issues
  • Quotation expires before creation
  • Insufficient funds scenarios
  • Provide unique externalId per ramp
  • Prevents duplicate transactions
  • Enables idempotent retries
  • Simplifies reconciliation
  • Save ramp ID immediately
  • Store all response data
  • Log status transitions
  • Keep payment proofs
  • Archive completed ramps

Testing Ramps

Sandbox Testing

In sandbox, use faker endpoints:
// Create ramp
const ramp = await createRamp(quoteId, userId, accountId);

// Simulate payment (sandbox only)
await fetch('/api/v2/faker/cash-in', {
  method: 'POST',
  headers: { 'Authorization': `Bearer ${token}` },
  body: JSON.stringify({ rampId: ramp.id })
});

// Poll for completion
const completed = await waitForStatus(ramp.id, 'COMPLETED');

Production Testing

Start with small amounts:
  1. Test with minimum (1010-50 equivalent)
  2. Verify complete flow end-to-end
  3. Check webhook delivery
  4. Confirm receipts generate
  5. Validate accounting
  6. Scale to larger amounts

Common Questions

Only if payment hasn’t been received yet. Once cash-in is completed, the ramp will process to completion.
Ramps expire after 24 hours if unpaid and move to EXPIRED status. No action needed from you.
  • Polygon: 2-5 minutes (128 block confirmations)
  • Solana: 1-2 minutes
  • Ethereum: 10-15 minutes
  • Tron: 1-3 minutes
No. Each ramp requires its own quotation. Quotations are single-use and expire after 30 seconds.
The rate is locked when you create the ramp using the quotation. Users receive the exact amount quoted.

Advanced Features

Split Disbursements

Send funds to multiple accounts:
{
  "quotationId": "quot-id",
  "userId": "user-id",
  "accounts": [
    { "id": "wallet-1", "amount": 60 },
    { "id": "wallet-2", "amount": 40 }
  ]
}

Transaction Metadata

Store custom data with your ramp:
{
  "quotationId": "quot-id",
  "userId": "user-id",
  "accountId": "account-id",
  "externalId": "order-123",
  "details": {
    "cashIn": {
      "transfiyaAccount": "3001234567"
    }
  }
}

Next Steps