Authentication
Zelta Pay API uses API key-based authentication for all public endpoints. This guide covers how to obtain, use, and manage your API keys securely.
API Key Authentication
Section titled “API Key Authentication”How It Works
Section titled “How It Works”All API requests must include your API key in the X-API-Key header:
X-API-Key: your-api-key-hereThe server validates this key before processing your request. Each account can have multiple API keys for different applications or environments.
Getting Your API Key
Section titled “Getting Your API Key”- Log in to your Zelta Pay Dashboard
- Navigate to Settings → API Keys
- Click Create New API Key
- Give it a descriptive name (e.g., “Production App”, “Mobile App”)
- Copy the generated key and store it securely
- Click Save
Security
Never commit API keys to version control. Use environment variables or secure secret management systems instead.
Rate Limiting
Section titled “Rate Limiting”Limits and Windows
Section titled “Limits and Windows”- Limit: 60 requests per minute per API key
- Window: 1 minute rolling window
- Per-key: Each API key has its own independent limit
Rate Limit Headers
Section titled “Rate Limit Headers”Every response includes rate limit information in headers:
| Header | Description | Example |
|---|---|---|
RateLimit-Limit | Maximum requests allowed | 60 |
RateLimit-Remaining | Requests left in window | 45 |
RateLimit-Reset | Unix timestamp of window reset | 1640995200 |
Example Headers
Section titled “Example Headers”HTTP/1.1 200 OKRateLimit-Limit: 60RateLimit-Remaining: 59RateLimit-Reset: 1640995260Content-Type: application/jsonHandling Rate Limits
Section titled “Handling Rate Limits”When you exceed the rate limit, you’ll receive a 429 Too Many Requests response:
{ "success": false, "message": "Too Many Requests", "error": { "code": "ERR_RATE_LIMIT_EXCEEDED" }, "timestamp": "2024-01-15T12:00:00.000Z"}The RateLimit-Reset header indicates when the window resets (in Unix seconds).
Best Practices
Section titled “Best Practices”- Monitor rate limit headers in your responses
- Implement exponential backoff for retries
- Use multiple API keys for high-volume applications
- Cache responses when possible to reduce API calls
Error Handling
Section titled “Error Handling”Common Authentication Errors
Section titled “Common Authentication Errors”| Code | HTTP | Description | Solution |
|---|---|---|---|
ERR_MISSING_API_KEY | 401 | X-API-Key header is missing | Add the X-API-Key header to your request |
ERR_API_KEY_NOT_FOUND | 404 | API key not found or invalid | Verify your API key is correct |
ERR_ACCOUNT_SUSPENDED | 403 | Account is suspended | Contact support@zelta.dev |
ERR_RATE_LIMIT_EXCEEDED | 429 | Rate limit exceeded (60 requests/min) | Implement backoff/retry logic |
Error Response Format
Section titled “Error Response Format”{ "success": false, "message": "API key not found", "error": { "code": "ERR_API_KEY_NOT_FOUND" }, "timestamp": "2024-01-15T12:00:00.000Z"}Implementation Examples
Section titled “Implementation Examples”Node.js Example
Section titled “Node.js Example”const apiKey = process.env.ZELTA_API_KEY;
async function makeApiRequest(endpoint, options = {}) { const response = await fetch(`https://api-pay.zelta.dev${endpoint}`, { ...options, headers: { 'X-API-Key': apiKey, 'Content-Type': 'application/json', ...options.headers } });
if (!response.ok) { const error = await response.json(); throw new Error(error.message); }
return response.json();}
// Usagetry { const paymentLinks = await makeApiRequest('/v1/payment-links'); console.log(paymentLinks);} catch (error) { console.error('API Error:', error.message);}Cloudflare Workers Example
Section titled “Cloudflare Workers Example”export default { async fetch(request, env, ctx) { const apiKey = env.ZELTA_API_KEY;
async function makeApiRequest(endpoint, options = {}) { const response = await fetch(`https://api-pay.zelta.dev${endpoint}`, { ...options, headers: { 'X-API-Key': apiKey, 'Content-Type': 'application/json', ...options.headers } });
if (!response.ok) { const error = await response.json(); throw new Error(error.message); }
return response.json(); }
// Example usage try { const paymentLinks = await makeApiRequest('/v1/payment-links'); return new Response(JSON.stringify(paymentLinks), { headers: { 'Content-Type': 'application/json' } }); } catch (error) { return new Response(JSON.stringify({ error: error.message }), { status: 500, headers: { 'Content-Type': 'application/json' } }); } }};Hono with Cloudflare Workers Example
Section titled “Hono with Cloudflare Workers Example”import { Hono } from 'hono';import { cors } from 'hono/cors';
type Bindings = { ZELTA_API_KEY: string;};
const app = new Hono<{ Bindings: Bindings }>();
// Enable CORSapp.use('*', cors());
async function makeApiRequest(endpoint: string, apiKey: string, options: RequestInit = {}) { const response = await fetch(`https://api-pay.zelta.dev${endpoint}`, { ...options, headers: { 'X-API-Key': apiKey, 'Content-Type': 'application/json', ...options.headers } });
if (!response.ok) { const error = await response.json(); throw new Error(error.message); }
return response.json();}
// Example endpointapp.get('/payment-links', async (c) => { try { const paymentLinks = await makeApiRequest('/v1/payment-links', c.env.ZELTA_API_KEY); return c.json(paymentLinks); } catch (error) { return c.json({ error: error.message }, 500); }});
export default app;Python Example
Section titled “Python Example”import requestsimport os
api_key = os.getenv('ZELTA_API_KEY')
def make_api_request(endpoint, **kwargs): headers = { 'X-API-Key': api_key, 'Content-Type': 'application/json' } headers.update(kwargs.get('headers', {}))
response = requests.request( method=kwargs.get('method', 'GET'), url=f'https://api-pay.zelta.dev{endpoint}', headers=headers, **{k: v for k, v in kwargs.items() if k not in ['method', 'headers']} )
if not response.ok: error = response.json() raise Exception(error['message'])
return response.json()
# Usagetry: payment_links = make_api_request('/v1/payment-links') print(payment_links)except Exception as error: print(f'API Error: {error}')PHP Example
Section titled “PHP Example”<?php$apiKey = $_ENV['ZELTA_API_KEY'];
function makeApiRequest($endpoint, $options = []) { global $apiKey;
$headers = [ 'X-API-Key: ' . $apiKey, 'Content-Type: application/json' ];
if (isset($options['headers'])) { $headers = array_merge($headers, $options['headers']); }
$ch = curl_init(); curl_setopt($ch, CURLOPT_URL, 'https://api-pay.zelta.dev' . $endpoint); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
if (isset($options['method'])) { curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $options['method']); }
if (isset($options['data'])) { curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($options['data'])); }
$response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch);
if ($httpCode >= 400) { $error = json_decode($response, true); throw new Exception($error['message']); }
return json_decode($response, true);}
// Usagetry { $paymentLinks = makeApiRequest('/v1/payment-links'); print_r($paymentLinks);} catch (Exception $e) { echo 'API Error: ' . $e->getMessage();}?>Security Best Practices
Section titled “Security Best Practices”1. Environment Variables
Section titled “1. Environment Variables”Store API keys in environment variables:
# .env fileZELTA_API_KEY=your-api-key-here2. Key Rotation
Section titled “2. Key Rotation”Regularly rotate your API keys:
- Create a new API key
- Update your applications
- Delete the old key
3. Access Control
Section titled “3. Access Control”- Use different API keys for different environments
- Limit key permissions when possible
- Monitor key usage in your dashboard
4. Error Handling
Section titled “4. Error Handling”Always handle authentication errors gracefully:
async function handleApiError(error) { if (error.message.includes('API key not found')) { console.error('Invalid API key'); // Redirect to settings or show error } else if (error.message.includes('Too Many Requests')) { console.error('Rate limit exceeded'); // Implement backoff strategy } else { console.error('API Error:', error.message); }}Testing Authentication
Section titled “Testing Authentication”Test Your API Key
Section titled “Test Your API Key”curl -X GET "https://api-pay.zelta.dev/v1/payment-links" \ -H "X-API-Key: your-api-key-here" \ -H "Content-Type: application/json"Expected Response
Section titled “Expected Response”{ "success": true, "data": { "paymentLinks": [], "total": 0 }, "message": null, "timestamp": "2024-01-15T12:00:00.000Z"}Troubleshooting
Section titled “Troubleshooting”Common Issues
Section titled “Common Issues”401 Unauthorized
- Check API key is correct
- Ensure
X-API-Keyheader is included - Verify key is active in dashboard
403 Forbidden
- Account may be suspended
- Contact support for assistance
429 Too Many Requests
- Implement rate limiting in your application
- Use multiple API keys for high volume
- Cache responses when possible
Next Steps
Section titled “Next Steps”Now that you understand authentication, explore these guides:
- Quick Start - Create your first payment link
- Creating Payment Links - Advanced payment link options
- Webhooks - Real-time payment notifications
- API Reference - Complete endpoint documentation