Request & Response Format
Direct Answer
All [API_NAME] requests use JSON format with standard HTTP headers. Responses follow consistent structure with resource objects, timestamps in ISO 8601, and standardized error format.
Request Format
Content Type
All POST, PATCH, and PUT requests must use JSON:
Content-Type: application/json
Request Body
Valid JSON:
{
"field1": "string value",
"field2": 123,
"field3": true,
"nested": {
"field4": "nested value"
},
"array": ["item1", "item2"]
}
Data Types:
| Type | Example | Notes |
|---|---|---|
| String | "value" | UTF-8 encoded, max 10,000 chars |
| Number | 123 or 123.45 | Integer or float |
| Boolean | true or false | Lowercase only |
| Null | null | Represents absence of value |
| Object | {"key": "value"} | Nested objects supported |
| Array | ["item1", "item2"] | Arrays of any type |
Special Fields
Timestamps:
Always use ISO 8601 format with timezone:
{
"scheduled_at": "2024-01-15T10:30:00Z",
"expires_at": "2024-12-31T23:59:59Z"
}
Dates:
{
"birth_date": "1990-06-15", // YYYY-MM-DD
"start_date": "2024-01" // YYYY-MM (month precision)
}
Amounts:
Use smallest currency unit (cents):
{
"amount": 1999, // $19.99
"currency": "usd" // ISO 4217 currency code
}
IDs:
Always strings with prefix:
{
"user_id": "usr_abc123",
"workspace_id": "ws_xyz789"
}
Metadata:
Custom key-value data:
{
"metadata": {
"customer_id": "12345",
"order_ref": "ORD-2024-001",
"notes": "VIP customer"
}
}
Limits:
- Max 50 keys
- Key names: 40 characters max
- Values: 500 characters max
Response Format
Success Response
Single Resource:
{
"id": "usr_abc123",
"object": "user",
"email": "user@example.com",
"name": "John Doe",
"role": "member",
"status": "active",
"metadata": {
"department": "engineering"
},
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
}
Standard Fields:
| Field | Type | Description |
|---|---|---|
id | string | Unique identifier |
object | string | Resource type ("user", "document", etc.) |
created_at | string | ISO 8601 creation timestamp |
updated_at | string | ISO 8601 last update timestamp |
{
"object": "list",
"data": [
{
"id": "usr_abc123",
"object": "user",
...
},
{
"id": "usr_def456",
"object": "user",
...
}
],
"has_more": true,
"url": "/v1/users"
}
Error Response
{
"error": {
"code": "INVALID_REQUEST",
"message": "Required parameter 'email' is missing",
"details": {
"parameter": "email",
"expected_type": "string"
},
"request_id": "req_abc123"
}
}
HTTP Status Codes
2xx Success
200 OK
Standard successful response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "usr_123",
"email": "user@example.com",
...
}
201 Created
Resource successfully created:
HTTP/1.1 201 Created
Location: https://api.example.com/v1/users/usr_new123
Content-Type: application/json
{
"id": "usr_new123",
"email": "newuser@example.com",
...
}
204 No Content
Successful request with no response body:
HTTP/1.1 204 No Content
Used for DELETE operations that don't return content.
4xx Client Errors
400 Bad Request
Invalid request format:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": {
"code": "INVALID_JSON",
"message": "Request body is not valid JSON"
}
}
401 Unauthorized
Authentication required or failed:
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
"error": {
"code": "INVALID_API_KEY",
"message": "The provided API key is invalid"
}
}
404 Not Found
Resource doesn't exist:
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": {
"code": "RESOURCE_NOT_FOUND",
"message": "No user found with ID 'usr_invalid'"
}
}
5xx Server Errors
500 Internal Server Error
Unexpected server error:
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{
"error": {
"code": "INTERNAL_ERROR",
"message": "An unexpected error occurred",
"request_id": "req_abc123"
}
}
Response Headers
Standard Headers
Content-Type: application/json; charset=utf-8
X-Request-ID: req_abc123xyz456
Date: Mon, 15 Jan 2024 10:30:00 GMT
Rate Limit Headers
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1704445200
Pagination Headers
Link: <https://api.example.com/v1/users?starting_after=usr_xyz>; rel="next"
Cache Headers
Cache-Control: max-age=300, private
ETag: "686897696a7c876b7e"
Last-Modified: Mon, 15 Jan 2024 10:00:00 GMT
Field Formatting
Naming Conventions
Use snake_case for all field names:
✅ Good:
{
"user_id": "usr_123",
"created_at": "2024-01-15T10:30:00Z",
"is_active": true
}
❌ Bad:
{
"userId": "usr_123",
"CreatedAt": "2024-01-15T10:30:00Z",
"IsActive": true
}
Date & Time
Always use ISO 8601 with UTC timezone:
{
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T11:45:30.123Z", // With milliseconds
"scheduled_for": "2024-02-01T09:00:00Z"
}
Parsing in JavaScript:
const date = new Date(response.created_at);
console.log(date.toLocaleString());
Parsing in Python:
from datetime import datetime
date = datetime.fromisoformat(response['created_at'].replace('Z', '+00:00'))
print(date)
Money & Currency
Use smallest unit (cents, pence, etc.):
{
"amount": 1999, // $19.99
"currency": "usd", // ISO 4217 code
"formatted": "$19.99" // Optional human-readable
}
Supported Currencies:
usd- US Dollareur- Eurogbp- British Poundjpy- Japanese Yen- [See full list →]
Enums
Use lowercase strings:
{
"status": "active", // not "ACTIVE"
"role": "admin", // not "Admin"
"priority": "high" // not "HIGH"
}
Common Enums:
{
"status": "active" | "inactive" | "pending" | "deleted",
"role": "owner" | "admin" | "member" | "viewer",
"visibility": "public" | "private" | "shared"
}
Booleans
Always true or false (lowercase):
{
"is_active": true,
"email_verified": false,
"deleted": false
}
Null Values
Use null for absent optional values:
{
"description": null, // No description set
"deleted_at": null, // Not deleted
"avatar_url": null // No avatar
}
Omitting vs Null:
In responses, we include fields with null values for clarity:
{
"id": "usr_123",
"name": "John Doe",
"bio": null, // Explicit: no bio
"avatar_url": null // Explicit: no avatar
}
In requests, you can omit optional fields:
{
"name": "John Doe"
// bio and avatar_url omitted
}
Nested Objects
Embedded Objects
Small related objects can be embedded:
{
"id": "doc_123",
"title": "Document Title",
"author": {
"id": "usr_456",
"name": "John Doe",
"email": "john@example.com"
},
"workspace": {
"id": "ws_789",
"name": "Engineering"
}
}
ID References
Large or frequently changing objects use ID references:
{
"id": "doc_123",
"title": "Document Title",
"author_id": "usr_456", // Reference by ID
"workspace_id": "ws_789" // Reference by ID
}
Expanding References:
Use expand parameter to get full objects:
GET /v1/documents/doc_123?expand=author,workspace
Returns:
{
"id": "doc_123",
"title": "Document Title",
"author_id": "usr_456",
"author": { // Expanded
"id": "usr_456",
"name": "John Doe",
...
},
"workspace_id": "ws_789",
"workspace": { // Expanded
"id": "ws_789",
"name": "Engineering",
...
}
}
Arrays
Simple Arrays
{
"tags": ["important", "urgent", "customer"],
"permissions": ["read", "write", "delete"],
"numbers": [1, 2, 3, 4, 5]
}
Object Arrays
{
"members": [
{
"user_id": "usr_123",
"role": "admin",
"joined_at": "2024-01-01T00:00:00Z"
},
{
"user_id": "usr_456",
"role": "member",
"joined_at": "2024-01-05T00:00:00Z"
}
]
}
Empty Arrays
Return empty array [], not null:
✅ Good:
{
"tags": [],
"members": []
}
❌ Bad:
{
"tags": null,
"members": null
}
Partial Responses
Field Selection
Request only needed fields:
GET /v1/users/usr_123?fields=id,email,name
Response:
{
"id": "usr_123",
"email": "user@example.com",
"name": "John Doe"
// Other fields omitted
}
Benefits:
- Reduced payload size
- Faster responses
- Lower bandwidth usage
Limitations:
idandobjectalways included- Invalid field names ignored
Pagination Response
{
"object": "list",
"data": [
{...},
{...}
],
"has_more": true,
"url": "/v1/resources",
"next_cursor": "usr_xyz789"
}
Versioning in Responses
Resource version tracking:
{
"id": "usr_123",
"version": 5, // Increments on each update
"updated_at": "2024-01-15T11:00:00Z"
}
Optimistic Locking:
PATCH /v1/users/usr_123
If-Match: 5 # Only update if current version is 5
{
"name": "New Name"
}
Success:
{
"id": "usr_123",
"version": 6, // Incremented
"name": "New Name"
}
Conflict:
HTTP/1.1 409 Conflict
{
"error": {
"code": "VERSION_CONFLICT",
"message": "Resource was modified by another request",
"current_version": 7
}
}
Webhooks Response
Webhook payloads follow same format:
{
"id": "evt_abc123",
"object": "event",
"type": "user.created",
"created": 1704441600,
"data": {
"object": {
"id": "usr_new123",
"object": "user",
...
}
}
}
Best Practices
1. Consistent Structure
All resources follow same pattern:
{
"id": "...",
"object": "...",
...resource fields...,
"metadata": {...},
"created_at": "...",
"updated_at": "..."
}
2. Meaningful Field Names
✅ Good:
{
"email_verified": true,
"last_login_at": "2024-01-15T10:00:00Z",
"profile_image_url": "https://..."
}
❌ Bad:
{
"ev": true,
"ll": "2024-01-15T10:00:00Z",
"img": "https://..."
}
3. Don't Abbreviate
✅ Good:
{
"description": "...",
"maximum_allowed": 100,
"is_administrator": true
}
❌ Bad:
{
"desc": "...",
"max_allow": 100,
"is_admin": true
}
4. Return Created Resource
On POST, return the created resource:
POST /v1/users
{
"email": "user@example.com"
}
Response: 201 Created
{
"id": "usr_new123",
"email": "user@example.com",
"created_at": "2024-01-15T10:30:00Z",
...
}
5. Validate Input
Return detailed validation errors:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Request validation failed",
"details": {
"email": ["Email is required", "Email format is invalid"],
"age": ["Age must be at least 18"],
"password": ["Password must be at least 8 characters"]
}
}
}
Character Encoding
All requests and responses use UTF-8:
Content-Type: application/json; charset=utf-8
Supported Characters:
- ✅ ASCII
- ✅ Unicode (UTF-8)
- ✅ Emoji: 🎉 😊 ✅
- ✅ International: 中文, العربية, עברית
Example:
{
"name": "François Müller",
"bio": "Software engineer 👨💻",
"location": "東京"
}
Content Negotiation
Request Format
POST /v1/users
Content-Type: application/json
{"email": "user@example.com"}
Response Format
Default is JSON. Specify alternative via Accept header:
GET /v1/users/usr_123
Accept: application/json # Default
Currently Supported:
application/json(default)
Future Support:
application/xmltext/csv(for exports)
Compression
Responses support gzip compression:
Request:
GET /v1/users
Accept-Encoding: gzip
Response:
HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Type: application/json
[Compressed data]
Benefits:
- 70-90% size reduction
- Faster transfers
- Lower bandwidth costs
Recommendation:
Always send Accept-Encoding: gzip header.
Related Documentation
- REST Endpoints - Endpoint patterns and methods
- Pagination - Working with large datasets
- Errors - Error response format
- API Reference - Complete endpoint list
Questions? Contact Support
Last Updated: [DATE]