Geotagr / Docs
Geotagr API
Write GPS and SEO metadata into JPEGs from your own software. The API is part of the Business plan. Photos are processed in memory and are never stored. A machine-readable OpenAPI 3.1 description is available.
Authentication
Create a key under Account, API. It is shown once; store it like a password. Send it on every request:
curl https://geotagr.com/api/v1/usage \
-H "Authorization: Bearer pp_live_YOUR_KEY"Keys can be revoked at any time and stop working immediately. Never put a key in browser code.
POST /api/v1/geotag
Upload one JPEG as multipart/form-data and receive the tagged JPEG. Parts: file (the photo, required), fields (JSON, optional) and options (JSON, optional). The file is checked by its content, not its name; only JPEG is accepted (default limit 25 MB). It counts as one photo on your plan.
curl https://geotagr.com/api/v1/geotag \
-H "Authorization: Bearer pp_live_YOUR_KEY" \
-F "[email protected];type=image/jpeg" \
-F 'fields={"lat":"24.8607343","lon":"67.0011364","title":"Plumber in Saddar","kw":"plumber, karachi","biz":"Acme Plumbing"}' \
-o tagged.jpgfields uses the same keys as the editor: lat, lon, alt, dir, acc, title, subject, desc, kw, biz, phone, web, addr, city, state, country, cc, artist, copy, doc, comment, date, rating. Values may be strings or numbers. date is YYYY-MM-DDTHH:MM:SS; kw is comma separated.
options: keywordSeparator, xmp (default true), strip (drop existing metadata) and clearGps. The response carries X-GPS-Verified (the written coordinates were read back) and X-Quota-Remaining.
POST /api/v1/suggest
AI title, subject, description and keywords for a photo. Send a downscaled JPEG (about 768 px on the long edge, under 1 MB) as a data URL, plus optional context. Counts as one AI suggestion.
curl https://geotagr.com/api/v1/suggest \
-H "Authorization: Bearer pp_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"image":"data:image/jpeg;base64,/9j/4AAQ...","context":{"business":"Acme Plumbing","city":"Karachi"}}'{ "title": "...", "subject": "...", "desc": "...", "kw": "a, b, c", "filename": "..." }GET /api/v1/usage
What is left on each meter. For team workspaces these are the pooled numbers.
curl https://geotagr.com/api/v1/usage -H "Authorization: Bearer pp_live_YOUR_KEY"Rate limits and quota
Every key has a per-minute rate limit (60 by default). Responses include X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (seconds). When exceeded you get 429 rate_limited with a Retry-After header. Separately, photos and AI suggestions count against your plan's monthly quota (429 limit_reached, with resetsAt).
Errors
Every error has the same JSON shape; branch on error.code.
{ "error": { "code": "limit_reached", "message": "You have used all your photos on the Business plan.", "resetsAt": "2026-11-01T00:00:00.000Z" } }| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | Missing, malformed or revoked API key. |
| 403 | plan_required | The key owner's plan does not include API access. |
| 403 | feature_locked | The plan does not include this feature (for example AI). |
| 403 | account_unavailable | The key owner's account is suspended or deleted. |
| 400 | invalid_request | Body or fields failed validation. `issues` lists each problem. |
| 422 | invalid_coordinates | lat/lon are out of range. |
| 422 | invalid_image | The JPEG is truncated or corrupt. |
| 413 | payload_too_large | The upload exceeds the size limit (`maxBytes`). |
| 415 | unsupported_media_type | The upload is not a JPEG (checked by content, not file name). |
| 429 | limit_reached | The plan's monthly quota for this meter is used up. `resetsAt` says when it renews. |
| 429 | rate_limited | Per-key rate limit exceeded. Wait `Retry-After` seconds. |
| 502 | upstream_error | The AI provider failed. Nothing was charged. |
| 503 | not_configured | AI is not configured on this server. |
| 500 | verification_failed | The tagged file did not read back correctly, so it was not returned and not counted. |
| 500 | server_error | Unexpected failure. Safe to retry. |