API Documentation

Learn how to connect and integrate with our API.

 

Authentication

All the API endpoints require an API key sent by the Bearer Authentication method.

Authorization: Bearer {api_key}
curl --request GET \
--url 'https://fomoboost.com/api/{endpoint}' \
--header 'Authorization: Bearer {api_key}' \

Rate limiting

Requests are limited independently per IP address, account, API key, and endpoint. All limits must have available quota for a request to succeed.

IP — 120 requests per 60 seconds per client IP.
Account — 300 requests per 60 seconds per user account.
API key — 60 requests per 60 seconds per Bearer token.
Endpoint — 30 requests per 60 seconds per API key, route, and HTTP method (some routes have lower limits).

X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset (seconds until the API key window resets), X-RateLimit-Policy, and X-RateLimit-Endpoint. On 429 responses, Retry-After (seconds) and X-RateLimit-Dimension indicate which limit was exceeded.

Safe retry rules

Integrations, plugins, and API clients must implement resilient retry behaviour. Never retry immediately in a tight loop.

  • Retry only 429 and transient 5xx responses — never retry 4xx validation or auth errors.
  • On 429, wait at least the Retry-After header value (in seconds) before the next attempt.
  • Use exponential backoff with jitter: start at 1s, double each attempt, cap at 60s, add random jitter (±20%).
  • Use a circuit breaker: after 5 consecutive failures, stop requests for 30–120s, then allow a single probe.
  • Respect X-RateLimit-Remaining and throttle proactively when remaining quota is low.
HTTP/1.1 429 Too Many Requests
Retry-After: 42
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 42
X-RateLimit-Dimension: api_key

{
    "errors": [
        {
            "title": "You reached the limit of requests in one minute, please wait.",
            "status": "429",
            "detail": "Rate limit exceeded for dimension \"api_key\" on endpoint \"campaigns:GET\". Retry after 42 seconds."        }
    ],
    "meta": {
        "rate_limit": {
            "dimension": "api_key",
            "endpoint": "campaigns:GET",
            "limit": 60,
            "retry_after": 42
        }
    }
}
class FomoApiClient {
    constructor({ baseUrl, apiKey, maxRetries = 5 }) {
        this.baseUrl = baseUrl.replace(/\/$/, '');
        this.apiKey = apiKey;
        this.maxRetries = maxRetries;
        this.consecutiveFailures = 0;
        this.circuitOpenUntil = 0;
    }

    async request(path, options = {}) {
        if(Date.now() < this.circuitOpenUntil) {
            throw new Error('Circuit breaker open — too many recent failures');
        }

        let attempt = 0;

        while(true) {
            const response = await fetch(`${this.baseUrl}${path}`, {
                ...options,
                headers: {
                    'Authorization': `Bearer ${this.apiKey}`,
                    'Accept': 'application/json',
                    ...(options.headers || {}),
                },
            });

            if(response.ok) {
                this.consecutiveFailures = 0;
                return response.json();
            }

            const retryable = response.status === 429 || response.status >= 500;

            if(!retryable || attempt >= this.maxRetries) {
                this.consecutiveFailures++;
                if(this.consecutiveFailures >= 5) {
                    this.circuitOpenUntil = Date.now() + 60000;
                }
                throw new Error(`API error ${response.status}`);
            }

            const retryAfterHeader = parseInt(response.headers.get('Retry-After') || '0', 10);
            const backoffMs = retryAfterHeader > 0
                ? retryAfterHeader * 1000
                : Math.min(60000, 1000 * Math.pow(2, attempt));
            const jitter = backoffMs * (0.8 + Math.random() * 0.4);

            await new Promise(resolve => setTimeout(resolve, jitter));
            attempt++;
        }
    }
}

Errors

Our API uses conventional HTTP status codes to indicate the success or failure of a request.

{
    "errors": [
        {
            "title": "You do not have access to the API.",
            "status": 401
        }
    ]
}
200 Request completed successfully
400 Bad request - Required parameters are missing or invalid
401 Unauthorized - API key is missing or invalid
404 The requested resource was not found
429 Too many requests - Rate limit exceeded. Check the Retry-After header before retrying.
500 Internal server error - this means there is a problem on our end
All API endpoint results work with the UTC timezone unless specified otherwise.
User
Statistics
Campaigns
Campaign notifications
Notification handlers
Account logs

Everything you need to create real urgency on your store

Real Urgency. Real Proof. Real Sales , All in One Place.