Make your first request.

Parse your User-Agent as JSON. No API key needed.

curl https://api.parseapi.com/useragent

Request

Send a GET request to https://api.parseapi.com. The path names the lookup, query parameters adjust it, and the response is JSON.

A path such as /email/{email} is a template. Replace the braces and their contents with your value. URL-encode values containing spaces or reserved characters.

Add ?pretty=true for formatted JSON.

Response

A successful request can answer that an input is invalid. For example, Phone and IBAN can return 200 with valid: false when parsing or a checksum fails. Email rejects malformed addresses with 400. Check the fields as well as the HTTP status.

false
A negative answer to that field's question. valid: false does not mean the request failed.
null
No answer is available for that field. Keep it distinct from false, zero, or an empty string.
Omitted
The field is not part of this response. For example, deep is absent unless requested.

Each endpoint explains its fields, supported inputs, and coverage. Handle missing answers explicitly and allow new fields to be added to the response.

Authentication

Send your API key with the X-API-Key header, the same key you create in the dashboard. No token exchange or refresh step is needed.

X-API-Key: YOUR_API_KEY

The bare /ip and /useragent self-lookups also work without a key. Use a key for other lookups.

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" \
  -H "Parse-Version: 2.0.0"

SDKs

Official clients. One method per endpoint, named after the route, same fields as the raw API. Swift and Kotlin take an app key and send the bundle ID. A language we don't have? Plain HTTP works everywhere, see Authentication above. AI agents get the same lookups as tools, see MCP.

1. Install

Terminal
npm install @parseapi/sdk

2. Add your key

Create a secret key in Keys. Set it in the terminal that will run the example. Keep it on your server.

Terminal environment
export PARSEAPI_KEY='YOUR_API_KEY'

3. Make a request

Look up a country and print its name. This lookup uses your plan's request allowance.

example.mjs
import { parseAPI } from '@parseapi/sdk';

const parse = parseAPI(); // Reads PARSEAPI_KEY.
const country = await parse.country('US');
console.log(country.name);
Run
node example.mjs

Handle errors by code, such as invalid_api_key or not_found. A response with valid: false is a successful lookup.

Handle API errors in your app

The same request, with a handler for API errors. Transport failures still propagate.

example.mjs
import { parseAPI, ParseAPIError } from '@parseapi/sdk';

const parse = parseAPI(); // Reads PARSEAPI_KEY.

try {
  const country = await parse.country('US');
  console.log(country.name);
} catch (error) {
  if (error instanceof ParseAPIError) {
    console.error(error.code, error.status, error.requestId);
  }
  throw error;
}

MIT licensed, source on GitHub.

Headers

Authenticated requests send 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_01hxyzX-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 see where your request was answered.

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

The Parse-Version response header identifies the API version that answered. Send an optional Parse-Version request header to pin your application to a supported contract. Requests that omit it use the team setting in Settings → API version. Your authentication and lookup URL stay the same.

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 check the calling page against the domains you list. They are designed to be included in browser code. 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. Add localhost to the list 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.

Shipping a native app? Create an app key and use the Swift or Kotlin SDK. App keys start with parse_app_. List your iOS bundle ID or Android package name on the key. The SDK sends it as X-App-Id on every request.

1. Install

Add the ParseAPI product to your app target. In Xcode, you can also add the repository URL through Add Package Dependencies.

Package.swift dependency
.package(url: "https://github.com/parseapi/swift", from: "1.4.0")

2. Add your key

Create an app key in Keys and allow your bundle identifier. Replace parse_app_... below. The SDK sends your bundle identifier automatically. Use your server for metered checks.

3. Make a request

Look up a country and print its name. This lookup uses your plan's request allowance.

Swift app code
import ParseAPI

func loadCountry() async throws {
    let parse = try ParseAPI("parse_app_...")
    let country = try await parse.country("US")
    print(country.name)
}

// Call from your app's async task.
// try await loadCountry()

Handle errors by code, such as invalid_api_key or not_found. A response with valid: false is a successful lookup.

Handle API errors in your app

The same request, with a handler for API errors. Transport failures still propagate.

Swift app code
import ParseAPI

func loadCountry() async throws {
    let parse = try ParseAPI("parse_app_...")
    do {
        let country = try await parse.country("US")
        print(country.name)
    } catch let error as ParseAPIError {
        print(error.code, error.status, error.requestId ?? "")
        throw error
    }
}

// Call from your app's async task.
// try await loadCountry()

App IDs match exactly, com.example.weather does not cover com.example.weather.widget. App keys cover lookups and plan deep. Metered endpoints like /carrier and /hlr answer 403 on an app key, call those from your server with a secret key.

Email and VAT behave differently: on an app key, ?deep=true returns the core result plus deep: {}, with no verification charge. Run those deep checks from your server with a secret key.

Archive a key in the dashboard to stop further use. Allow a few seconds for the change to take effect.

Usage and metered lookups

Every plan pools a monthly request allowance across the APIs. New terms allow seven days of grace after the allowance is exceeded, ending sooner if the UTC calendar month resets. After grace, requests return quota_exceeded (429) until the month resets or an upgrade provides enough capacity. There are no automatic request overage charges. Existing teams keep their prior soft-limit policy until they switch plans. See your current terms in Dashboard → Plan.

Responses under the new monthly policy include X-Quota-Limit and X-Quota-Reset. X-Quota-Remaining reports the remaining requests when available; X-Quota-Grace-Until appears during grace. Reset and grace deadlines are UTC Unix timestamps in seconds. Monthly usage counts successful authenticated requests, including metered checks, and updates shortly after a response. These headers are separate from the per-minute rate limit.

Metered products have separate monthly allowances. Email and VAT meter deep checks. Carrier, Caller, and HLR meter the lookup itself. Free includes a limited allowance for these products, too.

When a metered allowance runs out, further checks require on-demand usage on an eligible plan. Enable it and set a shared monthly spending limit under Dashboard → Plan. Without available allowance or enabled on-demand usage, the check returns quota_exceeded. Basic Email and VAT checks work without ?deep=true while the monthly request allowance or grace period permits.

See Plans for included allowances and rates. Each endpoint explains what counts as a metered check.

Errors

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

rate_limited, server_error, and service_unavailable may be temporary. See Retries and timeouts before retrying. Other errors usually require a change to the request, key settings, or plan.

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": "lat and lon must be valid numbers",
  "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. For an app key, check the exact app ID and whether the endpoint allows app keys. Call metered products from your server when using a mobile app. Read the response message before changing keys.

{
  "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_…"
}

api_version_retired 410

The version selected by your request header or team default is retired. Review the upgrade guide, test the matching response contract, then select a supported version in your application. For requests without a header, review the fallback in Settings → API version. Retrying the same version will not fix this error.

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_…"
}

Retries and timeouts

Set a timeout and check the HTTP status before treating a response as data. For rate_limited, wait the number of seconds in Retry-After. Temporary connection failures and 500 or 503 responses can be retried with bounded backoff.

A timeout does not prove the original lookup was never processed. Repeating a metered check can consume another unit. Official SDKs default to no automatic retries for metered checks; choose an explicit retry policy if your application needs one.

Keep the error's request_id when debugging or contacting support. A 429 with quota_exceeded needs allowance or billing action; waiting a few seconds will not resolve it.

A server-side JavaScript example with a ten-second timeout and one attempt:

const response = await fetch('https://api.parseapi.com/ip/8.8.8.8', {
  headers: { 'X-API-Key': 'YOUR_API_KEY', 'Parse-Version': '2.0.0' },
  signal: AbortSignal.timeout(10_000),
});
const body = await response.json();

if (!response.ok) {
  throw new Error(body.code + ': ' + body.message + ' (' + body.request_id + ')');
}

console.log(body);

Run this JavaScript on your server. In a browser, use a public key restricted to your domain.

Deep responses

Add ?deep=true to request additional fields for the same lookup. Those fields live in a nested deep object. The route and its core fields stay the same.

No ?deep=true
The deep key is omitted.
deep: {}
Requested, but no extra fields are included for this endpoint, plan, or key type.
deep: { ... }
Additional fields are included. Individual values may still be null.

An empty object is truthy in JavaScript. Check the field you need explicitly, such as response.deep?.deliverable === true. The presence of deep alone does not mean a check succeeded.

Plan deep is included on paid plans for endpoints such as geography profiles, Name, NAICS, IP, Useragent, Domain, Weather, VIN, NPI and Tariff. Email and VAT deep use metered allowances, including the Free plan's included checks. These can return a quota error when no allowance is available.

Phone core returns validation and formats; ?deep=true adds numbering-plan location on every plan. Time, Date, Currency, Language, Emoji, IBAN and Point also offer optional detail on every plan. Carrier and HLR deep add detail within the same metered lookup, with no second unit. Use Carrier for the serving carrier, Caller for caller ID, or HLR for live status. Each is a separate metered lookup.

APIs

Grouped by what they answer. Locate: where is this? Measure: how high, how many, how hot? Validate: is this real? Decode: what does this mean?

Questions? Email