Leadzy API

Lead capture product reference

Form-agnostic lead capture with flexible metadata, token billing, and two auth surfaces: OpenAPI keys for external capture and JWT for the dashboard.

OpenAPI base

https://api.leadzymarket.com/openapi
API keys

What Leadzy does

A production lead form API: accept any frontend payload, store known fields in columns and the rest in JSON metadata, then manage leads from the dashboard or via API.

Capture anywhere

HTML forms, React/Vue apps, chatbots, and AI agents POST to /openapi/leads. Known fields map to columns; declared custom fields go into metadata.

Two auth systems

External clients use x-api-key on /openapi/*. The dashboard uses JWT Bearer on /api/* with a selected integration apiKeyId.

Pay as you go

DEFAULT and API keys burn tokens per request. Soft deletes preserve history. Rate limits protect every key.

OpenAPI base (forms & agents)

https://api.leadzymarket.com/openapi

Dashboard API base (JWT)

https://api.leadzymarket.com/api
SurfaceAuthLead source
/openapi/leads*x-api-keyImplicit — authenticated key id
/api/leads*Bearer JWTRequired apiKeyId (owned DEFAULT/API key)
/api/keys, /api/payments*Bearer JWTAccount-scoped management

All responses are JSON. Send Content-Type: application/json on POST and PATCH. External capture example: https://api.leadzymarket.com/openapi/leads.

Quick start

Four steps to store your first lead from an external form or agent.

  1. Create an account — signup issues a default integration API key automatically.
  2. Copy your key from the API Keys page (format lz_…).
  3. Declare custom fields on that key (for example company, budget). Only declared custom fields are accepted.
  4. POST JSON to https://api.leadzymarket.com/openapi/leads with the x-api-key header.
curl — create a lead
curl -X POST https://api.leadzymarket.com/openapi/leads \
  -H "Content-Type: application/json" \
  -H "x-api-key: lz_YOUR_KEY_HERE" \
  -d '{
    "name": "Jane Doe",
    "email": "jane@example.com",
    "phone": "+1 555 0100",
    "message": "I would like a demo",
    "source": "website-contact-form",
    "company": "Acme Inc"
  }'
JavaScript — create a lead
const res = await fetch("https://api.leadzymarket.com/openapi/leads", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "x-api-key": process.env.LEADZY_API_KEY // lz_...
  },
  body: JSON.stringify({
    name: "Jane Doe",
    email: "jane@example.com",
    phone: "+1 555 0100",
    message: "I'd like a demo",
    source: "website-contact-form",
    // Declared custom fields on the API key land in metadata:
    company: "Acme Inc",
    plan: "pro"
  })
});

const json = await res.json();
// 201 → { success: true, message: "...", data: { id, name, email, metadata, ... } }

Authentication

Leadzy uses two separate auth systems — do not mix them up.

External / OpenAPIx-api-key

Required on every /openapi/leads* request. Keys look like lz_ plus 48 hex characters. Types: DEFAULT or API. Inactive or expired keys return 401.

HTTP header
x-api-key: lz_0123456789abcdef0123456789abcdef0123456789abcdef
Dashboard / managementAuthorization: Bearer

Used by the web app for /api/leads*, keys, billing, and analytics. Obtain a token via signup or POST /api/auth/login. Lead routes also require an owned apiKeyId.

HTTP header
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
SituationStatusMessage
Missing x-api-key401Missing API key. Provide x-api-key header.
Unknown / inactive key401Invalid or inactive API key.
Expired key401API key has expired.
Missing / invalid JWT401Authentication required.

Create and rotate keys on the API Keys page. Store keys in environment variables — never ship them in browser bundles for public sites (prefer a small server or edge function that proxies the POST).

OpenAPI leads

External CRUD under https://api.leadzymarket.com/openapi/leads. Every lead is scoped to the authenticating API key.

Lead object

FieldTypeNotes
iduuidStable lead identifier
namestring?Max 255 characters
emailstring?Must be a valid email if provided
phonestring?Max 50 characters
messagestring?Free-text message
sourcestring?Where the lead came from (max 255)
statusenumNEW | CONTACTED | CONVERTED | CLOSED (default NEW)
metadataobjectCustom fields declared on the API key
deletedAtdatetime?Set when soft-deleted
createdAtdatetimeISO 8601
updatedAtdatetimeISO 8601
POST/openapi/leads

Create a lead. All body fields are optional, but send at least an email, phone, or name. Custom fields must be declared on the API key; unknown custom fields return 422.

Request body

FieldTypeDescription
namestring?Contact name (max 255)
emailstring?Valid email address
phonestring?Phone number (max 50)
messagestring?Free-text message
sourcestring?Origin label (max 255)
statusenum?NEW | CONTACTED | CONVERTED | CLOSED (default NEW)
…declared custom keysanyMust match metadataFields on the API key; stored under metadata
JavaScript
const res = await fetch("https://api.leadzymarket.com/openapi/leads", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "x-api-key": process.env.LEADZY_API_KEY // lz_...
  },
  body: JSON.stringify({
    name: "Jane Doe",
    email: "jane@example.com",
    phone: "+1 555 0100",
    message: "I'd like a demo",
    source: "website-contact-form",
    // Declared custom fields on the API key land in metadata:
    company: "Acme Inc",
    plan: "pro"
  })
});

const json = await res.json();
// 201 → { success: true, message: "...", data: { id, name, email, metadata, ... } }
Python
import os
import requests

res = requests.post(
    "https://api.leadzymarket.com/openapi/leads",
    headers={
        "Content-Type": "application/json",
        "x-api-key": os.environ["LEADZY_API_KEY"],
    },
    json={
        "name": "Jane Doe",
        "email": "jane@example.com",
        "message": "I would like a demo",
        "source": "agent-integration",
        "company": "Acme Inc",
    },
    timeout=30,
)
res.raise_for_status()
lead = res.json()["data"]
print(lead["id"])
curl
curl -X POST https://api.leadzymarket.com/openapi/leads \
  -H "Content-Type: application/json" \
  -H "x-api-key: lz_YOUR_KEY_HERE" \
  -d '{
    "name": "Jane Doe",
    "email": "jane@example.com",
    "phone": "+1 555 0100",
    "message": "I would like a demo",
    "source": "website-contact-form",
    "company": "Acme Inc"
  }'

Response — 201

Response JSON
{
  "success": true,
  "message": "Lead created successfully.",
  "data": {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "name": "Jane Doe",
    "email": "jane@example.com",
    "phone": "+1 555 0100",
    "message": "I'd like a demo",
    "source": "website-contact-form",
    "status": "NEW",
    "metadata": {
      "company": "Acme Inc",
      "plan": "pro"
    },
    "deletedAt": null,
    "createdAt": "2026-03-31T12:00:00.000Z",
    "updatedAt": "2026-03-31T12:00:00.000Z"
  }
}

Cost is about 0.7–1.0 tokens per create. Insufficient balance returns 402.

GET/openapi/leads

Paginated list of non-deleted leads for this API key. email filter is a case-insensitive contains match.

Query parameters

ParamDefaultDescription
page1Page number (min 1)
limit20Page size (1–100)
emailCase-insensitive email contains filter
statusNEW | CONTACTED | CONVERTED | CLOSED
fromISO 8601 datetime — created after
toISO 8601 datetime — created before
sortBycreatedAtcreatedAt | updatedAt
orderdescasc | desc
JavaScript
const res = await fetch(
  "https://api.leadzymarket.com/openapi/leads?page=1&limit=20&status=NEW&sortBy=createdAt&order=desc",
  { headers: { "x-api-key": process.env.LEADZY_API_KEY } }
);
const { data, meta } = await res.json();
// data: Lead[], meta: { total, page, limit, totalPages }
Response JSON
{
  "success": true,
  "message": "Leads retrieved successfully.",
  "data": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "name": "Jane Doe",
      "email": "jane@example.com",
      "status": "NEW",
      "metadata": { "company": "Acme Inc" },
      "createdAt": "2026-03-31T12:00:00.000Z"
    }
  ],
  "meta": {
    "total": 143,
    "page": 1,
    "limit": 20,
    "totalPages": 8
  }
}
GET/openapi/leads/:id

Fetch one lead by UUID. Returns 404 if missing, deleted, or owned by another key. Costs 0.1 token.

JavaScript
const res = await fetch("https://api.leadzymarket.com/openapi/leads/LEAD_UUID", {
  headers: { "x-api-key": process.env.LEADZY_API_KEY }
});
// 200 → { success: true, data: Lead }
// 404 → { success: false, message: "Lead not found." }
PATCH/openapi/leads/:id

Partial update. Same known fields as create. Declared custom keys merge into metadata. Costs 0.4 token.

Statuses:

NewContactedConvertedLost
JavaScript
const res = await fetch("https://api.leadzymarket.com/openapi/leads/LEAD_UUID", {
  method: "PATCH",
  headers: {
    "Content-Type": "application/json",
    "x-api-key": process.env.LEADZY_API_KEY
  },
  body: JSON.stringify({
    status: "CONTACTED",
    notes: "Called on Monday" // declared custom keys merge into metadata
  })
});
DELETE/openapi/leads/:id

Soft-delete: sets deletedAt. The lead no longer appears in list results. Costs 0.2 token.

JavaScript
const res = await fetch("https://api.leadzymarket.com/openapi/leads/LEAD_UUID", {
  method: "DELETE",
  headers: { "x-api-key": process.env.LEADZY_API_KEY }
});
// Soft-delete: sets deletedAt; lead disappears from list results
// 200 → { success: true, message: "Lead deleted successfully.", data: { id } }

Dashboard API

The Leadzy web app manages leads over JWT. Every lead call selects an integration source with apiKeyId.

Base: https://api.leadzymarket.com/api. Header: Authorization: Bearer <jwt>. Billing uses the same token costs as OpenAPI for the selected key.

MethodPathNotes
GET/api/leadsRequires query apiKeyId; filters + pagination
GET/api/leads/statsRequires query apiKeyId
GET/api/leads/statusesStatus enum metadata
POST/api/leadsBody requires apiKeyId + lead fields
GET/api/leads/:idOwned by JWT user
PATCH/api/leads/:idPartial update / metadata
PATCH/api/leads/:id/statusNumeric status code 1–4 (NEW…CLOSED)
DELETE/api/leads/:idSoft delete
List leads (JWT)
const res = await fetch(
  "https://api.leadzymarket.com/api/leads?apiKeyId=YOUR_KEY_UUID&page=1&limit=20&status=NEW",
  { headers: { Authorization: `Bearer ${process.env.LEADZY_JWT}` } }
);
const { data, meta } = await res.json();
Create lead (JWT)
const res = await fetch("https://api.leadzymarket.com/api/leads", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Authorization: `Bearer ${process.env.LEADZY_JWT}`
  },
  body: JSON.stringify({
    apiKeyId: "YOUR_KEY_UUID",
    name: "Jane Doe",
    email: "jane@example.com",
    source: "manual-entry"
  })
});

Related management routes (JWT): /api/keys, /api/payments/*, /api/auth/me.

Tokens & rate limits

DEFAULT and API keys consume tokens per request. Stay within the rate window to avoid 429s.

OperationApprox. tokensNotes
POST …/leads0.7–1.0More body fields → closer to 1.0
GET …/leads0.3–0.5+0.1 per 20 limit (max 0.5)
GET …/leads/:id0.1Single read
PATCH …/leads/:id0.4Partial update
DELETE …/leads/:id0.2Soft delete

Rate limit

Default: 100 requests per 15 minutes per API key (or per IP if no key). Exceeding the limit returns 429.

Low balance returns 402. Top up tokens from Billing. Packages: starter ($5 / 100), growth ($20 / 500), pro ($35 / 1,000), enterprise ($150 / 5,000).

Errors

Every error uses the same JSON envelope so clients and agents can branch on success and status.

Error envelope
{
  "success": false,
  "message": "Lead not found.",
  "errors": [
    { "field": "email", "message": "Invalid email format" }
  ]
}
StatusWhen it happens
400Malformed request / related constraint error
401Missing/invalid API key or JWT
402Not enough token balance for this request
404Lead or apiKeyId not found / not owned
422Validation failed — see errors[].field
429Rate limit exceeded (100 / 15 min)
500Unexpected server error
Need help? Contact support

For AI agents

Copy this playbook into your tool prompt or skills file. Prefer machine-checked HTTP status and success flags over parsing message text alone.

Recommended agent behavior

  • Always set x-api-key and Content-Type: application/json on OpenAPI writes.
  • Call https://api.leadzymarket.com/openapi/leads— not /api/leads — for public capture.
  • Treat success === true plus 2xx as success; surface message on failure.
  • On 402, stop creating leads and tell the user to top up tokens. On 429, backoff and retry.
  • Use source to tag the agent or channel (e.g. support-bot).
agent-playbook.txt
# Leadzy API — agent integration playbook
#
# Purpose: Capture and manage sales/contact leads via REST.
# External capture auth: x-api-key: lz_<48-hex> on /openapi/leads*
# Dashboard auth: Authorization: Bearer <JWT> on /api/leads* (+ apiKeyId)
# OpenAPI base: https://api.leadzymarket.com/openapi
# Dashboard API base: https://api.leadzymarket.com/api
# Content-Type: application/json for POST and PATCH
#
# Create lead (primary external action):
#   POST /openapi/leads
#   Body (all optional): name, email, phone, message, source, status
#   Custom keys must be declared on the API key; stored under data.metadata
#   Success: HTTP 201, { success: true, data: Lead }
#
# List leads (OpenAPI):
#   GET /openapi/leads?page=1&limit=20&status=NEW&email=&from=&to=&sortBy=createdAt&order=desc
#
# Get / update / delete (OpenAPI):
#   GET    /openapi/leads/:id
#   PATCH  /openapi/leads/:id
#   DELETE /openapi/leads/:id   (soft delete)
#
# Lead.status enum: NEW | CONTACTED | CONVERTED | CLOSED
# Errors: { success: false, message, errors? }
# Tokens: create ~0.7–1.0; list ~0.3–0.5; get 0.1; patch 0.4; delete 0.2
# Rate limit: 100 requests / 15 minutes per API key (or IP)
# Do not use JWT for public form capture — use x-api-key on /openapi/leads.
Python example agents can run
import os
import requests

res = requests.post(
    "https://api.leadzymarket.com/openapi/leads",
    headers={
        "Content-Type": "application/json",
        "x-api-key": os.environ["LEADZY_API_KEY"],
    },
    json={
        "name": "Jane Doe",
        "email": "jane@example.com",
        "message": "I would like a demo",
        "source": "agent-integration",
        "company": "Acme Inc",
    },
    timeout=30,
)
res.raise_for_status()
lead = res.json()["data"]
print(lead["id"])