http://localhost:3000/api/v1
This API follows RESTful conventions and returns JSON responses with a standardized format. All endpoints are prefixed with /api/v1 and require specific headers for proper request tracking and authentication.
| Header | Description | Example |
|---|---|---|
X-Request-ID |
Unique identifier for request tracking | 550e8400-e29b-41d4-a716-446655440000 |
Content-Type |
Media type of the request body | application/json |
Authorization |
Bearer token for authenticated endpoints | Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... |
| Header | Description | Example |
|---|---|---|
Accept |
Expected response format | application/json |
{
"success": true,
"data": {
// Response payload
},
"message": "Operation completed successfully"
}{
"success": true,
"data": null,
"message": "Operation completed successfully"
}Error bodies are a flat JSON object — there is no wrapping success/error
envelope. code is a stable, machine-readable identifier; clients should branch
on it rather than string-matching message.
{
"code": "NOT_FOUND",
"message": "Resource with id '123' was not found",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}request_id matches the X-Request-ID response header (see below) and is
omitted (not null) when no request id is available.
Every status code below can be returned by the API. code is the value of the
JSON body's code field for that status.
| HTTP Status | code |
Cause |
|---|---|---|
| 400 | VALIDATION_FAILED |
Request body or query parameters failed validation |
| 401 | UNAUTHORIZED |
Missing or invalid authentication credentials |
| 403 | FORBIDDEN |
Authenticated caller is not allowed to perform this action |
| 404 | NOT_FOUND |
The requested resource does not exist |
| 409 | CONFLICT |
The request conflicts with the current resource state (e.g. duplicate, unique/foreign-key violation) |
| 422 | VALIDATION_FAILED |
Request body was well-formed but semantically invalid |
| 429 | RATE_LIMITED |
The caller exceeded the allowed request rate |
| 500 | INTERNAL_ERROR |
Unexpected internal failure |
| 503 | SERVICE_UNAVAILABLE |
A database or downstream service is temporarily unavailable (502 and 504 map to the same code) |
Every response — allowed or rejected — includes:
| Header | Meaning |
|---|---|
X-RateLimit-Limit |
Maximum requests allowed in the current window |
X-RateLimit-Remaining |
Requests remaining in the current window |
X-RateLimit-Reset |
Unix timestamp (seconds) when the window refreshes |
A 429 response additionally includes Retry-After, the number of seconds
(an integer ≥ 1) until the caller may retry.
Every response includes X-Request-ID, either echoed from the request or
generated by the server. On error responses, the same value appears in the
JSON body's request_id field, so it can be handed to support to correlate
a user-facing error with server logs.
const res = await fetch("/api/v1/events/does-not-exist");
if (!res.ok) {
const { code, message, request_id } = await res.json();
if (code === "RATE_LIMITED") {
const retryAfter = res.headers.get("Retry-After");
// back off and retry
} else {
// surface `message` to the user; log `request_id` for support
console.error(`[${request_id ?? "no-request-id"}] ${code}: ${message}`);
}
}Combined health check for API and Database connectivity.
Response:
{
"success": true,
"data": {
"status": "ok",
"timestamp": "2024-01-15T10:30:00Z"
},
"message": "API is healthy"
}Error Response (503):
{
"success": false,
"error": {
"code": "EXTERNAL_SERVICE_ERROR",
"message": "API is not ready: database is unreachable (connection timeout)"
}
}Database connectivity check.
Response:
{
"success": true,
"data": {
"status": "ok",
"database": "connected",
"timestamp": "2024-01-15T10:30:00Z"
},
"message": "Database is healthy"
}Soroban RPC connectivity check.
Response:
{
"success": true,
"data": {
"status": "ok",
"blockchain": "soroban",
"soroban_rpc": "https://soroban-testnet.stellar.org",
"timestamp": "2024-01-15T10:30:00Z"
},
"message": "Soroban RPC is reachable"
}Error Response (503):
{
"success": false,
"error": {
"code": "EXTERNAL_SERVICE_ERROR",
"message": "Soroban RPC health check failed"
}
}Readiness check for both API and Database.
Response:
{
"success": true,
"data": {
"status": "ready",
"api": "ok",
"database": "ok"
},
"message": "Service is ready"
}Returns a validation error for testing error handling.
Response (400):
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "The provided input is invalid"
}
}Returns an empty success response for testing success handling.
Response:
{
"success": true,
"data": null,
"message": "Operation completed successfully"
}Returns a not found error for testing 404 handling.
Path Parameters:
id(string): Resource identifier
Response (404):
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "Resource with id '123' was not found"
}
}Validates a signed attendee ticket QR payload and checks the corresponding ticket into the event.
Request Body:
{
"payload": {
"id": "...",
"qr_type": "ticket",
"data": {
"wallet_address": "GABC...XYZ",
"ticket_id": "550e8400-e29b-41d4-a716-446655440000"
},
"created_at": "2026-07-30T12:00:00Z",
"expires_at": "2026-07-30T12:05:00Z",
"nonce": "..."
},
"signature": "base64_signature",
"public_key": "hex_public_key"
}Response (200):
{
"success": true,
"data": {
"valid": true,
"scanned": true,
"ticket_id": "550e8400-e29b-41d4-a716-446655440000",
"ticket_status": "Scanned",
"scanned_at": "2026-07-30T12:00:12Z",
"message": "Ticket scan verified successfully"
},
"message": "Ticket scan verified successfully"
}Errors:
400— invalid payload or expired QR403— wallet address does not match ticket ownership404— ticket or QR payload not found409— ticket already scanned or QR already used
| Error Code | HTTP Status | Description |
|---|---|---|
VALIDATION_ERROR |
400 | Request data failed validation |
AUTH_ERROR |
401 | Authentication failed or missing |
FORBIDDEN |
403 | Insufficient permissions |
NOT_FOUND |
404 | Resource not found |
DATABASE_ERROR |
500 | Database operation failed |
EXTERNAL_SERVICE_ERROR |
503 | External service unavailable |
INTERNAL_SERVER_ERROR |
500 | Unexpected server error |
curl -X GET \
http://localhost:3000/api/v1/health \
-H 'X-Request-ID: 550e8400-e29b-41d4-a716-446655440000' \
-H 'Accept: application/json'curl -X GET \
http://localhost:3000/api/v1/examples/validation-error \
-H 'X-Request-ID: 550e8400-e29b-41d4-a716-446655440000' \
-H 'Accept: application/json'curl -X GET \
http://localhost:3000/api/v1/examples/not-found/123 \
-H 'X-Request-ID: 550e8400-e29b-41d4-a716-446655440000' \
-H 'Accept: application/json'Currently, no rate limiting is implemented. All endpoints are available without rate restrictions.
Authentication is not yet implemented for the current endpoints. Future endpoints will require Bearer token authentication via the Authorization header.
The API is versioned using URL path versioning. The current version is v1. All endpoints are prefixed with /api/v1.
The following endpoints are planned for future implementation:
POST /auth/register- User registrationPOST /auth/login- User loginPOST /auth/logout- User logoutGET /users/profile- Get user profilePUT /users/profile- Update user profile
GET /events- List eventsPOST /events- Create eventGET /events/:id- Get event detailsPUT /events/:id- Update eventDELETE /events/:id- Delete event
- All timestamps are returned in ISO 8601 format (UTC)
- The
X-Request-IDheader is propagated through the system for distributed tracing - Error responses are standardized across all endpoints
- The API uses PostgreSQL as the primary database
- CORS is configured for cross-origin requests