Private API
This API is for external partner platforms. The website itself must use React
Router loaders/actions and shared server functions directly, not /api/v1.
This API is currently subject to breaking changes. Treat this documentation as the source of truth; we keep it updated as the project and API contract evolve.
Base URL
https://venezuelatebusca.com/api/v1
Authentication
Every /api/v1 request requires an API key:
Authorization: Bearer <api_key>
API keys are stored as hashes in D1. A key has a source, and that source is
used automatically for person provenance. Clients may send source_id and
source_notes, but cannot send or override source.
Source handles:
form
hospital_list
persons_list
pacientes_terremoto_venezuela
sos_venezuela_2026
laguaira_hsiciliano
The API documentation only shows the read-oriented surface. Write endpoints
remain available for approved partners with explicit permissions and are
documented in the private OpenAPI reference.
API keys can have explicit permissions:
persons:read
persons:write
tips:read
tips:write
reports:read
reports:write
resources:read
resources:write
New keys default to read-only access:
persons:read
tips:read
reports:read
resources:read
Disabled keys or missing permissions return 403. Missing or invalid keys
return 401.
Rate Limits
Cloudflare Workers Rate Limiting protects the API:
- Partner API:
120requests per minute per API key. - Auth failures and anonymous attempts:
20requests per minute per IP.
Rate-limited responses return 429 and include Retry-After.
Responses
Successful non-delete responses always return data.
Single resource:
{
"data": {
"id": "person_123",
"first_name": "Ana"
}
}
List resource:
{
"data": [],
"pagination": {
"next_cursor": null,
"previous_cursor": null,
"limit": 50
}
}
General errors:
{
"error": "Person not found."
}
Validation errors:
{
"errors": {
"first_name": ["First name is required."]
}
}
Pagination
List endpoints use cursor pagination.
limitdefaults to50.limitis capped at100.- Use
cursorexactly as returned. - Do not parse or edit cursors.
- No
page,offset, ortotal_count.
GET /api/v1/persons?limit=100
GET /api/v1/persons?limit=100&cursor=<opaque_cursor>
When next_cursor is null, there is no next page. When
previous_cursor is null, there is no previous page.
Endpoints
GET /api/v1/metrics
requires persons:read
GET /api/v1/persons
requires persons:read
GET /api/v1/persons/:person_id
requires persons:read
GET /api/v1/persons/:person_id/tips
requires tips:read
GET /api/v1/persons/:person_id/tips/:tip_id
requires tips:read
GET /api/v1/persons/:person_id/reports
requires reports:read
GET /api/v1/persons/:person_id/reports/:report_id
requires reports:read
GET /api/v1/resources
requires resources:read
GET /api/v1/resources/:resource_id
requires resources:read
Persons
List filters use stable handles:
GET /api/v1/persons?source=persons_list
GET /api/v1/persons?hospital=miguel_perez_carreno
GET /api/v1/persons?hospital_status=admitted
GET /api/v1/persons?gender=female
Person responses enrich controlled values as { "handle": "...", "label": "..." }.
Every person response includes sources as flat resource objects and tips as
plain tip objects.
Tips
Tips are scoped by person_id. A tip_id that belongs to a different person
returns 404.
Reports
Report reasons:
duplicate
inappropriate
incorrect_info
already_found
other
Reports are scoped by person_id. A report_id that belongs to a different
person returns 404.
Metrics
GET /api/v1/metrics
{
"data": {
"total": 123,
"missing": 100,
"found": 23
}
}
Status Codes
400 Bad request or invalid JSON
401 Missing or invalid API key
403 Disabled API key, missing permission, or forbidden source ownership
404 Resource not found
405 Unsupported method
409 Conflict, such as national ID uniqueness
415 Unsupported content type
422 Validation error
429 Rate limited
500 Unexpected server error