ASDAC API Documentation
The ASDAC Public API exposes traveler declaration data, aggregate statistics, and reference lookups so partners and integrators can build on top of the American Samoa Declaration & Customs platform.
Base URL
/api/v1All responses are JSON. Successful responses are wrapped in a top-level data field; list responses additionally include a pagination object.
Quick Start
- Obtain an API token from your administrator (admin dashboard → API Tokens).
- Send the token as a Bearer credential in the
Authorizationheader. - Make requests against any endpoint your token has permission for. Reference and health endpoints are public.
curl -X GET "/api/v1/health"Authentication
Protected endpoints require a Bearer token in the Authorization header. Tokens are issued by an administrator from the admin dashboard and are shown in full only once at creation time — store yours immediately.
Authorization Header Format
Authorization: Bearer <your-api-token>Tokens are SHA-256 hashed at rest. Each token has a status of active, expired, or revoked; only active tokens authenticate.
curl -X GET "/api/v1/declarations" \
-H "Authorization: Bearer your_api_token_here"Token Permissions
Each token is granted one or more permission scopes. A request is rejected with 403 FORBIDDEN if the token does not include the scope required by the endpoint.
| Permission | Grants Access To |
|---|---|
read:declarations | GET /api/v1/declarations and GET /api/v1/declarations/:id |
read:statistics | GET /api/v1/statistics |
read:reference | Reserved for future use. Reference and health endpoints are currently public and do not check this scope. |
Rate Limiting
Every endpoint is rate-limited. Authenticated requests are counted per token; unauthenticated requests (e.g. health, reference) are counted per client IP. The default is 100 requests per 60 seconds; administrators can adjust both the limit and the window from the admin dashboard.
Response Headers
Every response — successful or rate-limited — includes the current rate-limit state:
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed in the current window. |
X-RateLimit-Remaining | Requests still available in the current window (never negative). |
X-RateLimit-Reset | Unix timestamp (seconds) when the current window ends and the counter resets. |
Retry-After | Sent only on 429 responses. Number of seconds the client should wait before retrying. |
Rate Limit Exceeded
When the limit is exceeded, the API returns 429 Too Many Requests with the RATE_LIMITED error code and the Retry-After header populated.
Endpoints
Health Check
/api/v1/healthLiveness probe. Public — no token required. Useful for uptime monitoring.
Response Example
{
"data": {
"status": "ok",
"service": "travelpass-api",
"version": "v1",
"time": "2026-04-28T04:29:49Z"
}
}Error Responses
Declarations
/api/v1/declarationsRequires AuthPaginated list of traveler declarations. By default returns only submitted declarations, ordered by submission time descending.
read:declarationsParameters
| Name | Type | Location | Description |
|---|---|---|---|
page | integer | query | Page number (default: 1) |
limit | integer | query | Items per page (default: 25, max: 100) |
status | string | query | Filter by status: draft, submitted. Omit to return submitted only. |
tripType | string | query | arriving_visitor | arriving_resident | departing | transit |
modeOfTravel | string | query | air | sea |
fromDate | date | query | Inclusive lower bound for submittedAt (ISO 8601 date or datetime). |
toDate | date | query | Inclusive upper bound for submittedAt (interpreted as end-of-day if a date-only value is given). |
Response Example
{
"data": [
{
"id": "f0ab05a1-eeb5-4792-8c20-882016e9ac9b",
"referenceCode": "AS-ZX1W8P-2024",
"status": "submitted",
"submittedAt": "2024-12-13T10:15:00Z",
"tripType": "departing",
"modeOfTravel": "air",
"personalInfo": {
"firstName": "Sione",
"middleName": "",
"lastName": "Taufa",
"passportNumber": "TO77889900",
"citizenship": "Tonga",
"dateOfBirth": "1975-12-03",
"gender": "Male"
},
"travelDetails": {
"airline": "Hawaiian Airlines",
"flightNumber": "HA463",
"departureDate": "2024-12-20"
},
"declarations": {
"agricultureItems": false,
"animals": false,
"currency": false,
"restrictedItems": false
},
"departureDetails": {
"durationOfStay": { "value": 14, "unit": "days" },
"spendingAmount": 2500,
"purposeOfVisit": "visit_friends",
"discoverySource": "word_of_mouth",
"placeOfStay": "private",
"islandsVisited": ["tutuila", "aunuu"],
"mainAppeal": "culture"
}
}
],
"pagination": {
"page": 1,
"limit": 25,
"total": 9,
"totalPages": 1
}
}Error Responses
/api/v1/declarations/{id}Requires AuthRetrieve a single declaration by either its UUID or its human-readable reference code (e.g. AS-ZX1W8P-2024).
read:declarationsParameters
| Name | Type | Location | Description |
|---|---|---|---|
id* | string | path | Declaration UUID or reference code |
Response Example
{
"data": {
"id": "f0ab05a1-eeb5-4792-8c20-882016e9ac9b",
"referenceCode": "AS-ZX1W8P-2024",
"status": "submitted",
"submittedAt": "2024-12-13T10:15:00Z",
"tripType": "departing",
"modeOfTravel": "air",
"personalInfo": { /* ... */ },
"travelDetails": { /* ... */ },
"declarations": { /* ... */ },
"departureDetails": { /* ... */ }
}
}Error Responses
Statistics
/api/v1/statisticsRequires AuthAggregate counts across all submitted declarations: totals, breakdowns by trip type and mode of travel, plus the last-7-days submission count.
read:statisticsResponse Example
{
"data": {
"total": 9,
"byTripType": {
"arriving_visitor": 4,
"arriving_resident": 2,
"departing": 2,
"transit": 1
},
"byMode": {
"air": 8,
"sea": 1
},
"last7Days": 3
}
}Error Responses
Reference Data
Reference endpoints expose the lookup vocabularies used elsewhere in the API (trip types, modes of travel, islands, etc.). They are public — no token required — but are still subject to rate limiting and the global API on/off switch.
/api/v1/referenceList every reference type with a short description and the number of values it contains.
Response Example
{
"data": [
{ "type": "trip_types", "description": "Trip type options", "count": 4 },
{ "type": "modes_of_travel", "description": "Mode of travel options", "count": 2 },
{ "type": "islands", "description": "Islands of American Samoa", "count": 7 },
{ "type": "discovery_sources", "description": "How visitors discovered American Samoa", "count": 6 },
{ "type": "departure_purpose_of_visit", "description": "Departure purpose of visit options", "count": 8 },
{ "type": "place_of_stay", "description": "Accommodation options", "count": 2 },
{ "type": "main_appeal", "description": "Main appeal factors for visitors", "count": 4 }
]
}Error Responses
/api/v1/reference/{type}Retrieve the values for a specific reference type. Each value is an object with id (machine-readable code) and label (human-readable name).
Parameters
| Name | Type | Location | Description |
|---|---|---|---|
type* | string | path | One of: trip_types, modes_of_travel, islands, discovery_sources, departure_purpose_of_visit, place_of_stay, main_appeal |
Response Example
{
"data": [
{ "id": "tutuila", "label": "Tutuila" },
{ "id": "aunuu", "label": "Aunu'u" },
{ "id": "tau", "label": "Ta'u" },
{ "id": "ofu", "label": "Ofu" },
{ "id": "olosega", "label": "Olosega" },
{ "id": "rose_atoll", "label": "Rose Atoll" },
{ "id": "swains", "label": "Swains Island" }
]
}Error Responses
Error Codes
All errors share the same envelope: a stable machine-readable code, a human-readable message, and — for validation failures — a details object naming the offending fields.
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Validation failed: Trip type is not included in the list",
"details": { "trip_type": ["is not included in the list"] }
}
}Error Codes Reference
| Code | HTTP Status | Meaning |
|---|---|---|
VALIDATION_ERROR | 400 / 422 | Invalid request parameters or body. details lists the field errors. |
UNAUTHORIZED | 401 | Missing bearer token, malformed header, or unknown token. |
TOKEN_EXPIRED | 401 | Token is past its expires_at timestamp. |
TOKEN_REVOKED | 401 | Token was revoked by an administrator. |
FORBIDDEN | 403 | Token authenticated but lacks the required permission scope. |
ENDPOINT_DISABLED | 403 | Administrator removed this endpoint from the allow-list. |
NOT_FOUND | 404 | Requested resource (declaration, reference type) does not exist. |
RATE_LIMITED | 429 | Rate limit exceeded. Honor the Retry-After header. |
INTERNAL_ERROR | 500 | Unexpected server error. Safe to retry with backoff. |
API_DISABLED | 503 | Administrator has flipped the global API kill-switch off. |
SDK Examples
End-to-end examples for common integration patterns.
async function fetchAllDeclarations(token) {
const declarations = [];
let page = 1;
let totalPages = 1;
const headers = { 'Authorization': `Bearer ${token}` };
do {
const res = await fetch(
`/api/v1/declarations?page=${page}&limit=100`,
{ headers }
);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const body = await res.json();
declarations.push(...body.data);
totalPages = body.pagination.totalPages;
page += 1;
} while (page <= totalPages);
return declarations;
}async function fetchWithRetry(url, options, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const res = await fetch(url, options);
if (res.status !== 429) return res;
const retryAfter = parseInt(res.headers.get('Retry-After') || '60', 10);
console.warn(`Rate limited; waiting ${retryAfter}s...`);
await new Promise(r => setTimeout(r, retryAfter * 1000));
}
throw new Error('Max retries exceeded');
}