{"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. Depth 1 is public; depth 2 requires a signed-in key; depth 3 requires Pro or above.","security":[{"bearerAuth":[]},{"apiKeyAuth":[]}],"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"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeolocateResponse"}}}},"400":{"description":"Malformed JSON or missing image_url / image_b64.","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"}}}},"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/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"},"location":{"type":"object","properties":{"latitude":{"type":"number"},"longitude":{"type":"number"},"country":{"type":"string"},"city":{"type":"string"},"address":{"type":"string"}}},"confidence":{"type":"number"},"reasoning":{"type":"string"},"depth":{"type":"integer"},"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"}}