XMagnet API Documentation

https://api.xmagnet.ai/v1

Enrich contacts, validate emails, and search your database programmatically. All endpoints use a simple API key for authentication and a credit-based billing model.

Quick Start

1

Get Your API Key

Log in to the XMagnet Dashboard and navigate to Settings → API Keys. Click Generate New Key, give it a label, and copy the key. You won’t be able to see the full key again.

2

Make Your First Request

Use the key in the X-API-Key header to enrich a contact:

curl -X POST https://api.xmagnet.ai/v1/enrich/single \
  -H "Content-Type: application/json" \
  -H "X-API-Key: xm_live_YOUR_KEY_HERE" \
  -d '{
    "email": "jane@example.com"
  }'
3

Check Your Response

A successful response returns enriched contact data:

{
  "status": "success",
  "data": {
    "email": "jane@example.com",
    "first_name": "Jane",
    "last_name": "Doe",
    "title": "VP of Marketing",
    "company": "Acme Corp",
    "linkedin_url": "https://linkedin.com/in/janedoe",
    "location": "San Francisco, CA",
    "industry": "Technology"
  },
  "credits_used": 1,
  "credits_remaining": 4999
}

Authentication

Every request must include your API key. You can pass it in either of two headers:

Header Format Example
X-API-Key Raw key value X-API-Key: xm_live_abc123...
Authorization Bearer token Authorization: Bearer xm_live_abc123...

Key Types

Prefix Environment Description
xm_live_... Production Consumes credits and returns real data. Use in production applications.
xm_test_... Test Returns mock data and does not consume credits. Use during development.

Endpoints

Contact Enrichment

Single Enrichment

POST /v1/enrich/single
Scope: enrich:read

Enrich a single contact by email address, LinkedIn URL, or name + company combination.

Request Body

Field Type Required Description
email string One of email, linkedin_url, or name+company required Contact’s email address
linkedin_url string One of email, linkedin_url, or name+company required Full LinkedIn profile URL
first_name string Required with company Contact’s first name
last_name string Required with company Contact’s last name
company string Required with name Company name or domain

Python Example

import requests

url = "https://api.xmagnet.ai/v1/enrich/single"
headers = {
    "Content-Type": "application/json",
    "X-API-Key": "xm_live_YOUR_KEY_HERE"
}
payload = {
    "email": "jane@example.com"
}

response = requests.post(url, json=payload, headers=headers)
data = response.json()
print(data["data"]["title"])  # "VP of Marketing"

JavaScript Example

const response = await fetch("https://api.xmagnet.ai/v1/enrich/single", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-API-Key": "xm_live_YOUR_KEY_HERE"
  },
  body: JSON.stringify({
    email: "jane@example.com"
  })
});

const data = await response.json();
console.log(data.data.title); // "VP of Marketing"

Response

{
  "status": "success",
  "data": {
    "email": "jane@example.com",
    "first_name": "Jane",
    "last_name": "Doe",
    "title": "VP of Marketing",
    "company": "Acme Corp",
    "company_domain": "acmecorp.com",
    "linkedin_url": "https://linkedin.com/in/janedoe",
    "location": "San Francisco, CA",
    "industry": "Technology",
    "company_size": "201-500",
    "phone": "+1-555-0123"
  },
  "credits_used": 1,
  "credits_remaining": 4999
}
Credits: Each successful single enrichment consumes 1 credit. If the contact is not found, no credits are charged.

Bulk Enrichment

POST /v1/enrich/bulk
Scope: enrich:read

Enrich up to 100 contacts in a single request. Each contact in the array follows the same field rules as the single enrichment endpoint.

Request

{
  "contacts": [
    { "email": "jane@example.com" },
    { "email": "john@acmecorp.com" },
    { "linkedin_url": "https://linkedin.com/in/sarahsmith" },
    { "first_name": "Mike", "last_name": "Chen", "company": "globex.com" }
  ]
}

Response

{
  "status": "success",
  "results": [
    {
      "input": { "email": "jane@example.com" },
      "status": "found",
      "data": {
        "email": "jane@example.com",
        "first_name": "Jane",
        "last_name": "Doe",
        "title": "VP of Marketing",
        "company": "Acme Corp"
      }
    },
    {
      "input": { "email": "john@acmecorp.com" },
      "status": "found",
      "data": { ... }
    },
    {
      "input": { "linkedin_url": "https://linkedin.com/in/sarahsmith" },
      "status": "not_found",
      "data": null
    },
    {
      "input": { "first_name": "Mike", "last_name": "Chen", "company": "globex.com" },
      "status": "found",
      "data": { ... }
    }
  ],
  "summary": {
    "total": 4,
    "found": 3,
    "not_found": 1,
    "credits_used": 3
  },
  "credits_remaining": 4996
}
Credits: Only successful matches consume credits. The summary object tells you exactly how many credits were used.

Email Validation

Single Validation

POST /v1/validate/single
Scope: validate:read

Validate a single email address. Returns deliverability status, risk score, and detailed checks.

Request

{
  "email": "jane@example.com"
}

Response

{
  "status": "success",
  "data": {
    "email": "jane@example.com",
    "result": "deliverable",
    "score": 98,
    "is_free_provider": false,
    "is_disposable": false,
    "is_role_based": false,
    "is_catch_all": false,
    "mx_found": true,
    "smtp_check": true,
    "suggestion": null
  },
  "credits_used": 1,
  "credits_remaining": 4998
}

Result Values

Value Description
deliverable The email address is valid and accepting mail.
undeliverable The email address does not exist or is rejecting mail.
risky The email may be a catch-all, disposable, or role-based address. Use with caution.
unknown Unable to determine deliverability (e.g., server timeout). No credits are charged.

Bulk Validation

POST /v1/validate/bulk
Scope: validate:read

Validate up to 500 email addresses in a single request.

Request

{
  "emails": [
    "jane@example.com",
    "bouncy@invalid.xyz",
    "info@acmecorp.com"
  ]
}

Response

{
  "status": "success",
  "results": [
    {
      "email": "jane@example.com",
      "result": "deliverable",
      "score": 98
    },
    {
      "email": "bouncy@invalid.xyz",
      "result": "undeliverable",
      "score": 12
    },
    {
      "email": "info@acmecorp.com",
      "result": "risky",
      "score": 55
    }
  ],
  "summary": {
    "total": 3,
    "deliverable": 1,
    "undeliverable": 1,
    "risky": 1,
    "unknown": 0,
    "credits_used": 3
  },
  "credits_remaining": 4995
}

Credits

GET /v1/credits
Scope: credits:read

Check your current credit balance and usage.

Response

{
  "status": "success",
  "data": {
    "plan": "Growth",
    "credits_total": 10000,
    "credits_used": 5004,
    "credits_remaining": 4996,
    "resets_at": "2026-05-01T00:00:00Z"
  }
}

Rate Limits

Rate limits are applied per API key and vary by key type:

Key Type Requests / Second Requests / Minute Bulk Max Items
xm_test_... 5 60 10
xm_live_... (Starter) 10 300 100
xm_live_... (Growth) 25 1,000 250
xm_live_... (Enterprise) 100 5,000 500

When you exceed a rate limit, the API returns a 429 status with retry information:

{
  "status": "error",
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Too many requests. Please retry after 2 seconds.",
    "retry_after": 2
  }
}
Tip: Use exponential backoff when retrying rate-limited requests. The retry_after field tells you exactly how long to wait.

Caching

XMagnet automatically caches enrichment and validation results for 30 days. If you request data for a contact that has been enriched within the last 30 days, the cached result is returned instantly and no credits are consumed.

To force a fresh lookup, pass "force_refresh": true in the request body. This will consume credits normally.

{
  "email": "jane@example.com",
  "force_refresh": true
}

Error Handling

All errors follow a consistent format:

{
  "status": "error",
  "error": {
    "code": "INVALID_REQUEST",
    "message": "The 'email' field must be a valid email address.",
    "field": "email"
  }
}

Status Codes

Code Meaning Description
200 OK Request succeeded.
400 Bad Request Invalid or missing parameters. Check the message field for details.
401 Unauthorized Missing or invalid API key.
402 Payment Required Insufficient credits. Top up your account to continue.
403 Forbidden Your API key does not have the required scope for this endpoint.
404 Not Found The requested endpoint does not exist.
429 Too Many Requests Rate limit exceeded. Wait and retry using the retry_after value.
500 Internal Server Error Something went wrong on our end. Retry or contact support.

API Key Security

Keep your API keys safe. Follow these best practices:

  • Never expose keys in client-side code. API calls should be made from your backend server, never from a browser or mobile app.
  • Use environment variables. Store keys in .env files or your platform’s secret manager — never hard-code them into source files.
  • Rotate keys regularly. You can generate new keys and revoke old ones from the dashboard at any time.
  • Use test keys for development. Test keys (xm_test_...) return mock data and don’t consume credits.
  • Restrict key scopes. When generating a key, grant only the scopes your application needs (e.g., enrich:read only).
Tip: If you suspect a key has been compromised, revoke it immediately from Settings → API Keys and generate a new one.

Code Examples

Python: Enrich a Contact

import requests
import os

API_KEY = os.environ.get("XMAGNET_API_KEY")
BASE_URL = "https://api.xmagnet.ai/v1"

def enrich_contact(email=None, linkedin_url=None, first_name=None, last_name=None, company=None):
    """Enrich a single contact using the XMagnet API."""
    payload = {}
    if email:
        payload["email"] = email
    if linkedin_url:
        payload["linkedin_url"] = linkedin_url
    if first_name:
        payload["first_name"] = first_name
    if last_name:
        payload["last_name"] = last_name
    if company:
        payload["company"] = company

    response = requests.post(
        f"{BASE_URL}/enrich/single",
        json=payload,
        headers={
            "Content-Type": "application/json",
            "X-API-Key": API_KEY
        }
    )
    response.raise_for_status()
    return response.json()

# Usage
result = enrich_contact(email="jane@example.com")
print(f"Name:    {result['data']['first_name']} {result['data']['last_name']}")
print(f"Title:   {result['data']['title']}")
print(f"Company: {result['data']['company']}")
print(f"Credits remaining: {result['credits_remaining']}")

JavaScript: Validate Emails in Bulk

const API_KEY = process.env.XMAGNET_API_KEY;
const BASE_URL = "https://api.xmagnet.ai/v1";

async function validateEmails(emails) {
  const response = await fetch(`${BASE_URL}/validate/bulk`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-API-Key": API_KEY
    },
    body: JSON.stringify({ emails })
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.error.message);
  }

  return response.json();
}

// Usage
const emails = [
  "jane@example.com",
  "bounce@invalid.xyz",
  "info@acmecorp.com"
];

const result = await validateEmails(emails);

result.results.forEach(r => {
  console.log(`${r.email}: ${r.result} (score: ${r.score})`);
});

console.log(`\nSummary: ${result.summary.deliverable} deliverable, ` +
  `${result.summary.undeliverable} undeliverable, ` +
  `${result.summary.risky} risky`);

cURL: Check Credit Balance

curl -X GET https://api.xmagnet.ai/v1/credits \
  -H "X-API-Key: xm_live_YOUR_KEY_HERE"

Limits at a Glance

Limit Value
Max contacts per bulk enrichment 100 (Starter), 250 (Growth), 500 (Enterprise)
Max emails per bulk validation 500
Max API keys per account 10
Cache TTL 30 days
Max request body size 1 MB
Request timeout 30 seconds

Need Help?

We’re here to help you integrate successfully: