We integrate crypto withdrawal to bank cards (off-ramp) using push-to-card technology. This involves connecting with payment networks like Visa Direct or Mastercard Send. In practice, one in two companies faces transaction declines due to bank filters or incorrect tokenization. Over the past year, we've completed 15 such integrations and developed an approach that raises transaction success to 95%. Our typical integration costs start from $5,000 and can save users up to 2% on fees compared to bank transfers. Depending on complexity, total project cost ranges from $5,000 to $15,000. Setup includes card verification via micro-deposit, AML screening, and an automatic retry system. For a recent client, we reduced monthly losses from declined transactions by $4,500 on average.
Why push-to-card is not just "transfer money"
Unlike pull transactions (debit from card), push-to-card uses a different API — Visa Direct or Mastercard Send. It's a direct credit to a debit card through the payment network. Providers require separate permissions and licensing — simply plugging in the API won't work. The underlying technology involves card tokenization and a dedicated transfer retry mechanism.
Visa Direct supports instant transfers to Visa debit cards in 200+ countries. Average posting time: 30 minutes in the US, several hours in the EU. Mastercard Send provides similar service for Mastercard cards. Access to these APIs is only through authorized technology partners (Marqeta, Stripe Issuing, Checkout.com Payouts, Modulr).
Visa Direct Documentation — official API description and requirements.
How card tokenization works for withdrawal
The user adds a card via API — we accept the data but don't store the PAN. Tokenization through Checkout.com or a similar provider replaces the card number with a one-time or permanent token. This is critical for security and PCI DSS compliance.
@app.post("/api/withdrawal-cards")
async def add_withdrawal_card(
card_data: CardData,
user: User = Depends(get_current_user)
):
# Tokenize via Checkout.com
token_resp = await checkout.tokenize_card({
"type": "card",
"number": card_data.number,
"expiry_month": card_data.expiry_month,
"expiry_year": card_data.expiry_year,
"name": card_data.holder_name,
})
# Verify card: small charge + return
verify_result = await verify_card_ownership(
token=token_resp["token"],
user_id=user.id
)
if verify_result.verified:
await db.save_withdrawal_card(
user_id=user.id,
token=token_resp["token"],
last4=card_data.number[-4:],
brand=token_resp["scheme"],
)
Integration via Checkout.com Payouts
import httpx
import uuid
class CheckoutPayoutsClient:
BASE_URL = "https://api.checkout.com"
def __init__(self, secret_key: str):
self.session = httpx.AsyncClient(
headers={"Authorization": f"Bearer {secret_key}"}
)
async def payout_to_card(
self,
card_token: str, # tokenized card
amount: int, # in minor units (cents)
currency: str,
reference: str,
recipient_name: str,
) -> dict:
payload = {
"source": {
"type": "currency_account",
"id": "ca_xxx", # your Checkout account
},
"destination": {
"type": "token",
"token": card_token,
},
"amount": amount,
"currency": currency,
"reference": reference,
"instruction": {
"purpose": "CRYPTO_WITHDRAWAL",
"charge_bearer": "CRED",
"funds_transfer_type": "FD", # Fund Disbursement
},
"sender": {
"type": "instrument",
"reference": str(uuid.uuid4()),
"first_name": "Platform",
"last_name": "Name",
},
}
resp = await self.session.post(
f"{self.BASE_URL}/transfers",
json=payload
)
return resp.json()
How to reduce decline rates?
Banks often block incoming push payments from crypto companies. The average success rate for off-ramp is 85–95%. Declines occur due to mismatch of cardholder name with KYC data, exceeding limits, or internal bank risk policies. To minimize rejections:
- Card verification: We perform micro-deposit verification: charge $0.01–$1.00 and ask the user to confirm the amount from their statement.
- BIN filtering: Exclude cards from banks that massively decline crypto transfers.
- Retry mechanism: Implement automatic retries with exponential backoff (up to 3 attempts) and a fallback to bank transfer.
Example: we use a RabbitMQ queue with retry mechanism. On decline, the transaction goes to a queue with a delay of 5 minutes, then 15, then 60. After the third attempt — an alert in Slack and transfer to a bank account via SEPA/ACH.
Comparison of off-ramp providers
| Provider | Integration type | Average speed | Availability | Fee (estimate) |
|---|---|---|---|---|
| Visa Direct | Push-to-card | 30 min – 2 h | 200+ countries | 0.5–1.5% + $0.50 |
| Mastercard Send | Push-to-card | 30 min – 2 h | 150+ countries | 0.5–2.0% + $0.50 |
| Checkout.com Payouts | Aggregator | 1–4 h | 180+ countries | 1–3% (all-in) |
Visa Direct is 2x faster than Mastercard Send in Asian countries due to local clearing networks. However, Mastercard Send often has lower fees in Europe.
Mastercard Send Developer Portal — detailed specifications and requirements.
Steps to integrate off-ramp
- Choose provider: Evaluate Visa Direct, Mastercard Send, or aggregators based on target region and fees.
- Set up tokenization: Integrate with a tokenization service (e.g., Checkout.com) to securely store card tokens.
- Implement card verification: Use micro-deposits to confirm card ownership and match with KYC.
- Configure retry logic: Build an automatic retry queue with exponential backoff and fallback to bank transfer.
- Monitor transactions: Set up alerts for declines and track success rates via dashboards like Tenderly.
- Perform AML check crypto: Integrate AML screening on every withdrawal request to comply with regulations.
What's included in the work?
| Step | Duration |
|---|---|
| Analysis and provider selection | 3–5 days |
| API integration (tokenization, sending) | 5–10 days |
| Verification and retries | 3–5 days |
| Monitoring and documentation | 2–3 days |
We set up the complete withdrawal pipeline to card turnkey:
- Selection and integration of provider (Visa Direct / Mastercard Send / aggregator)
- Implementation of card tokenization and secure storage
- Setup of verification (micro-deposit + KYC matching)
- Retry system and fallback to bank transfer
- Monitoring of transaction success and alerts for declines (via Tenderly or custom dashboard)
- API documentation and launch support
Timeline: from 2 to 4 weeks depending on provider and requirements. We'll estimate your project after consultation.
Schedule a consultation on off-ramp integration — we'll discuss your stack, limits, and speed requirements. We have over 5 years of experience in blockchain development and have completed 30+ projects with off-ramp integrations. We guarantee security and transparency — all operations pass AML screening.
Get a project estimate by contacting us.
Frequently Asked Questions
- Which cards are supported for crypto withdrawal to card?
- Debit Visa and Mastercard cards issued in 200+ countries are supported. Credit cards are not accepted by all providers — they require additional onboarding.
- How long does the transfer to card take?
- Typically 30 minutes to 2 hours, depending on the issuing bank's country and time of day. In rare cases, the transfer may take up to 24 hours due to internal bank checks.
- Why is my withdrawal to card declined?
- Declines usually relate to bank policies: some banks block push payments from crypto companies. The average success rate for off-ramp transactions is 85–95%. We configure a fallback to bank transfer and automatic retry attempts.
- How do you verify the card belongs to the user?
- We use micro-deposit verification: charge a small amount (usually $0.01–$1.00) and ask the user to confirm it. Additionally, we match the cardholder name with KYC data.
- What are the withdrawal limits via Visa Direct?
- The maximum single transaction amount is up to $50,000 (varies by country and bank). Daily and monthly limits are set by the provider — we help select optimal settings.







