API Documentation
Complete REST API reference for Waitlist Widget. 🚀
Base URL
Production: https://api.waitlistwidget.com/api
Local Development: http://localhost:3001/apiAuthentication
All API requests require authentication using your API Key.
Getting Your API Key
- Log in to your dashboard
- Navigate to your project
- Copy the API key from project settings
Authentication Methods
Header Authentication (Recommended)
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.waitlistwidget.com/api/projectsQuery Parameter (Alternative)
curl "https://api.waitlistwidget.com/api/projects?apiKey=YOUR_API_KEY"⚠️ Security Warning: Never expose your API key in client-side code. Use server-side requests only.
Rate Limiting
To ensure fair usage and system stability:
| Endpoint Type | Rate Limit | Window |
|---|---|---|
| Public (widget) | 3 requests | per minute per IP |
| Private (dashboard) | 60 requests | per minute per user |
| Webhooks | 10 requests | per minute per project |
Rate Limit Headers:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1634567890429 Too Many Requests Response:
{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests. Please try again later.",
"retryAfter": 60
}
}Endpoints
Projects
List All Projects
Get all projects for the authenticated user.
Endpoint: GET /api/projects
Headers:
Authorization: Bearer YOUR_API_KEYResponse: 200 OK
{
"success": true,
"data": {
"projects": [
{
"id": "proj_abc123",
"name": "My Awesome Product",
"slug": "awesome-product",
"description": "Product description",
"subscriberCount": 127,
"createdAt": "2025-10-01T10:00:00.000Z",
"updatedAt": "2025-10-22T13:45:00.000Z"
}
]
}
}cURL Example:
curl -X GET \
-H "Authorization: Bearer YOUR_API_KEY" \
https://api.waitlistwidget.com/api/projectsJavaScript Example:
const response = await fetch('https://api.waitlistwidget.com/api/projects', {
headers: {
'Authorization': `Bearer ${API_KEY}`
}
});
const data = await response.json();
console.log(data.projects);Get Project by ID
Retrieve a specific project.
Endpoint: GET /api/projects/:id
Parameters:
id(path): Project ID
Response: 200 OK
{
"success": true,
"data": {
"project": {
"id": "proj_abc123",
"name": "My Awesome Product",
"slug": "awesome-product",
"description": "Product description",
"apiKey": "wls_live_abc123...",
"subscriberCount": 127,
"createdAt": "2025-10-01T10:00:00.000Z",
"updatedAt": "2025-10-22T13:45:00.000Z"
}
}
}cURL Example:
curl -X GET \
-H "Authorization: Bearer YOUR_API_KEY" \
https://api.waitlistwidget.com/api/projects/proj_abc123Create Project
Create a new waitlist project.
Endpoint: POST /api/projects
Headers:
Authorization: Bearer YOUR_API_KEY
Content-Type: application/jsonRequest Body:
{
"name": "My New Product",
"slug": "new-product",
"description": "Optional description"
}Validation Rules:
name: Required, 3-100 charactersslug: Required, 3-50 characters, lowercase, alphanumeric + hyphensdescription: Optional, max 500 characters
Response: 201 Created
{
"success": true,
"data": {
"project": {
"id": "proj_xyz789",
"name": "My New Product",
"slug": "new-product",
"description": "Optional description",
"apiKey": "wls_live_xyz789...",
"subscriberCount": 0,
"createdAt": "2025-10-22T13:50:00.000Z",
"updatedAt": "2025-10-22T13:50:00.000Z"
}
},
"message": "Project created successfully"
}cURL Example:
curl -X POST \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"My New Product","slug":"new-product"}' \
https://api.waitlistwidget.com/api/projectsJavaScript Example:
const response = await fetch('https://api.waitlistwidget.com/api/projects', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'My New Product',
slug: 'new-product',
description: 'Optional description'
})
});
const data = await response.json();
console.log(data.project);Update Project
Update an existing project.
Endpoint: PUT /api/projects/:id
Parameters:
id(path): Project ID
Request Body:
{
"name": "Updated Product Name",
"description": "Updated description"
}Response: 200 OK
{
"success": true,
"data": {
"project": {
"id": "proj_abc123",
"name": "Updated Product Name",
"slug": "awesome-product",
"description": "Updated description",
"subscriberCount": 127,
"updatedAt": "2025-10-22T13:55:00.000Z"
}
},
"message": "Project updated successfully"
}Delete Project
Delete a project and all its subscribers.
Endpoint: DELETE /api/projects/:id
Parameters:
id(path): Project ID
Response: 200 OK
{
"success": true,
"message": "Project deleted successfully"
}⚠️ Warning: This action is irreversible. All subscribers will be permanently deleted.
Subscribers
List Subscribers
Get all subscribers for a specific project.
Endpoint: GET /api/projects/:projectId/subscribers
Parameters:
projectId(path): Project IDpage(query, optional): Page number (default: 1)limit(query, optional): Items per page (default: 50, max: 100)sort(query, optional): Sort order (ascordesc, default:desc)
Response: 200 OK
{
"success": true,
"data": {
"subscribers": [
{
"id": "sub_abc123",
"email": "user@example.com",
"subscribedAt": "2025-10-22T10:30:00.000Z",
"metadata": {
"source": "landing-page",
"referrer": "https://google.com"
}
}
],
"pagination": {
"page": 1,
"limit": 50,
"total": 127,
"totalPages": 3
}
}
}cURL Example:
curl -X GET \
-H "Authorization: Bearer YOUR_API_KEY" \
"https://api.waitlistwidget.com/api/projects/proj_abc123/subscribers?page=1&limit=50"Add Subscriber (Public)
Add a subscriber to a project. This endpoint is public and used by the widget.
Endpoint: POST /api/public/subscribe
Headers:
Content-Type: application/jsonRequest Body:
{
"email": "user@example.com",
"apiKey": "wls_live_abc123..."
}Validation Rules:
email: Required, valid email format, not disposableapiKey: Required, valid project API key
Response: 201 Created
{
"success": true,
"data": {
"subscriber": {
"id": "sub_xyz789",
"email": "user@example.com",
"subscribedAt": "2025-10-22T13:55:00.000Z"
}
},
"message": "Successfully subscribed to waitlist"
}Error Response (Duplicate): 409 Conflict
{
"success": false,
"error": {
"code": "EMAIL_ALREADY_SUBSCRIBED",
"message": "This email is already on the waitlist"
}
}cURL Example:
curl -X POST \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","apiKey":"wls_live_abc123..."}' \
https://api.waitlistwidget.com/api/public/subscribeJavaScript Example:
const response = await fetch('https://api.waitlistwidget.com/api/public/subscribe', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: 'user@example.com',
apiKey: 'wls_live_abc123...'
})
});
const data = await response.json();
if (data.success) {
console.log('Subscribed successfully!');
} else {
console.error(data.error.message);
}Export Subscribers (CSV)
Export all subscribers as CSV.
Endpoint: GET /api/projects/:projectId/export
Parameters:
projectId(path): Project ID
Response: 200 OK (CSV file)
email,subscribedAt
user1@example.com,2025-10-22T10:00:00.000Z
user2@example.com,2025-10-22T11:30:00.000ZcURL Example:
curl -X GET \
-H "Authorization: Bearer YOUR_API_KEY" \
-o subscribers.csv \
https://api.waitlistwidget.com/api/projects/proj_abc123/exportDelete Subscriber
Remove a subscriber from a project.
Endpoint: DELETE /api/projects/:projectId/subscribers/:subscriberId
Parameters:
projectId(path): Project IDsubscriberId(path): Subscriber ID
Response: 200 OK
{
"success": true,
"message": "Subscriber removed successfully"
}Usage & Billing
Get Usage Stats
Get current usage statistics for your account.
Endpoint: GET /api/usage
Response: 200 OK
{
"success": true,
"data": {
"currentPlan": "starter",
"usage": {
"projects": {
"current": 3,
"limit": 5
},
"subscribers": {
"current": 487,
"limit": 5000
},
"webhooks": {
"enabled": true,
"limit": 10
}
},
"billingPeriod": {
"start": "2025-10-01T00:00:00.000Z",
"end": "2025-11-01T00:00:00.000Z"
}
}
}Error Codes
Standard error response format:
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Human-readable error message",
"details": {} // Optional additional context
}
}Common Error Codes
| HTTP Status | Error Code | Description |
|---|---|---|
400 | VALIDATION_ERROR | Invalid request body or parameters |
401 | UNAUTHORIZED | Missing or invalid API key |
403 | FORBIDDEN | Insufficient permissions |
404 | NOT_FOUND | Resource not found |
409 | CONFLICT | Resource already exists (e.g., duplicate email) |
422 | UNPROCESSABLE_ENTITY | Business logic validation failed |
429 | RATE_LIMIT_EXCEEDED | Too many requests |
500 | INTERNAL_SERVER_ERROR | Server error |
503 | SERVICE_UNAVAILABLE | Service temporarily unavailable |
Validation Errors
Example Response: 400 Bad Request
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Validation failed",
"details": {
"fields": {
"email": "Invalid email format",
"name": "Name must be at least 3 characters"
}
}
}
}Webhooks
Set up webhooks to receive real-time notifications when subscribers join your waitlist.
See full webhook documentation: WEBHOOKS.md
Quick Example:
POST https://your-server.com/webhook
Content-Type: application/json
X-Webhook-Signature: sha256=abc123...
{
"event": "subscriber.created",
"data": {
"subscriber": {
"id": "sub_xyz789",
"email": "user@example.com",
"subscribedAt": "2025-10-22T14:00:00.000Z"
},
"project": {
"id": "proj_abc123",
"name": "My Product"
}
},
"timestamp": "2025-10-22T14:00:01.000Z"
}SDKs & Libraries
We're working on official SDKs for popular languages. Until they're available, you can use standard HTTP clients in your language of choice.
Interested in an SDK for your language? Contact us at support@waitlistwidget.com
Example HTTP Clients
- JavaScript/TypeScript:
fetchAPI (built-in) oraxios - Python:
requestsorhttpx - PHP:
GuzzleHttporcURL - Ruby:
net/http(stdlib) orhttparty - Go:
net/httppackage - Java:
HttpClientorOkHttp
All examples in this documentation use standard HTTP requests that work with any client library.
Best Practices
1. Security
- ✅ Never expose API keys in client-side code
- ✅ Use HTTPS for all API requests
- ✅ Rotate keys if compromised
- ✅ Verify webhook signatures (see WEBHOOKS.md)
2. Performance
- ✅ Cache responses when appropriate
- ✅ Use pagination for large datasets
- ✅ Implement exponential backoff for retries
- ✅ Respect rate limits (check headers)
3. Error Handling
async function subscribeToWaitlist(email) {
try {
const response = await fetch('/api/public/subscribe', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, apiKey: API_KEY })
});
const data = await response.json();
if (!response.ok) {
// Handle different error codes
switch (data.error.code) {
case 'EMAIL_ALREADY_SUBSCRIBED':
alert('You\'re already on the waitlist!');
break;
case 'RATE_LIMIT_EXCEEDED':
alert('Too many attempts. Please try again later.');
break;
case 'VALIDATION_ERROR':
alert(`Invalid email: ${data.error.message}`);
break;
default:
alert('Something went wrong. Please try again.');
}
return;
}
alert('Successfully subscribed!');
} catch (error) {
console.error('Network error:', error);
alert('Connection error. Please check your internet.');
}
}Changelog
v1.0.0 (2025-10-22)
- 🎉 Initial API release
- ✅ Projects CRUD endpoints
- ✅ Subscribers management
- ✅ Public subscribe endpoint
- ✅ CSV export
- ✅ Usage tracking
- ✅ Rate limiting
Support
Questions? We're here to help!
- 📧 Email: support@waitlistwidget.com - We typically respond within 24 hours
- 📚 Documentation: See QUICKSTART.md, WIDGET.md, WEBHOOKS.md, and FAQ.md
Feedback? We'd love to hear from you at support@waitlistwidget.com