{"openapi":"3.1.0","info":{"title":"Oceanir API","version":"1.0.0","summary":"Visual geolocation and evidence verification API.","description":"Turn an image URL or raw base64 payload into ranked location candidates, confidence, and visual evidence. JSON in, JSON out. Errors use a typed ApiError object (code, message, hint, docs) that also carries RFC 9457 problem fields (type, title, status, detail) and may be served as application/problem+json. Rate limits are advertised on every response via RateLimit and X-RateLimit-* headers. REST is a keyed developer integration — agents should use MCP at https://mcp.oceanir.ai (OAuth for tools/call), which calls this API on the server.","contact":{"name":"Oceanir developer resources","url":"https://oceanir.ai/developers","email":"team@oceanir.ai"},"license":{"name":"Proprietary"}},"servers":[{"url":"https://oceanir.ai","description":"Production"}],"security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"tags":[{"name":"Geolocation","description":"Pixel-only image geolocation."},{"name":"Account","description":"Credits, usage, and history."},{"name":"Cases","description":"Multi-image investigations."},{"name":"Discovery","description":"Machine-readable docs."}],"paths":{"/api/v1/geolocate":{"post":{"operationId":"geolocateImage","tags":["Geolocation"],"summary":"Geolocate an image","description":"Analyze an image URL or base64 payload and return ranked location evidence. Send JSON, never multipart. image_b64 must be raw base64 with no data: prefix. All REST calls require an API key and sufficient credits. Reusing an Idempotency-Key with the identical request replays the completed response without another model call or credit debit.\n\nVERIFYING A CLAIM. Pass `scope` ({name, lat, lng, radius_km — default 60}) to test a location you already believe: a listing's stated city, an address on a case file, a caption. Oceanir locates the image from visual evidence FIRST and only then compares, so the scope narrows the search and can never raise confidence — and the model will reject it outright on hard image-legible contradiction (signage in an impossible script, the wrong driving side, a landmark that is elsewhere). The response then carries `scope` (distance_km, within_scope) and `claim.verdict`, one of `agrees`, `contradicts`, or `unverifiable`. Branch on `claim.verdict` rather than thresholding distance_km yourself. `unverifiable` means the image does not settle it and the item needs a human — it is a real answer, not a failure — and `agrees` means the image is consistent with the claim, not that the claim is true.\n\nCHECKING THE LIGHT. Add `scope.captured_at` when the claim carries a date. It is the only evidence in the response that does not come from the model, and so the only one that can contradict it: given a place and a time, the sun was above the horizon or it was not. A bare date (`2026-09-12`) returns `claim.daylight.solar_day` — sunrise, sunset, how many minutes of daylight there were, and `polar_night` / `midnight_sun`. A daylit image claimed at a place and date where `polar_night` is true is contradicted by astronomy, whatever the confidence says. A time WITH a UTC offset (`2026-09-12T14:30:00-04:00`) additionally returns `claim.daylight.at_capture` with the sun's altitude, compass direction, and `conflicts_with_daylit_image`. A time WITHOUT an offset has its clock time IGNORED and only its date used — `at_capture` comes back null and `time_note` explains why. An assumed timezone can turn noon into midnight, so it is never guessed.\n\nPass `batch_id` from POST /api/v1/batches to group a queue of images under one set of progress counters.\n\nPRODUCT BOUNDARY. Oceanir reads the scene — architecture, signage, terrain, vegetation — and never the people in it. There is no face recognition, no biometric identification and no person matching at any depth. It answers where an image was taken, never who is in it. The SaaS agreement prohibits combining Output with people-search or identity resolution in any workflow whose purpose or effect is to determine the whereabouts of a natural person.","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":256},"description":"Unique identifier for one logical request. Reuse only when retrying the identical payload."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeolocateRequest"}}}},"responses":{"200":{"description":"Successful geolocation analysis.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}},"Idempotent-Replayed":{"description":"true when this body was replayed from a completed request.","schema":{"type":"string","enum":["true"]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeolocateResponse"},"example":{"success":true,"analysis_id":"example-analysis-id","location":{"latitude":45.77,"longitude":4.8459,"country":"France","city":"Lyon","neighborhood":"6th arrondissement","address":"Lyon, France"},"confidence":0.79,"reasoning":"Street signage and architecture suggest Lyon. Confirm the area with independent evidence.","visual_clues":[{"label":"French street signage","detail":""},{"label":"Stone facades","detail":""}],"model":"orca-1.5","depth":2,"timing_ms":9120}}}},"400":{"description":"Malformed JSON request body.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Missing or invalid API key.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Insufficient credits.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Key is not allowed to call this endpoint.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"No such endpoint.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"405":{"description":"Method not allowed. Use POST.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Idempotency key is in progress or was reused with a different payload.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"Invalid request payload.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal error.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"503":{"description":"Analysis service unavailable.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"default":{"description":"Typed error. Read code, message, and RFC 9457 type/title/status/detail.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/batches":{"post":{"operationId":"createBatch","tags":["Batches"],"summary":"Create a batch","description":"Open a named batch bound to the calling API key, then pass its id as `batch_id` on each /api/v1/geolocate call to group a queue of images. Creating and holding a batch is free — billing happens per analysis exactly as it does for an unbatched request. The batch tracks progress; it does not store results, which keeps it usable by accounts contractually configured not to retain analyses.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","maxLength":80,"description":"A label you will recognise later, e.g. a case or run reference."}}}}}},"responses":{"201":{"description":"Batch created."},"401":{"description":"Missing or invalid API key.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"`name` is required.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"default":{"description":"Typed error.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"get":{"operationId":"listBatches","tags":["Batches"],"summary":"List batches","description":"List batches belonging to the calling key, newest first. Paginate with `limit` and `before` (pass the previous page's `next_before`). Scoped to the key rather than the account, matching what submission accepts.","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"before","in":"query","schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"A page of batches."},"401":{"description":"Missing or invalid API key.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"default":{"description":"Typed error.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/batches/{id}":{"get":{"operationId":"getBatch","tags":["Batches"],"summary":"Read a batch","description":"Poll a batch's progress: request_count against completed_count and failed_count, plus the aggregate status.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The batch."},"401":{"description":"Missing or invalid API key.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"No such batch for this key.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"default":{"description":"Typed error.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"delete":{"operationId":"cancelBatch","tags":["Batches"],"summary":"Cancel a batch","description":"Stop accepting new submissions. Analyses already in flight run to completion — cancelling them would bill for inference whose result you never receive.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The cancelled batch."},"401":{"description":"Missing or invalid API key.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"No such batch for this key.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"default":{"description":"Typed error.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/credits":{"get":{"operationId":"getCredits","tags":["Account"],"summary":"Read credit balance","description":"Return the authenticated account's remaining credits, API credit pool, and usage totals.","responses":{"200":{"description":"Credit snapshot.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditsResponse"}}}},"401":{"description":"Missing or invalid API key.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/usage":{"get":{"operationId":"getUsage","tags":["Account"],"summary":"Read API usage","description":"Return meter status, overage mode, and access lifecycle for the authenticated account.","responses":{"200":{"description":"Usage snapshot.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageResponse"}}}},"401":{"description":"Missing or invalid API key.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/analyses":{"get":{"operationId":"listAnalyses","tags":["Account"],"summary":"List analyses","description":"List geolocation analyses for the authenticated principal. Filter with q, city, and limit.","parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string"},"description":"Search neighborhood, city, or filename."},{"name":"city","in":"query","required":false,"schema":{"type":"string"},"description":"Restrict to a city slug."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50}}],"responses":{"200":{"description":"Analysis list.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalysesResponse"}}}},"401":{"description":"Missing or invalid API key.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/cases":{"get":{"operationId":"listCases","tags":["Cases"],"summary":"List cases","description":"List investigation cases for the authenticated principal.","parameters":[{"name":"teamId","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50}}],"responses":{"200":{"description":"Case list.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CasesResponse"}}}},"401":{"description":"Missing or invalid API key.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"post":{"operationId":"createCase","tags":["Cases"],"summary":"Create a case","description":"Create an investigation case for grouping analyses.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"teamId":{"type":"string"}}}}}},"responses":{"200":{"description":"Created case.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Case"}}}},"401":{"description":"Missing or invalid API key.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"402":{"description":"Plan does not include cases.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"Rate limit exceeded.","headers":{"RateLimit":{"description":"RFC 9331 quota snapshot, e.g. \"ip\";r=40;t=12","schema":{"type":"string"}},"RateLimit-Policy":{"description":"RFC 9331 policy, e.g. \"ip\";q=50;w=60","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Legacy limit for the current window.","schema":{"type":"string"}},"X-RateLimit-Remaining":{"description":"Legacy remaining requests in the current window.","schema":{"type":"string"}},"X-RateLimit-Reset":{"description":"Legacy UNIX timestamp when the window resets.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"IETF draft-polli window limit.","schema":{"type":"string"}},"RateLimit-Remaining":{"description":"IETF draft-polli remaining requests.","schema":{"type":"string"}},"RateLimit-Reset":{"description":"IETF draft-polli reset UNIX timestamp.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait after a 429.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}},"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/docs":{"get":{"operationId":"getApiDocs","tags":["Discovery"],"summary":"Read API documentation","security":[],"responses":{"200":{"description":"HTML API documentation.","content":{"text/html":{"schema":{"type":"string"}}}}}}}},"components":{"schemas":{"ApiError":{"type":"object","required":["success","error","code","message","docs","type","title","status","detail"],"properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"code":{"type":"string","enum":["not_found","method_not_allowed","unauthorized","forbidden","payment_required","rate_limited","invalid_request","invalid_image_b64","server_error"]},"message":{"type":"string"},"hint":{"type":"string"},"details":{"type":"object","additionalProperties":true},"docs":{"type":"string","format":"uri"},"type":{"type":"string","format":"uri","description":"RFC 9457 problem type URI, e.g. https://oceanir.ai/docs/authentication/errors#unauthorized"},"title":{"type":"string","description":"Short RFC 9457 problem title."},"status":{"type":"integer","description":"HTTP status code."},"detail":{"type":"string","description":"Human-readable RFC 9457 problem detail."},"instance":{"type":"string","description":"Optional occurrence URI."}}},"Error":{"type":"object","required":["success","error","code","message","docs","type","title","status","detail"],"properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"code":{"type":"string","enum":["not_found","method_not_allowed","unauthorized","forbidden","payment_required","rate_limited","invalid_request","invalid_image_b64","server_error"]},"message":{"type":"string"},"hint":{"type":"string"},"details":{"type":"object","additionalProperties":true},"docs":{"type":"string","format":"uri"},"type":{"type":"string","format":"uri","description":"RFC 9457 problem type URI, e.g. https://oceanir.ai/docs/authentication/errors#unauthorized"},"title":{"type":"string","description":"Short RFC 9457 problem title."},"status":{"type":"integer","description":"HTTP status code."},"detail":{"type":"string","description":"Human-readable RFC 9457 problem detail."},"instance":{"type":"string","description":"Optional occurrence URI."}}},"Problem":{"type":"object","required":["type","title","status","detail"],"properties":{"type":{"type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"instance":{"type":"string"},"code":{"type":"string"},"docs":{"type":"string","format":"uri"}}},"GeolocateRequest":{"type":"object","properties":{"image_url":{"type":"string","format":"uri","description":"Public HTTPS image URL to analyze."},"image_b64":{"type":"string","description":"Raw base64 image payload. No data: prefix."},"depth":{"type":"integer","enum":[1,2,3],"default":1,"description":"1 Surface, 2 Standard, 3 Forensic."}},"anyOf":[{"required":["image_url"]},{"required":["image_b64"]}]},"GeolocateResponse":{"type":"object","properties":{"success":{"type":"boolean"},"analysis_id":{"type":["string","null"],"description":"Saved analysis identifier; null when no history row is retained."},"location":{"type":"object","properties":{"latitude":{"type":"number"},"longitude":{"type":"number"},"country":{"type":"string"},"city":{"type":"string"},"neighborhood":{"type":"string"},"address":{"type":"string"},"map_url":{"type":"string","format":"uri"}}},"confidence":{"type":"number","minimum":0,"maximum":1},"reasoning":{"type":"string"},"thinking":{"type":"string","description":"Optional analysis explanation at depth 2 or 3."},"visual_clues":{"type":"array","description":"Depth 2 or 3; detail may be empty.","items":{"type":"object","properties":{"label":{"type":"string"},"detail":{"type":"string"},"x":{"type":"number"},"y":{"type":"number"},"contours":{"type":"array","items":{}}}}},"forensic":{"type":"object","description":"Optional depth-3 evidence, candidates, and verification status.","additionalProperties":true},"calibration":{"type":"object","description":"Optional depth-3 publication and abstention policy.","additionalProperties":true},"model":{"type":"string","enum":["orca-1.5"]},"depth":{"type":"integer","enum":[1,2,3]},"timing_ms":{"type":"integer"}}},"CreditsResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"balance":{"type":"number"},"api_balance":{"type":"number"},"total_available":{"type":"number"},"total_purchased":{"type":["number","null"]},"total_used":{"type":["number","null"]}}}}},"UsageResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","additionalProperties":true}}},"AnalysesResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object"}}}},"Case":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}}},"CasesResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Case"}}}}},"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Oceanir API key as `Authorization: Bearer <key>`. Equivalent to apiKeyAuth. UI keys look like oceanir_<hex>_<ts>; partner keys may look like orc_<hex>."},"apiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"Oceanir API key as `x-api-key: <key>`. Equivalent to bearerAuth; both are accepted on every endpoint."},"oauth2":{"type":"oauth2","description":"OAuth 2.0 authorization code flow. Used by MCP clients (Claude Code, Claude Desktop, Cursor). Discovery: /.well-known/oauth-authorization-server","flows":{"authorizationCode":{"authorizationUrl":"https://oceanir.ai/api/auth/oauth2/authorize","tokenUrl":"https://oceanir.ai/api/auth/oauth2/token","refreshUrl":"https://oceanir.ai/api/auth/oauth2/token","scopes":{"mcp:tools":"Call Oceanir tools over the MCP endpoint.","openid":"Authenticate the end user.","profile":"Read basic profile information.","email":"Read the account email address.","offline_access":"Obtain a refresh token for long-running agents."}}}}}},"x-api-key-roles":{"description":"An API key inherits the capability tier of the account that owns it. Depth 3 and batch endpoints require pro or above.","roles":[{"name":"free","grants":["geolocate:d1"]},{"name":"starter","grants":["geolocate:d1","geolocate:d2"]},{"name":"pro","grants":["geolocate:d1","geolocate:d2","geolocate:d3","cases:read","cases:write"]},{"name":"enterprise","grants":["geolocate:d1","geolocate:d2","geolocate:d3","cases:read","cases:write","batch:submit"]}]},"x-rate-limit":{"description":"Every /api response includes RFC 9331 RateLimit / RateLimit-Policy headers plus X-RateLimit-*. 429 responses also send Retry-After. Documented key tiers: free 5/min, pro 30/min, enterprise 120/min.","headers":["RateLimit","RateLimit-Policy","RateLimit-Limit","RateLimit-Remaining","RateLimit-Reset","X-RateLimit-Limit","X-RateLimit-Remaining","X-RateLimit-Reset","Retry-After"]},"externalDocs":{"description":"Oceanir developer resources","url":"https://oceanir.ai/developers"}}