Skip to main content
LeadMagic is built with developers in mind. Every response includes rich metadata, standardized headers, and detailed error messages to make debugging and monitoring effortless.

Why We Build This Way

Our Philosophy: APIs should be predictable, transparent, and never surprise you. Every decision in our API design prioritizes developer happiness and operational confidence.

Design Principles

Standards-First

We follow RFC 9457 for errors, IETF draft-ietf-httpapi-ratelimit-headers for rate limits, and RFC 7807 patterns throughout. No proprietary formats to learn.

Observable by Default

Every response includes 15+ headers giving you complete visibility into credits, rate limits, concurrency, and usage - without extra API calls.

Graceful Degradation

Soft-mode rate limiting, automatic retries, and fallback mechanisms mean our limits guide you rather than break you.

Context-Rich Errors

Errors include actionable suggestions, documentation links, and machine-readable context so you can handle them programmatically.

Why Response Headers Matter

Traditional APIs force you to make extra calls to check your balance or limits. LeadMagic embeds everything in response headers:
# One request = Full operational context
curl -I 'https://api.leadmagic.io/v1/people/email-validation' \
  -H 'X-API-Key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"email": "test@example.com"}'
Every response includes:
  • Your remaining credits (X-Credits-Remaining)
  • Rate limit status (RateLimit-Remaining, RateLimit-Reset)
  • Daily quota (X-RateLimit-Remaining-Daily)
  • Usage percentages (X-RateLimit-Daily-Usage-Percent)
  • Soft mode status (X-RateLimit-Soft-Mode)
This means you can build dashboards, set up alerts, and implement smart rate limiting without polling separate endpoints.

Response Headers

Every API response includes comprehensive headers for monitoring, debugging, and rate limit management.
Following the IETF draft-ietf-httpapi-ratelimit-headers standard:
HeaderDescriptionExample
RateLimit-LimitMaximum requests per minute3000
RateLimit-RemainingRequests remaining this minute2847
RateLimit-ResetSeconds until limit resets42

Legacy X- Headers (Backwards Compatible)

HeaderDescriptionExample
X-RateLimit-LimitMaximum requests per minute3000
X-RateLimit-RemainingRequests remaining this minute2847
X-RateLimit-ResetUnix timestamp when limit resets1706745600

Daily Limit Headers

HeaderDescriptionExample
X-RateLimit-Limit-DailyMaximum requests per day500000
X-RateLimit-Remaining-DailyRequests remaining today485000
X-RateLimit-Reset-DailyUnix timestamp when daily limit resets1706832000

Complete Header Reference

Here’s a real-world example showing all headers in a typical response:
HTTP/2 200 OK
Content-Type: application/json

# IETF Standard Rate Limit Headers (Use these!)
RateLimit-Limit: 3000
RateLimit-Remaining: 2847
RateLimit-Reset: 42

# Legacy Rate Limit Headers (Backwards compatible)
X-RateLimit-Limit: 3000
X-RateLimit-Remaining: 2847
X-RateLimit-Reset: 1706745600

# Daily Limits
X-RateLimit-Limit-Daily: 500000
X-RateLimit-Remaining-Daily: 485000
X-RateLimit-Reset-Daily: 1706832000

# Credits Tracking
X-Credits-Remaining: 15432.50
X-Credits-Cost: 0.05

# Usage Metrics (percentages for easy alerting)
X-RateLimit-Daily-Usage-Percent: 3
X-RateLimit-RPM-Usage-Percent: 5

# Soft Mode (we warn but don't block)
X-RateLimit-Soft-Mode: true

# Concurrency
X-Concurrent-Requests: 12
X-Active-Reservations: 0
X-Peak-Concurrency: 45

# Request Tracking
X-Request-ID: req_abc123def456
Pro Tip: Log these headers after every request. When debugging issues, you’ll have complete visibility into your API state at that exact moment.

Request Headers

Required Headers

HeaderDescriptionExample
X-API-KeyYour API key (case-insensitive)lm_live_abc123...
Content-TypeAlways application/json for POSTapplication/json
Case-Insensitive Authentication: The X-API-Key header accepts any case variation: X-API-Key, X-API-KEY, x-api-key all work identically.

Optional Headers

HeaderDescriptionUse Case
User-AgentIdentifies your applicationUsed for timeout optimization (Clay integrations get longer timeouts)
X-Request-IDYour request tracking IDReturned in error responses for debugging
AcceptResponse formatapplication/json (default)

Success Messages

Every endpoint returns a human-readable message field that tells you exactly what happened. These are designed to be user-friendly and can be displayed directly in your UI.
MessageMeaning
Email is valid.Email verified as deliverable
Email is valid (catch-all domain with engagement data).Valid with extra confidence on catch-all domain
Email is invalid.Email doesn’t exist or bounces
Domain accepts all emails (catch-all). Unable to verify specific address.Can’t verify on catch-all domain
Unable to determine email validity.Verification inconclusive
Why Messages Matter: These aren’t just for humans - they’re also machine-readable. Check the message field to determine success vs. not-found scenarios, especially when credits_consumed might still be > 0 for verified “not found” results.

Analytics Endpoints

Monitor your API usage programmatically with our comprehensive analytics suite.
All analytics endpoints are FREE - they don’t consume any credits and are exempt from rate limiting.

Dashboard Overview

Get a real-time snapshot of your account status:
curl 'https://api.leadmagic.io/v1/analytics/dashboard' \
  -H 'X-API-Key: YOUR_API_KEY'
Response:
{
  "user": {
    "id": "user_abc123",
    "email": "developer@company.com"
  },
  "credits": {
    "current": 15432.50,
    "formatted": "$154.33"
  },
  "rate_limit": {
    "minute": {
      "limit": 3000,
      "used": 45,
      "remaining": 2955,
      "utilization": 1.5
    },
    "daily": {
      "limit": 500000,
      "used": 12500,
      "remaining": 487500,
      "utilization": 2.5
    }
  },
  "concurrency": {
    "current": 0,
    "peak": 23,
    "active_reservations": 0
  },
  "stats": {
    "today": {
      "requests": 1250,
      "credits": 875.50,
      "chargeable_requests": 1100,
      "chargeable_rate": 88.0,
      "unique_products": 5
    },
    "this_week": {
      "requests": 8500,
      "credits": 5200.25,
      "chargeable_requests": 7200,
      "chargeable_rate": 84.7,
      "unique_products": 8
    },
    "this_month": {
      "requests": 45000,
      "credits": 28500.00,
      "chargeable_requests": 38000,
      "chargeable_rate": 84.4,
      "unique_products": 12
    }
  }
}

Available Analytics Endpoints

GET /v1/analytics/dashboard

Real-time dashboard with credits, rate limits, and usage stats for today, this week, and this month.

GET /v1/analytics/usage

Daily usage summary with total requests, credits consumed, and chargeable rates.Query params: ?days=30 (1-90)

GET /v1/analytics/products

Per-product breakdown showing requests, credits, success rates, and average costs.Query params: ?days=30 (1-90)

GET /v1/analytics/credits

Credit consumption history with daily breakdown and chargeable request analysis.Query params: ?days=30 (1-90)

GET /v1/analytics/summary

All-time statistics including total requests, credits consumed, success rates, and first/last request timestamps.Query params: ?start_date=YYYY-MM-DD&end_date=YYYY-MM-DD

GET /v1/analytics/daily

Detailed daily metrics with latency percentiles, error rates, and performance data.Query params: ?days=30 (1-90)

GET /v1/analytics/day/:date

Per-product breakdown for a specific day. Top 15 products plus aggregated “other” category.Path param: :date in YYYY-MM-DD format

Usage Example: Daily Breakdown

curl 'https://api.leadmagic.io/v1/analytics/usage?days=7' \
  -H 'X-API-Key: YOUR_API_KEY'
Response:
{
  "period": {
    "start": "2025-10-25",
    "end": "2025-11-01",
    "days": 7
  },
  "summary": {
    "total_requests": 8500,
    "chargeable_requests": 7200,
    "total_credits": 5200.25,
    "avg_credits_per_request": 0.61,
    "chargeable_rate": 84.7,
    "unique_products": 8
  },
  "daily": [
    {
      "date": "2025-11-01",
      "total_requests": 1250,
      "chargeable_requests": 1100,
      "total_credits": 875.50,
      "unique_products_used": 5
    }
    // ... more days
  ]
}

Credits Endpoints

Check Your Balance

curl 'https://api.leadmagic.io/v1/credits' \
  -H 'X-API-Key: YOUR_API_KEY'
Response:
{
  "credits": 15432.50
}

Additional Credits Endpoints

EndpointMethodDescription
GET /v1/creditsGETGet current credit balance
POST /v1/credits/refreshPOSTForce refresh credits from database
GET /v1/credits/healthGETValidate API key and check authentication status

Error Handling

LeadMagic follows RFC 9457 Problem Details for standardized, machine-readable error responses.

Error Response Format

{
  "success": false,
  "errors": [
    {
      "type": "https://api.leadmagic.io/errors/insufficient_credits",
      "title": "Insufficient credits: need 5, have 2.50. Add credits to continue.",
      "status": 402,
      "detail": "This request requires 5 credit(s) but your account only has 2.50 credits remaining.",
      "instance": "/v1/people/mobile-finder#req_abc123",
      "code": "insufficient_credits",
      "action": "Add credits to your account at https://app.leadmagic.io/billing",
      "docs": "https://docs.leadmagic.io/api-reference/credits",
      "context": {
        "credits_required": 5,
        "credits_available": 2.50,
        "credits_needed": 2.50
      }
    }
  ],
  "meta": {
    "request_id": "req_abc123",
    "timestamp": "2025-10-01T12:00:00.000Z",
    "environment": "production"
  }
}

Response Fields Explained

FieldDescription
typeURI identifying the error type (machine-readable)
titleHuman-readable summary (safe to display to users)
statusHTTP status code
detailSpecific explanation of what went wrong
codeShort error code for programmatic handling
actionSuggested fix or next steps
docsLink to relevant documentation
contextMachine-readable details (varies by error type)

HTTP Status Codes

200

Success - Request completed

400

Bad Request - Invalid input

401

Unauthorized - Invalid API key

402

Payment Required - Low credits

429

Too Many Requests - Rate limited

500

Server Error - Our fault

Error Types

HTTP 401 - Unauthorized
CodeDescription
missing_authenticationNo API key provided in X-API-Key header
invalid_api_keyAPI key doesn’t exist or is incorrect
insufficient_permissionsAPI key lacks access to this resource
{
  "errors": [{
    "type": "https://api.leadmagic.io/errors/invalid_api_key",
    "title": "Invalid API key. The key does not exist or is incorrect.",
    "status": 401,
    "code": "invalid_api_key",
    "docs": "https://docs.leadmagic.io/api-reference/authentication"
  }]
}

Idempotency

Every request can include a unique identifier for tracking and debugging:
curl -X POST 'https://api.leadmagic.io/v1/people/email-validation' \
  -H 'X-API-Key: YOUR_API_KEY' \
  -H 'X-Request-ID: my-unique-request-id-123' \
  -H 'Content-Type: application/json' \
  -d '{"email": "test@example.com"}'
The X-Request-ID is returned in error responses and logged for debugging:
{
  "errors": [{
    "instance": "/v1/people/email-validation#my-unique-request-id-123"
  }],
  "meta": {
    "request_id": "my-unique-request-id-123"
  }
}

Graceful Degradation

LeadMagic is designed to handle failures gracefully:
ScenarioBehavior
DO TimeoutFalls back to direct database query
Rate limit in soft modeLogs warning but allows request
External service failureReturns 502 with retry guidance
Database unavailableReturns 503 with retry timing
High Availability: Our Durable Objects provide sub-millisecond rate limiting with automatic failover to PostgreSQL when needed.

Best Practices

When you receive a 429 error, use the Retry-After header:
async function callWithRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    const response = await fn();

    if (response.status === 429) {
      const retryAfter = response.headers.get('Retry-After') || Math.pow(2, i);
      await sleep(retryAfter * 1000);
      continue;
    }

    return response;
  }
  throw new Error('Max retries exceeded');
}
Build proactive monitoring using response headers:
async function monitoredRequest(url, options) {
  const response = await fetch(url, options);

  const dailyUsage = response.headers.get('X-RateLimit-Daily-Usage-Percent');
  const creditsRemaining = response.headers.get('X-Credits-Remaining');

  if (parseInt(dailyUsage) > 80) {
    alert('Approaching daily rate limit: ' + dailyUsage + '%');
  }

  if (parseFloat(creditsRemaining) < 1000) {
    alert('Low credits: ' + creditsRemaining);
  }

  return response;
}
Always include a request ID for easier debugging:
const requestId = `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;

const response = await fetch(url, {
  headers: {
    'X-API-Key': apiKey,
    'X-Request-ID': requestId,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
});

// Log for debugging
console.log(`Request ${requestId}: ${response.status}`);
Don’t call /v1/credits before every request. Cache and refresh periodically:
let cachedCredits = null;
let lastFetch = 0;
const CACHE_TTL = 60000; // 1 minute

async function getCredits() {
  if (cachedCredits && Date.now() - lastFetch < CACHE_TTL) {
    return cachedCredits;
  }

  const response = await fetch('https://api.leadmagic.io/v1/credits', {
    headers: { 'X-API-Key': apiKey }
  });

  const { credits } = await response.json();
  cachedCredits = credits;
  lastFetch = Date.now();
  return credits;
}

SDK Support

While we don’t have official SDKs yet, our REST API works seamlessly with any HTTP client:

Node.js

Use native fetch or axios for HTTP requests.

Python

Use requests or httpx for async support.

Any Language

Any HTTP client works - just send JSON with your API key.

Why We Built It This Way

Traditional APIs return cryptic errors like {"error": "Bad request"}. This leaves developers guessing what went wrong and how to fix it.Our approach: Every error follows RFC 9457 Problem Details, a standard designed by the IETF specifically for HTTP API errors. This means:
  • type: A URI identifying the error type (bookmarkable, consistent)
  • title: Human-readable summary you can show users
  • status: HTTP status code (redundant but useful)
  • detail: Specific explanation of what went wrong
  • action: Suggested fix (unique to LeadMagic)
  • docs: Link to relevant documentation
  • context: Machine-readable details (credits needed, rate limits, etc.)
This isn’t just for show - your code can programmatically handle errors based on type while showing users the title and action.
We implement the IETF draft-ietf-httpapi-ratelimit-headers standard for rate limit headers:
RateLimit-Limit: 3000
RateLimit-Remaining: 2847
RateLimit-Reset: 42
Why this matters:
  • These headers are on track to become an official standard
  • Libraries already support them (many HTTP clients auto-parse)
  • Consistent across all modern APIs that implement the spec
  • No need to learn LeadMagic-specific header names
We also include legacy X-RateLimit-* headers for backwards compatibility.
Most APIs hard-block you when you hit limits. This causes:
  • Unexpected failures in production
  • Data loss if you’re mid-batch
  • Frustrated developers
Our approach: Soft mode warns but doesn’t block. When you exceed limits, we:
  1. Log the violation
  2. Set X-RateLimit-Soft-Exceeded: true
  3. Still process your request
This gives you time to fix your implementation without breaking production. Watch for the header in logs and fix before we have to enforce limits.
Checking your balance shouldn’t require extra API calls. Every enrichment response includes:
X-Credits-Remaining: 15432.50
X-Credits-Cost: 1
Benefits:
  • Build credit alerts without polling
  • Log spend per-request for cost attribution
  • Pause automatically when credits run low
  • Never wonder “how much did that cost?”
Our message field isn’t just “success” - it tells you what actually happened:
  • "Email is valid." - Great, use it!
  • "Domain accepts all emails (catch-all)." - Be cautious
  • "No email found for this person." - Try different inputs
This lets you:
  • Display messages directly to end users
  • Make programmatic decisions based on outcomes
  • Distinguish between “not found” and “error”
All analytics endpoints are FREE - no credits consumed, no rate limits. This means you can:
  • Poll /v1/analytics/dashboard every minute
  • Build real-time dashboards
  • Set up alerting without worrying about cost
  • Audit your usage as often as needed
We want you to have complete visibility into your API usage.

Next Steps