CLASHUP API Documentation
CLASHUP provides a REST API for sending and verifying one-time passwords (OTPs) via email. All API requests use JSON and return standardized JSON responses.
Base URL: https://api.clashup.site/api/v1
Authentication
All API requests require an API key sent in the X-API-Key header.
curl -X POST https://api.clashup.site/api/v1/otp/send \
-H "X-API-Key: cu_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{"channel": "email", "recipient": "user@example.com"}'How to get an API key:
- Register and verify your account at clashup.site/register
- Create an application in the dashboard
- Generate an API key for your application
- Copy and securely store the key (shown only once)
Local Development
Browser apps served from http://localhost, http://127.0.0.1, or http://[::1] can call the production API directly. Create an application and API key in the dashboard, then send the key in every request.
fetch('https://api.clashup.site/api/v1/otp/send', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': 'cu_live_your_api_key'
},
body: JSON.stringify({
channel: 'email',
recipient: 'user@example.com'
})
});Keep your key private
Use this browser setup for local development and trusted internal tools. Never embed a live API key in a public website, mobile app, or code repository; send those requests through your own backend instead.
Rate Limiting
API requests are rate-limited per API key. Rate limit headers are included in every response.
| Header | Description |
|---|---|
| X-RateLimit-Limit | Max requests per window |
| X-RateLimit-Remaining | Requests remaining in current window |
| X-RateLimit-Reset | Window reset time (unix timestamp) |
OTP endpoints: 30 requests per minute per IP. If exceeded, you'll receive a 429 Too Many Requests response.
Error Handling
All errors return a consistent JSON format:
{
"success": false,
"message": "Validation failed",
"statusCode": 400,
"errors": [
{ "field": "email", "message": "Please provide a valid email" }
]
}| Code | Description |
|---|---|
| 400 | Bad Request - Invalid parameters |
| 401 | Unauthorized - Missing or invalid API key |
| 403 | Forbidden - Insufficient permissions |
| 404 | Not Found - Resource doesn't exist |
| 429 | Too Many Requests - Rate limit exceeded |
| 500 | Server Error - Something went wrong |
Send OTP
/api/v1/otp/send
Generates and sends a one-time password to the specified recipient.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| channel | string | Yes | email or sms |
| recipient | string | Yes | Email address or phone number |
| metadata | object | No | Custom key-value metadata |
Example Request
curl -X POST https://api.clashup.site/api/v1/otp/send \
-H "X-API-Key: cu_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"channel": "email",
"recipient": "user@example.com",
"metadata": { "purpose": "login" }
}'Success Response
{
"success": true,
"message": "OTP sent successfully",
"statusCode": 200,
"data": {
"requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"channel": "email",
"recipient": "user@example.com",
"status": "pending",
"expiresAt": "2025-01-01T00:10:00.000Z"
}
}Verify OTP
/api/v1/otp/verify
Verifies an OTP code against a pending request.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| requestId | string | Yes | The requestId from the send response |
| otp | string | Yes | The OTP code entered by the user |
Example Request
curl -X POST https://api.clashup.site/api/v1/otp/verify \
-H "X-API-Key: cu_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"otp": "123456"
}'Success Response
{
"success": true,
"message": "OTP verified successfully",
"statusCode": 200,
"data": {
"requestId": "a1b2c3d4-...",
"status": "verified",
"verifiedAt": "2025-01-01T00:05:30.000Z"
}
}Important Notes
- OTPs expire after 10 minutes by default
- Maximum 3 verification attempts per OTP request
- After max attempts, the OTP is marked as failed
- OTP values are hashed - they cannot be retrieved, only verified
Webhook Events
Configure webhooks in the dashboard to receive real-time notifications for these events:
| Event | Description |
|---|---|
| otp.sent | OTP was sent successfully |
| otp.verified | OTP was verified successfully |
| otp.failed | OTP verification failed (max attempts) |
| otp.expired | OTP expired without verification |
Webhook Payload
{
"event": "otp.verified",
"timestamp": "2025-01-01T00:05:30.000Z",
"data": {
"requestId": "a1b2c3d4-...",
"channel": "email",
"recipient": "user@example.com",
"status": "verified"
}
}Verifying Webhook Signatures
Every webhook request includes an X-Clashup-Signature header containing an HMAC-SHA256 signature.
const crypto = require('crypto');
function verifySignature(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// In your webhook handler:
app.post('/webhook', (req, res) => {
const signature = req.headers['x-clashup-signature'];
const isValid = verifySignature(
JSON.stringify(req.body),
signature,
'your_webhook_secret'
);
if (!isValid) return res.status(401).send('Invalid');
// Process the event...
res.status(200).send('OK');
});Health Check
/api/health
Returns API status. No authentication required.
{
"success": true,
"message": "CLASHUP API is running",
"data": {
"status": "operational",
"version": "1.0.0",
"uptime": 86400,
"mongodb": "connected"
}
}