API Reference

Overview

LeadFlags scores inbound leads with predefined quality criteria and returns a numeric score, quality level, flags, and a recommended action.

JSON-first. All requests and responses use Content-Type: application/json. No form-encoded or XML.
Deterministic. Same input always produces the same output. No AI, no enrichment, no profiling. Rules are transparent and auditable.

Use LeadFlags before CRM ingestion to filter low-quality leads, reduce wasted calls, and focus your team on leads that convert.

Base URL

All API requests use this base:

https://leadflags.com

Example: POST https://leadflags.com/api/score-lead/

Endpoint

POST /api/score-lead

Accepts a JSON body with lead data. No required fields; send only what you have.

Headers (required)

HeaderDescription
Content-TypeMust be application/json
X-API-KeyYour API key (required). Get it from the dashboard.
Authorization: Bearer — Coming soon. Currently only X-API-Key is supported.

Body

Arbitrary JSON object—no fixed schema. We detect scoring fields by key aliases (case-insensitive, - and _ treated the same). Unknown keys are stored as metadata and not used for scoring.

Canonical fieldAccepted keys (examples)Description
namename, fullName, first_name, last_name, contactContact name (first + last combined if sent separately)
emailemail, e-mail, mail, emailAddressEmail address
phonephone, telephone, mobile, phoneNumber, cellPhone (E.164 or national format)
messagemessage, body, notes, comment, contentMessage or notes
sourcesource, utm_source, lead_source, channelLead source (e.g. website, campaign)
countrycountry, geo, countryCode, country_isoCountry (ISO2 or name). Consistency only (e.g. phone vs country)
Any other keyStored as metadata; not used in scoring

Schema-flexible input, deterministic output

LeadFlags accepts any JSON structure—nested objects, arrays, mixed keys. There is no fixed schema. We detect canonical fields (name, email, phone, message, source, country, etc.) via a versioned synonym dictionary and optional overrides. Same input with the same detector_version always yields the same normalized result.

Optional mapping override: If your payload uses non-standard keys, you can tell us explicitly with a reserved object _leadflags_map. Map a JSON path or key to a canonical field:

{
  "contactEmail": "user@example.com",
  "tel": "+34987654321",
  "_leadflags_map": {
    "contactEmail": "email",
    "tel": "phone"
  }
}

Only known canonical field names are allowed in the map. If a path is missing, a warning is added and detection continues with synonyms/heuristics.

Normalize-only endpoint: POST https://leadflags.comapi/normalize-lead returns the full normalization result (detector_version, canonical_lead, detected_fields, missing_fields, conflicts, warnings) and optionally score/quality/flags. Use it to inspect how we interpreted your payload without changing scoring logic. Query ?debug_mode=1 for full conflict and source_path details.

detected_fields indicates which canonical field was filled, from which path, and by which method (override, key synonym, or heuristic). It does not expose how the score is computed.

Request examples

All examples send the same JSON body and require X-API-Key. Replace YOUR_API_KEY with your key.

curl -X POST "https://leadflags.com/api/score-lead/" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{"name":"Pieter van der Berg","email":"pieter@bedrijf.nl","phone":"+31612345678","message":"Interested in enterprise plan","source":"website","country":"NL"}'
fetch("https://leadflags.com/api/score-lead/", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-API-Key": "YOUR_API_KEY"
  },
  body: JSON.stringify({
    name: "Jane Doe",
    email: "jane@company.com",
    phone: "+34912345678",
    message: "Interested in enterprise plan",
    source: "website",
    country: "ES"
  })
})
  .then(res => res.json())
  .then(data => console.log(data));
$ch = curl_init("https://leadflags.com/api/score-lead/");
curl_setopt_array($ch, [
  CURLOPT_POST => true,
  CURLOPT_POSTFIELDS => json_encode([
    'name' => 'Pieter van der Berg',
    'email' => 'pieter@bedrijf.nl',
    'phone' => '+31612345678',
    'message' => 'Interested in enterprise plan',
    'source' => 'website',
    'country' => 'NL'
  ]),
  CURLOPT_HTTPHEADER => [
    'Content-Type: application/json',
    'X-API-Key: YOUR_API_KEY'
  ],
  CURLOPT_RETURNTRANSFER => true
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
import requests

response = requests.post(
    "https://leadflags.com/api/score-lead/",
    headers={
        "Content-Type": "application/json",
        "X-API-Key": "YOUR_API_KEY"
    },
    json={
        "name": "Jane Doe",
        "email": "jane@company.com",
        "phone": "+34912345678",
        "message": "Interested in enterprise plan",
        "source": "website",
        "country": "ES"
    }
)
data = response.json()
require 'net/http'
require 'json'

uri = URI("https://leadflags.com/api/score-lead/")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = (uri.scheme == 'https')
req = Net::HTTP::Post.new(uri)
req['Content-Type'] = 'application/json'
req['X-API-Key'] = 'YOUR_API_KEY'
req.body = {
  name: 'Pieter van der Berg',
  email: 'pieter@bedrijf.nl',
  phone: '+31612345678',
  message: 'Interested in enterprise plan',
  source: 'website',
  country: 'NL'
}.to_json
res = http.request(req)
data = JSON.parse(res.body)

Response format

On success (200), the response body is (example for the request above — complete lead, no flags):

{
  "score": 100,
  "quality": "high",
  "flags": [],
  "recommended_action": "call_immediately"
}
FieldTypeDescription
scorenumber0–100. Higher = better quality.
qualitystringhigh | medium | low
flagsstring[]List of flag codes explaining deductions (see Flags reference).
recommended_actionstringcall_immediately | review_before_call | do_not_call
country and country_sent are not currently included in the response body. Geographic fields in the request are used only for consistency checks (e.g. phone vs country).

Quality levels & recommended actions

Default thresholds (customizable via query params ?mid=80&low=50 for Enterprise):

ScoreQualityRecommended action
≥ 80highcall_immediately
50–79mediumreview_before_call
< 50lowdo_not_call

Flags reference

Flags explain why the score was reduced. Each flag has a severity (Low, Medium, High, Critical) that reflects its relative importance. Exact score weights are internal and may change over time.

Name

FlagDescriptionTypical causeSeverity
missing_nameName not provided or emptyField omitted or blankMedium
very_short_nameName too short (e.g. single letter)Placeholder or typoMedium
numeric_nameName is mostly numbersTest data or fakeHigh
random_nameName looks random (e.g. jumbled chars)Spam or testHigh

Email

FlagDescriptionTypical causeSeverity
missing_emailEmail not provided or emptyField omittedHigh
invalid_emailEmail format invalidTypo or invalid formatHigh
disposable_emailDisposable/temp email domainOne-time email servicesHigh
free_email_domainFree provider (Gmail, Yahoo, etc.)Personal vs businessLow
role_emailRole-based address (info@, support@)Generic mailboxMedium

Phone

FlagDescriptionTypical causeSeverity
missing_phonePhone not provided or emptyField omittedHigh
invalid_phonePhone format invalidWrong format or typoCritical
too_short_phoneToo few digitsIncomplete numberHigh
repeated_digits_phoneMostly repeated digits (e.g. 1111111)Placeholder or fakeMedium

Message

FlagDescriptionTypical causeSeverity
missing_messageMessage not provided or emptyField omittedMedium
short_messageMessage too shortLow intent or placeholderMedium
generic_messageGeneric or template-like textCopy-paste or botMedium
spam_keywordsSpam-like wording detectedSpam or abuseHigh

Source

FlagDescriptionTypical causeSeverity
missing_sourceSource not provided or emptyField omittedLow
test_sourceSource indicates test (e.g. "test", "demo")Test submissionHigh
unknown_sourceSource not in known listNew or custom sourceLow

Country

FlagDescriptionTypical causeSeverity
missing_countryCountry/geo not providedField omittedLow
invalid_countryCountry value could not be normalizedTypo or unknown codeLow
country_phone_mismatchPhone prefix does not match countryWrong country or fake phoneHigh
Note. Flag severity reflects relative importance. Exact score weights are internal and may change over time to improve accuracy.

Thresholds, rate limits & support

Thresholds

A threshold is the limit at which something changes. In our case: score threshold and action threshold. Example: score ≥ 80 → call immediately; score ≥ 50 → review; score < 50 → do not call.

Custom thresholds (Enterprise)

Pass query parameters mid=X and low=X to set your own cutoffs.

Example: POST /api/score-lead?mid=70&low=40 — then score ≥ 70 is high, ≥ 40 is medium, < 40 is low. Defaults: mid=80, low=50.

Rate limit

How many requests you can make per minute. Examples: Starter 60 req/min, Growth 300 req/min, Scale 1,000 req/min. This protects the server, prevents abuse, and prioritizes premium clients.

Priority processing

When there's load: Starter uses the normal queue; Growth and Scale use the fast queue. At first this can be symbolic, but it sends a clear value message.

Support

Email support: We reply when we can. No guaranteed response times.

Fast / priority support: Response in < 24h. Priority over Starter. You don't need a full support team for this.

IP allowlist (Enterprise)

Only traffic from authorised IPs is accepted. Clients ask for it for security and compliance.

Early access to new features

Growth (and similar) see new features first, help validate them, and feel premium.

Errors

Error responses use standard HTTP status codes and a JSON body with error and optional message.

400 Bad Request — invalid_json

Request body is not valid JSON.

{
  "error": "invalid_json"
}

401 Unauthorized

Missing or invalid X-API-Key header.

{
  "error": "Unauthorized",
  "message": "Valid X-API-Key header required"
}

405 Method Not Allowed

Endpoint only accepts POST.

{
  "error": "Method Not Allowed"
}

Response includes Allow: POST header.

200 OK

Success. Body contains score, quality, flags, recommended_action.

Best practices

  • Send only what you have. Don’t invent or guess data. Empty or omitted fields are scored accordingly.
  • Use LeadFlags before CRM ingestion. Score at the gate so you don’t store or process low-quality leads.
  • Log score and flags in your system. Keep a record for routing, analytics, and auditing.
  • Treat recommended_action as a suggestion. You decide how to route (call immediately, queue for review, or do not call).