Docs

Introduction

All responses are minimal JSON. The free tier is real. Add ?deep=true on a paid plan for richer fields, see Deep below for specifics.

Base: https://api.parseapi.com

Machine-readable: openapi.json (OpenAPI 3.1), or copy for agents.

State and postal require ?country=, codes are not globally unique.

Add ?pretty=true to any request for formatted JSON, handy in a browser or terminal.

Authentication

Send your API key on every request with the X-API-Key header, a static secret, not a token. Set the header and call the endpoint. That is the whole flow.

X-API-Key: YOUR_API_KEY

Authorization: Bearer works too. Same key, either header. Use whichever your client or SDK defaults to.

Authorization: Bearer YOUR_API_KEY
curl "https://api.parseapi.com/ip/8.8.8.8" \
  -H "X-API-Key: YOUR_API_KEY"

SDKs

Official, typed clients for Node, Python, Go, Ruby, PHP, and Rust. One method per endpoint, named after the route, same fields as the raw API. No SDK yet? Plain HTTP works everywhere, see Authentication above.

npm install @parseapi/sdk

import { parseAPI } from '@parseapi/sdk';

const parse = parseAPI('YOUR_API_KEY');
const country = await parse.country('US');

MIT licensed, source on GitHub.

Headers

Every request sends X-API-Key or Authorization: Bearer (see Authentication above). Optionally send your own X-Request-Id for tracing. We echo it back, or generate one (e.g. req_...) if you don't.

X-API-Key: YOUR_API_KEY
X-Request-Id: req_01hxyz…

Authenticated responses include X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset, your per-minute limit, calls left in the current window, and seconds until it rolls over. Separate from your monthly quota. On rate_limited (429), Remaining is 0 and a Retry-After header (seconds) tells you exactly how long to back off.

X-Request-Id: req_01hxyz…
X-Served-From: Virginia
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 42

X-Served-From is the edge that answered, where in plain language (Virginia, Tokyo, …), so you can feel where the request landed.

Error bodies include that same request_id, copy it from Activity in the dashboard if you contact support.

API keys

Create and archive keys in the dashboard. Keys start with parse_. Use a separate one per environment, dev, staging, prod.

Keep secret keys server-side. Call parseAPI from your backend, not from browser code or a public repo.

Need to call from a browser? Create a public key instead. Public keys start with parse_public_ and only work from domains you list, so shipping one in your page source is the point, not a leak. Same header, same responses, same limits.

fetch('https://api.parseapi.com/email/hi@example.com', {
  headers: { 'X-API-Key': 'parse_public_...' }
})

Add example.com and it covers every subdomain too. localhost always works for local development. Metered calls like deep email verification work on public keys and count against your plan, so keep those server-side unless you mean it.

Archiving a key stops it within a few seconds.

Usage

Every plan pools a monthly request quota across all APIs. Cross it and nothing breaks, it's a soft limit, not a cutoff. We email you at 80%, 100%, and 120%, so you see it coming instead of finding out in production.

Deep verification has its own included monthly quota. Deep stops working once it's used, everything else keeps running, and you're never billed unless you turn it on yourself. Enable on-demand billing under Dashboard → Plan to keep deep calls going past your quota, capped at whatever you set.

Track usage in the dashboard.

Errors

Errors return a consistent JSON body: code, message, docs, and request_id.

rate_limited, server_error, and service_unavailable are worth retrying with backoff. Everything else means the request needs a fix, not a retry.

invalid_api_key 401

Missing or bad key. Check X-API-Key or Authorization, or grab a key from Dashboard → Keys.

{
  "code": "invalid_api_key",
  "message": "Invalid or missing API key",
  "docs": "https://parseapi.com/docs#invalid_api_key",
  "request_id": "req_…"
}

invalid_request 400

Missing or invalid input. message names the exact field, fix it and resend.

{
  "code": "invalid_request",
  "message": "Invalid email address",
  "docs": "https://parseapi.com/docs#invalid_request",
  "request_id": "req_…"
}

permission_denied 403

Your key can't perform this action. On a public key with Domain not allowed for this key, the page calling isn't on the key's domain list, add it in Dashboard → Keys. Otherwise, generate a fresh key there.

{
  "code": "permission_denied",
  "message": "Permission denied",
  "docs": "https://parseapi.com/docs#permission_denied",
  "request_id": "req_…"
}

plan_required 403

This team needs its own paid plan. Subscribe it under Dashboard → Plan.

{
  "code": "plan_required",
  "message": "This team needs a paid plan to use the API",
  "docs": "https://parseapi.com/docs#plan_required",
  "request_id": "req_…"
}

not_found 404

No match, or an unknown route. message names exactly what wasn't found, check the path and value.

{
  "code": "not_found",
  "message": "Postal code not found: 00000 (US)",
  "docs": "https://parseapi.com/docs#not_found",
  "request_id": "req_…"
}

rate_limited 429

Too many requests in a short window. Back off and retry after Retry-After seconds, see Headers for your live limit and reset countdown.

{
  "code": "rate_limited",
  "message": "Rate limited",
  "docs": "https://parseapi.com/docs#rate_limited",
  "request_id": "req_…"
}

quota_exceeded 429

A monthly allowance is exhausted. Wait for reset, or turn on on-demand billing under Dashboard → Plan.

{
  "code": "quota_exceeded",
  "message": "Monthly email verification limit reached. Basic validation still works without ?deep=true.",
  "docs": "https://parseapi.com/docs#quota_exceeded",
  "request_id": "req_…"
}

server_error 500

Something broke on our side. Retry, if it keeps happening, email Email with your request_id.

{
  "code": "server_error",
  "message": "Server error",
  "docs": "https://parseapi.com/docs#server_error",
  "request_id": "req_…"
}

service_unavailable 503

A required service is temporarily unavailable. Retry shortly, this clears on its own.

{
  "code": "service_unavailable",
  "message": "Authentication temporarily unavailable",
  "docs": "https://parseapi.com/docs#service_unavailable",
  "request_id": "req_…"
}

Deep

Every endpoint returns a full, useful core response on every plan. Free included. Add ?deep=true and paid plans get that same response back, plus one more field: a nested deep object with richer data for the same lookup. There's no separate paid endpoint to learn, same route, same core fields, one param away from more.

Deep fields only ever live inside deep, never mixed into the fields above it. That's deliberate: your code can check if (response.deep) and always know what it got, and we can ship new deep fields later without ever changing what the core response looks like. Nothing built against core breaks when deep grows.

GET /ip/52.94.76.10?deep=true
{
  "ip": "52.94.76.10",
  "country": "US",
  "country_name": "United States",
  "continent": "NA",
  "asn": "AS16509",
  "asn_name": "Amazon.com, Inc.",
  "deep": {
    "state": "OR",
    "city": "Boardman",
    "datacenter": true,
    "provider": "aws"
  }
}

It's opt-in on every call, not a plan-wide switch. Leave off ?deep=true and a paid key gets the exact same lean response as a free one, same fields, same latency, every time.

Supported on IP, email, useragent, phone, and domain. Continent, country, state, city, postal, currency, timezone, elevation, emoji, and MX already return their full payload, there's nothing extra for deep to add there.

For most of those five, deep just returns data we already hold, gated by plan. Email deep is the exception, it runs a live deliverability check, not just a format check, so it also draws from your plan's monthly verification allowance (100 on Free).

APIs

Grouped by what they answer. Locate: where is this? Validate: is this real? Decode: what does this mean?

Questions? Email