API reference
Programmatic access to Uruguayan customs declarations. Base URL https://uytrades.com/api/v1. Responses are application/json; dates are ISO 8601.
Authentication
Send a personal access token in the Authorization: Bearer <token> header. Tokens are created at /account. The plaintext value is returned once, at creation, and cannot be retrieved afterwards.
curl -H "Authorization: Bearer uytr_a1b2c3d4_xxxxxxxxxxxx" \
"https://uytrades.com/api/v1/me"
A token inherits the plan of the account that created it. If the subscription lapses, Pro endpoints return 402 for that token; no revocation is needed.
Session cookie authentication is also accepted, so endpoints can be opened directly in a signed-in browser. Use a token for non-interactive clients.
Rate limits
Limits apply per account, across all of its tokens. Creating additional tokens does not raise them.
Both windows apply simultaneously. The two endpoint groups are metered independently: exhausting one does not affect the other.
Responses from these endpoints carry:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 47
X-RateLimit-Reset: 1755792000
X-RateLimit-Limit-Minute: 20
X-RateLimit-Remaining-Minute: 19
Exceeding either window returns 429. Retry-After is the number of seconds until that window resets.
HTTP/1.1 429 Too Many Requests
Retry-After: 412
{
"error": {
"code": "rate_limited",
"message": "60 requests/hour exceeded.",
"limit": 60,
"window": "hour",
"reset": 1755792000
}
}
Endpoints
GET /api/v1/me
Returns the authenticated account's id, email, plan and expiry.
curl -H "Authorization: Bearer $TOKEN" "https://uytrades.com/api/v1/me"
{"id": 42, "email": "you@example.com", "tier": "pro",
"is_pro": true, "pro_until": "2027-01-14T00:00:00+00:00"}
GET /api/v1/dua/meta
Filter options, row caps and column names. Requires no authentication.
curl "https://uytrades.com/api/v1/dua/meta"
{"row_limit_max": 10000, "default_limit": 100,
"regimens": ["ALL", "EXPORT", "IMPORT", "TRANSIT"],
"columns": ["anio", "fecha_dua", "aduana_ing_egr", ...],
"requires_pro": true, "is_pro": false}
GET /api/v1/dua
Returns declaration rows matching the filters, ordered by fecha_dua DESC, nro_publico. Requires Pro.
curl -H "Authorization: Bearer $TOKEN" \
"https://uytrades.com/api/v1/dua?year=2026®imen=IMPORT&limit=100"
{"data": [{"anio": 2026, "fecha_dua": "2026-03-04", "nombre": "ACME SA", ...}],
"pagination": {"limit": 100, "offset": 0, "returned": 100, "has_more": true},
"query": {"year": 2026, "aduana": null, "regimen": "IMPORT", "search": null},
"meta": {"elapsed_ms": 84.2}}
has_more is false on the last page, including when the total is an exact multiple of limit. Offsets are stable within a page sequence as long as the filters do not change.
GET /api/v1/dua/summary
Aggregates the same filter set without returning rows: total count, total customs value in USD, the ten customs offices with the highest value, and a count per régimen. Requires Pro.
curl -H "Authorization: Bearer $TOKEN" \
"https://uytrades.com/api/v1/dua/summary?year=2026®imen=IMPORT"
{"row_count": 148230, "total_usd": 2841993022.14,
"by_aduana": [{"aduana": "001", "rows": 91204, "usd": 1922841003.5}],
"by_regimen": [{"regimen_tipo": "I", "rows": 148230}],
"query": {"year": 2026, "aduana": null, "regimen": "IMPORT", "search": null}}
GET
POST
DELETE
/api/v1/keys
Lists, creates and revokes tokens for the authenticated account. POST returns the plaintext token in the response body; it is not retrievable later. Creating requires Pro.
curl -X POST -H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"name": "nightly-etl"}' \
"https://uytrades.com/api/v1/keys"
{"id": 7, "name": "nightly-etl", "prefix": "a1b2c3d4",
"created_at": "2026-08-21T16:04:11+00:00", "last_used_at": null,
"token": "uytr_a1b2c3d4_xxxxxxxxxxxx"}
curl -X DELETE -H "Authorization: Bearer $TOKEN" \
"https://uytrades.com/api/v1/keys/7"
Maximum 20 active tokens per account. Revoke one before creating another.
Errors
Every error uses the same envelope. code is stable and safe to branch on; status repeats the HTTP status. Some errors add fields, such as upgrade_url on 402 and reset on 429.
{"error": {"code": "unauthorized", "status": 401, "message": "Authentication required. ..."}}
Authentication failures return 401 with a JSON body and a WWW-Authenticate: Bearer header. No endpoint under /api/v1 responds with a redirect, so clients may follow redirects safely without masking an auth error.
Bulk downloads
This API is designed for scoped queries. At 60 requests per hour and 10,000 rows per request, retrieving a full year of declarations is impractical.
Use the CSV export at /app/export instead. It accepts the same Bearer token and streams up to 1,000,000 rows in a single request.
curl -H "Authorization: Bearer $TOKEN" \
"https://uytrades.com/app/export?year=2026®imen=IMPORT&search=ACME" \
-o acme-2026.csv
What is stable
The endpoints on this page are stable. Response fields will not be removed or change type without notice.
Every other path under /api/v1 serves the web application or is in beta. Those are unversioned and may change or be withdrawn without notice:
/api/v1/alerts
/api/v1/watches
/api/v1/views
/api/v1/export-schedules
They accept the same authentication but are not covered by the guarantee above.
Beta
GET /api/v1/stories/candidate recomputes a single story candidate for the video pipeline's reconciliation step. It requires Pro, counts against the expensive budget, and returns application/json. Its response follows the story formats and may change without notice.
Parameters: format, period (year:YYYY or ytd:YYYY), the format's own parameters, and optionally through (an ISO 8601 date) and page_size. An unknown parameter returns 400.
curl -H "Authorization: Bearer $TOKEN" \
"https://uytrades.com/api/v1/stories/candidate?format=A&period=year:2025&ncm=4011®imen=I&page_size=10"