Skip to content

Quick Start

Welcome to Zelta Pay API! This guide will help you create your first payment link and understand the basics of our API.

Before you begin, make sure you have:

  • A Zelta Pay account
  • An API key (obtain from your dashboard)
  • Basic knowledge of HTTP requests
  • A development environment ready
  1. Log in to your Zelta Pay Dashboard
  2. Navigate to API Keys
  3. Click Create New API Key
  4. Give it a descriptive name (e.g., “My App Integration”)
  5. Copy the generated API key and store it securely

Let’s test your API key by listing your existing payment links:

Terminal window
curl -X GET "https://api-pay.zelta.dev/v1/payment-links" \
-H "X-API-Key: your-api-key-here" \
-H "Content-Type: application/json"
const response = await fetch('https://api-pay.zelta.dev/v1/payment-links', {
method: 'GET',
headers: {
'X-API-Key': 'your-api-key-here',
'Content-Type': 'application/json'
}
});
const result = await response.json();
console.log(result);
export default {
async fetch(request, env, ctx) {
const response = await fetch('https://api-pay.zelta.dev/v1/payment-links', {
method: 'GET',
headers: {
'X-API-Key': env.ZELTA_API_KEY,
'Content-Type': 'application/json'
}
});
const result = await response.json();
return new Response(JSON.stringify(result), {
headers: { 'Content-Type': 'application/json' }
});
}
};
import { Hono } from 'hono';
import { cors } from 'hono/cors';
type Bindings = {
ZELTA_API_KEY: string;
};
const app = new Hono<{ Bindings: Bindings }>();
// Enable CORS
app.use('*', cors());
app.get('/payment-links', async (c) => {
const response = await fetch('https://api-pay.zelta.dev/v1/payment-links', {
method: 'GET',
headers: {
'X-API-Key': c.env.ZELTA_API_KEY,
'Content-Type': 'application/json'
}
});
const result = await response.json();
return c.json(result);
});
export default app;
import requests
response = requests.get(
'https://api-pay.zelta.dev/v1/payment-links',
headers={
'X-API-Key': 'your-api-key-here',
'Content-Type': 'application/json'
}
)
result = response.json()
print(result)

Now let’s create a payment link:

Terminal window
curl -X POST "https://api-pay.zelta.dev/v1/payment-links" \
-H "X-API-Key: your-api-key-here" \
-H "Content-Type: application/json" \
-d '{
"concept": "Test Payment",
"amount": 100,
"customerName": "John Doe",
"isTest": true
}'
const response = await fetch('https://api-pay.zelta.dev/v1/payment-links', {
method: 'POST',
headers: {
'X-API-Key': 'your-api-key-here',
'Content-Type': 'application/json'
},
body: JSON.stringify({
concept: 'Test Payment',
amount: 100,
customerName: 'John Doe',
isTest: true
})
});
const result = await response.json();
console.log(result);
export default {
async fetch(request, env, ctx) {
const response = await fetch('https://api-pay.zelta.dev/v1/payment-links', {
method: 'POST',
headers: {
'X-API-Key': env.ZELTA_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
concept: 'Test Payment',
amount: 100,
customerName: 'John Doe',
isTest: true
})
});
const result = await response.json();
return new Response(JSON.stringify(result), {
headers: { 'Content-Type': 'application/json' }
});
}
};
import { Hono } from 'hono';
import { cors } from 'hono/cors';
type Bindings = {
ZELTA_API_KEY: string;
};
const app = new Hono<{ Bindings: Bindings }>();
// Enable CORS
app.use('*', cors());
app.post('/payment-links', async (c) => {
const body = await c.req.json();
const response = await fetch('https://api-pay.zelta.dev/v1/payment-links', {
method: 'POST',
headers: {
'X-API-Key': c.env.ZELTA_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
concept: 'Test Payment',
amount: 100,
customerName: 'John Doe',
isTest: true
})
});
const result = await response.json();
return c.json(result);
});
export default app;
import requests
response = requests.post(
'https://api-pay.zelta.dev/v1/payment-links',
headers={
'X-API-Key': 'your-api-key-here',
'Content-Type': 'application/json'
},
json={
'concept': 'Test Payment',
'amount': 100,
'customerName': 'John Doe',
'isTest': True
}
)
result = response.json()
print(result)

A successful response will look like this:

{
"success": true,
"data": {
"paymentLink": {
"id": "pl_1234567890abcdef",
"paymentLinkUrl": "https://pay.zelta.dev/abc123",
"customerName": "John Doe",
"concept": "Test Payment",
"amount": 100,
"status": "pending",
"createdAt": "2024-01-15T10:30:00.000Z",
"expiresAt": "2024-01-22T10:30:00.000Z",
"isTest": true
}
},
"message": "Payment link created successfully",
"timestamp": "2024-01-15T10:30:00.000Z"
}
  • paymentLinkUrl: The URL your customer will use to pay
  • id: Unique identifier for the payment link
  • status: Current status (always “pending” for new links)
  • expiresAt: When the link expires (7 days from creation)

Once you have the payment link URL, you can:

  1. Send it to your customer via email, SMS, or display it on your website
  2. Redirect them to the payment portal
  3. Monitor the status by calling the API or setting up webhooks
// Redirect customer to payment page
window.location.href = result.data.paymentLink.paymentLinkUrl;

To receive real-time notifications when payments are completed:

  1. Go to SettingsWebhooks in your dashboard
  2. Add your webhook URL (must be HTTPS)
  3. Select the events you want to receive
  4. Test your webhook endpoint
// Node.js with Express
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['zeltapay-signature'];
const timestamp = req.headers['zeltapay-timestamp'];
// Verify signature (important for security)
if (!verifySignature(req.body.toString(), timestamp, signature)) {
return res.status(401).json({ error: 'Invalid signature' });
}
const payload = JSON.parse(req.body);
if (payload.type === 'payment.success') {
console.log('Payment completed:', payload.transaction.amount);
// Update your database, send confirmation email, etc.
}
res.status(200).json({ received: true });
});
export default {
async fetch(request, env, ctx) {
if (request.method !== 'POST') {
return new Response('Method not allowed', { status: 405 });
}
const url = new URL(request.url);
if (url.pathname !== '/webhook') {
return new Response('Not found', { status: 404 });
}
try {
const signature = request.headers.get('zeltapay-signature');
const timestamp = request.headers.get('zeltapay-timestamp');
// Get raw body
const rawBody = await request.text();
// Verify signature (important for security)
if (!await verifySignature(rawBody, timestamp, signature, env.WEBHOOK_SECRET)) {
return new Response(JSON.stringify({ error: 'Invalid signature' }), {
status: 401,
headers: { 'Content-Type': 'application/json' }
});
}
const payload = JSON.parse(rawBody);
if (payload.type === 'payment.success') {
console.log('Payment completed:', payload.transaction.amount);
// Update your database, send confirmation email, etc.
}
return new Response(JSON.stringify({ received: true }), {
status: 200,
headers: { 'Content-Type': 'application/json' }
});
} catch (error) {
console.error('Webhook processing error:', error);
return new Response(JSON.stringify({ error: 'Processing failed' }), {
status: 500,
headers: { 'Content-Type': 'application/json' }
});
}
}
};
async function verifySignature(rawBody, timestamp, signature, secret) {
// Implementation details in signature verification guide
return true; // Placeholder
}

Hono with Cloudflare Workers Webhook Example

Section titled “Hono with Cloudflare Workers Webhook Example”
import { Hono } from 'hono';
import { cors } from 'hono/cors';
type Bindings = {
WEBHOOK_SECRET: string;
};
const app = new Hono<{ Bindings: Bindings }>();
// Enable CORS
app.use('*', cors());
app.post('/webhook', async (c) => {
try {
const signature = c.req.header('zeltapay-signature');
const timestamp = c.req.header('zeltapay-timestamp');
if (!signature || !timestamp) {
return c.json({ error: 'Missing required headers' }, 400);
}
// Get raw body
const rawBody = await c.req.text();
// Verify signature (important for security)
if (!await verifySignature(rawBody, timestamp, signature, c.env.WEBHOOK_SECRET)) {
return c.json({ error: 'Invalid signature' }, 401);
}
const payload = JSON.parse(rawBody);
if (payload.type === 'payment.success') {
console.log('Payment completed:', payload.transaction.amount);
// Update your database, send confirmation email, etc.
}
return c.json({ received: true });
} catch (error) {
console.error('Webhook processing error:', error);
return c.json({ error: 'Processing failed' }, 500);
}
});
async function verifySignature(rawBody: string, timestamp: string, signature: string, secret: string): Promise<boolean> {
// Implementation details in signature verification guide
return true; // Placeholder
}
export default app;

Now that you’ve created your first payment link, explore these guides:

  • Check that your API key is correct
  • Ensure the X-API-Key header is included
  • Verify the API key is active in your dashboard
  • Check that all required fields are provided
  • Ensure the amount is in cents (e.g., 100 = $1.00)
  • Verify the JSON format is correct
  • You’ve exceeded the rate limit (60 requests per minute)
  • Wait before making more requests
  • Consider implementing request queuing

If you need help:

  • Documentation: Browse our guides and API reference
  • Dashboard: Use the built-in API testing tools
  • Support: Contact us at support@zelta.dev
  • GitHub: Report issues and feature requests