meowtrace

API Documentation

meowtrace is a REST API for IP address → geolocation. Send an IPv4 address, get back country, region and city. All requests are JSON over HTTPS.

Base URL: https://api.meowtrace.com

Introduction

Every lookup returns a compact JSON record. v1 resolves to country, region and city — honest about resolution, with no invented precision.

Lookups are billed 1 credit each. Your remaining balance is returned in the x-credits-remaining response header, and a per-request id in x-request-id.

Authentication

Lookup endpoints require an API key. Create one in the portal (shown once). Send it as a header:

x-api-key: mt_live_xxxxxxxxxxxxxxxxxxxxxxxx

Portal/account endpoints (keys, billing) use a bearer session token from sign-in instead: Authorization: Bearer <token>.

Errors

Errors share one shape: { "error": { "code", "message" } }.

CodeHTTPMeaning
invalid_ip400Malformed IPv4 address
bad_request400Malformed body or unknown route
batch_too_large400Bulk batch over the 1000-IP cap
unauthorized401Missing or invalid API key / session
not_found404Valid IP, no containing range
out_of_credits429Credit hard-cap reached — refill at next reset

Single lookup

GET /v1/lookup/:ip

Resolve one IPv4 address. Costs 1 credit on success.

curl https://api.meowtrace.com/v1/lookup/1.2.3.4 \
     -H "x-api-key: mt_live_…"

200 OK

{
  "ip": "1.2.3.4",
  "result": {
    "ip": "1.2.3.4",
    "country": { "code": "PL", "name": "Poland" },
    "region": "Mazowieckie",
    "city": "Warsaw"
  }
}

Returns 404 not_found for a valid IP outside coverage, 400 invalid_ip for a malformed address.

Bulk lookup

POST /v1/lookup

Resolve up to 1000 IPs in one request. One bad entry never fails the batch — each result carries its own status.

curl -X POST https://api.meowtrace.com/v1/lookup \
     -H "x-api-key: mt_live_…" \
     -H "content-type: application/json" \
     -d '{"ips": ["1.2.3.4", "8.8.8.8", "bad.ip"]}'

200 when all resolve; 207 Multi-Status when any entry is not-found, invalid, or unbillable:

{
  "count": 3,
  "partial": true,
  "credits_charged": 1,
  "results": [
    { "status": "found", "result": { "ip": "1.2.3.4", "country": { "code": "PL", "name": "Poland" }, "region": "Mazowieckie", "city": "Warsaw" } },
    { "ip": "8.8.8.8", "status": "not_found" },
    { "ip": "bad.ip", "status": "invalid" }
  ]
}

Per-IP status: found, not_found, invalid, or insufficient_credit. The batch is processed until credits are exhausted; the remainder are marked insufficient_credit.

API keys

Manage keys with a bearer session token. Keys are hashed at rest and the raw secret is shown only once.

POST /v1/keys  ·  GET /v1/keys  ·  DELETE /v1/keys/:id
EndpointBody / Result
POST /v1/keys{ "label"? }{ id, key, prefix, warning }key shown once
GET /v1/keys{ keys: [{ id, key_prefix, label, created_at, revoked_at }] }
DELETE /v1/keys/:id{ revoked: true, id }

Credits & tiers

1 credit = 1 lookup. Balance is hard-capped — when it hits zero, lookups return 429 until the next refill/reset.

TierPriceCreditsReset
Free$010 / dayDaily, 00:00 GMT+8 (no rollover)
Hobby$14.90/mo200,000 / moMonthly (no rollover)
Enterprise$250/moUnlimitedFair-usage policy

Billing

Subscriptions and invoicing run through Stripe. From the portal:

POST /v1/billing/checkout  ·  POST /v1/billing/portal

checkout (body { "tier": "hobby" | "enterprise" }) returns a hosted Stripe Checkout URL. portal returns a Stripe Customer Portal URL for self-serve payment methods and invoices. A successful payment provisions your tier's credits automatically.