API
Overview
The GeoRedirect.io API resolves the best destination URL for a visitor based on geo context (country, region, ASN, CIDR, etc.). Make a single POST to receive a decision in ~20ms median.
- Base URL
https://api.georedirect.io - Version
v1 - Format
application/json
Authentication
Use a Bearer token in the Authorization header.
Authorization: Bearer <API_KEY>
Rotate keys regularly. Keep them secret; do not embed in public clients.
POST /v1/resolve
Resolve the destination URL for a visitor using IP and rules. If multiple rules match, the first match wins.
Request Body
{
"ip": "203.0.113.50",
"user_agent": "optional user agent string",
"rules": [
{ "if": { "country": "US" }, "to": "https://example.com/us" },
{ "if": { "country": "DE" }, "to": "https://example.com/de" },
{ "else": "https://example.com/global" }
],
"metadata": { "sessionId": "abc123" }
}
Response
{
"to": "https://example.com/us",
"matched": { "country": "US" },
"latency_ms": 18,
"trace_id": "trc_7QyZb2"
}
curl -X POST https://api.georedirect.io/v1/resolve \
-H "Authorization: Bearer <API_KEY>" \
-H "Content-Type: application/json" \
-d '{
"ip": "203.0.113.50",
"rules": [
{"if": {"country": "US"}, "to": "https://example.com/us"},
{"if": {"country": "DE"}, "to": "https://example.com/de"},
{"else": "https://example.com/global"}
]
}'
$ch = curl_init("https://api.georedirect.io/v1/resolve");
curl_setopt_array($ch, [
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <API_KEY>",
"Content-Type: application/json"
],
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POSTFIELDS => json_encode([
"ip" => "203.0.113.50",
"rules" => [
["if" => ["country" => "US"], "to" => "https://example.com/us"],
["if" => ["country" => "DE"], "to" => "https://example.com/de"],
["else" => "https://example.com/global"]
]
])
]);
$res = curl_exec($ch);
const res = await fetch("https://api.georedirect.io/v1/resolve", {
method: "POST",
headers: {
"Authorization": "Bearer <API_KEY>",
"Content-Type": "application/json"
},
body: JSON.stringify({
ip: "203.0.113.50",
rules: [
{ if: { country: "US" }, to: "https://example.com/us" },
{ if: { country: "DE" }, to: "https://example.com/de" },
{ else: "https://example.com/global" }
]
})
});
const data = await res.json();
GET /v1/health
Public health check for monitoring.
GET https://api.georedirect.io/v1/health
200 OK
{ "status": "ok", "uptime": 123456 }
GET /v1/ipinfo
Return geo context for an IP (country, region, ASN).
GET https://api.georedirect.io/v1/ipinfo?ip=203.0.113.50
Authorization: Bearer <API_KEY>
200 OK
{
"ip": "203.0.113.50",
"country": "US",
"region": "CA",
"asn": 15169
}
Errors
| Status | Code | Message |
|---|---|---|
| 400 | bad_request |
Your payload is invalid or incomplete. |
| 401 | unauthorized |
Missing or invalid API key. |
| 403 | forbidden |
Key lacks permission for this endpoint. |
| 404 | not_found |
Resource not found. |
| 429 | rate_limited |
Too many requests. See rate limits. |
| 500 | server_error |
Unexpected error. Try again. |
Error schema
{
"error": {
"status": 401,
"code": "unauthorized",
"message": "Missing or invalid API key",
"trace_id": "trc_7QyZb2"
}
}
Rate limits
Requests per month by plan. Bursting is allowed within reason; sustained abuse triggers 429.
| Plan | Included | Overage |
|---|---|---|
| Free | 500 / mo | Not available |
| Starter | 10k / mo | Contact support |
| Pro | 50k / mo | Contact support |
| Scale | Custom | Contract |
SDKs
Official SDKs (coming soon): PHP, Node.js, Python.
- PHP
- Node.js
- Python
Webhooks
Configure webhooks to receive decision events and analytics asynchronously. We sign webhook payloads; verify signatures on your side.
{
"event": "resolve.completed",
"to": "https://example.com/us",
"matched": { "country": "US" },
"latency_ms": 18,
"trace_id": "trc_7QyZb2",
"delivered_at": "2025-08-13T10:12:33Z",
"signature": "v1=hex..."
}