This guide covers the technical details of integrating ZBD Onramp, including session management, widget parameters, and webhook handling.
Integration Flow
Initialize Session
Call the /api/v1/ramp-widget
endpoint from your backend
Load Widget
Embed the returned widget URL in an iframe
Handle Events
Process webhooks and frontend messages
Session Initialization
Create a widget session by calling our API from your backend. This ensures your API key remains secure.
Endpoint
POST https://api.zebedee.io/api/v1/ramp-widget
Request
curl -X POST https://api.zebedee.io/api/v1/ramp-widget \
-H "Content-Type: application/json" \
-H "apikey: YOUR_API_KEY" \
-d '{
"email": "player@game.com",
"webhook_url": "https://yourgame.com/webhooks/zbd",
"quote_currency": "USD",
"base_currency": "BTC",
"destination": "https://yourgame.com/purchase-complete",
"reference_id": "player_123_purchase_456",
"metadata": {
"player_id": "123",
"game_session": "abc"
}
}'
curl -X POST https://api.zebedee.io/api/v1/ramp-widget \
-H "Content-Type: application/json" \
-H "apikey: YOUR_API_KEY" \
-d '{
"email": "player@game.com",
"webhook_url": "https://yourgame.com/webhooks/zbd",
"quote_currency": "USD",
"base_currency": "BTC",
"destination": "https://yourgame.com/purchase-complete",
"reference_id": "player_123_purchase_456",
"metadata": {
"player_id": "123",
"game_session": "abc"
}
}'
const response = await fetch('https://api.zebedee.io/api/v1/ramp-widget', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': process.env.ZBD_API_KEY
},
body: JSON.stringify({
email: user.email,
webhook_url: 'https://yourgame.com/webhooks/zbd',
quote_currency: 'USD',
base_currency: 'BTC',
destination: 'https://yourgame.com/purchase-complete',
reference_id: `${user.id}_${purchaseId}`,
metadata: {
player_id: user.id,
game_session: sessionId
}
})
});
const data = await response.json();
Parameters
Parameter | Type | Required | Description |
---|
email | string | Yes | User’s email address |
webhook_url | string | Yes | URL to receive webhook events |
quote_currency | string | No | Fiat currency (default: “USD”) |
base_currency | string | No | Crypto currency: “BTC” or “USDC” |
destination | string | No | URL to redirect after completion |
reference_id | string | No | Your internal reference ID |
metadata | object | No | Custom data (returned in webhooks) |
access_token | string | No | Existing user session token |
Response
{
"success": true,
"data": {
"session_token": "eyJraWQiOiJzLWE1OWNk...",
"widget_url": "https://ramp.zbdpay.com/?session=eyJraWQiOiJzLWE1OWNk...",
"expires_at": "2025-06-09T12:00:00Z"
}
}
Widget sessions expire after 15 minutes. Create a new session if the user needs more time.
Once you have the widget URL, embed it in your application using an iframe.
Basic Implementation
<iframe
id="zbd-onramp"
src="WIDGET_URL_FROM_API"
style="width: 100%; height: 600px; border: none;"
allow="camera; microphone"
sandbox="allow-scripts allow-same-origin allow-forms allow-popups"
></iframe>
Frontend Events
The widget communicates via postMessage
. Listen for these events:
window.addEventListener('message', (event) => {
// Verify origin
if (event.origin !== 'https://onramp.zbd.gg') return;
switch (event.data.type) {
case 'zbd.onramp.ready':
console.log('Widget loaded successfully');
break;
case 'zbd.onramp.close':
// User clicked close button
hideWidget();
break;
case 'zbd.onramp.success':
// Purchase completed
console.log('Transaction ID:', event.data.transactionId);
showSuccessMessage();
break;
case 'zbd.onramp.error':
// Handle errors
console.error('Widget error:', event.data.message);
break;
case 'zbd.onramp.resize':
// Widget requests size change
adjustIframeHeight(event.data.height);
break;
}
});
Security Best Practices
API Key Security
- Never expose API keys in frontend code
- Use environment variables
- Rotate keys regularly
- Restrict key permissions
Webhook Security
- Always verify signatures
- Use HTTPS endpoints only
- Implement idempotency
- Log all events
Next Steps