API Documentation

API Documentation

Complete REST API reference for Waitlist Widget. 🚀

Base URL

Production: https://api.waitlistwidget.com/api
Local Development: http://localhost:3001/api

Authentication

All API requests require authentication using your API Key.

Getting Your API Key

  1. Log in to your dashboard
  2. Navigate to your project
  3. Copy the API key from project settings

Authentication Methods

curl -H "Authorization: Bearer YOUR_API_KEY" \
  https://api.waitlistwidget.com/api/projects

Query 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 TypeRate LimitWindow
Public (widget)3 requestsper minute per IP
Private (dashboard)60 requestsper minute per user
Webhooks10 requestsper minute per project

Rate Limit Headers:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1634567890

429 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_KEY

Response: 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/projects

JavaScript 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_abc123

Create Project

Create a new waitlist project.

Endpoint: POST /api/projects

Headers:

Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

Request Body:

{
  "name": "My New Product",
  "slug": "new-product",
  "description": "Optional description"
}

Validation Rules:

  • name: Required, 3-100 characters
  • slug: Required, 3-50 characters, lowercase, alphanumeric + hyphens
  • description: 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/projects

JavaScript 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 ID
  • page (query, optional): Page number (default: 1)
  • limit (query, optional): Items per page (default: 50, max: 100)
  • sort (query, optional): Sort order (asc or desc, 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/json

Request Body:

{
  "email": "user@example.com",
  "apiKey": "wls_live_abc123..."
}

Validation Rules:

  • email: Required, valid email format, not disposable
  • apiKey: 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/subscribe

JavaScript 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.000Z

cURL Example:

curl -X GET \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -o subscribers.csv \
  https://api.waitlistwidget.com/api/projects/proj_abc123/export

Delete Subscriber

Remove a subscriber from a project.

Endpoint: DELETE /api/projects/:projectId/subscribers/:subscriberId

Parameters:

  • projectId (path): Project ID
  • subscriberId (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 StatusError CodeDescription
400VALIDATION_ERRORInvalid request body or parameters
401UNAUTHORIZEDMissing or invalid API key
403FORBIDDENInsufficient permissions
404NOT_FOUNDResource not found
409CONFLICTResource already exists (e.g., duplicate email)
422UNPROCESSABLE_ENTITYBusiness logic validation failed
429RATE_LIMIT_EXCEEDEDToo many requests
500INTERNAL_SERVER_ERRORServer error
503SERVICE_UNAVAILABLEService 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: fetch API (built-in) or axios
  • Python: requests or httpx
  • PHP: GuzzleHttp or cURL
  • Ruby: net/http (stdlib) or httparty
  • Go: net/http package
  • Java: HttpClient or OkHttp

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!

Feedback? We'd love to hear from you at support@waitlistwidget.com