Bearer token authentication uses short-lived access tokens (15-minute TTL) paired with long-lived refresh tokens (30-day TTL).

Obtain the initial token pair with POST /api/v2/auth/token, passing your API credentials in the request body. Include the access token as Authorization: Bearer {token} in subsequent requests. When an access token expires, exchange the refresh token for a new pair at POST /api/v2/auth/refresh. Do not store access tokens beyond the request cycle; store only the refresh token securely.

Cursor Pagination Fixes the Drift Problem

Cursor-based pagination replaces the ?page=N pattern. Each response that has additional results includes a next_cursor value in the meta object. Pass it as ?cursor={value} in the next request. This approach avoids the "page drift" difficulty: with offset pagination, inserting a new post while a client is paginating through results causes the client to skip or re-read posts. Cursor pagination is stable regardless of insertions or deletions.

Unified Response Envelope

The unified response envelope is {"success": true, "data": {...}, "meta": {...}, "errors": []}. In v1, each endpoint returned its own structure — some nested the main resource under a key matching the resource type ({"post": {...}}), others returned the resource directly at the root. v2 is consistent: the resource is always under data, pagination metadata is always under meta, and errors are always in the errors array.

Migration Strategy: One Endpoint at a Time

v1 endpoints remain active and will receive security patches until v1.6.0. If your integration uses offset pagination heavily — for example, to export large result sets — migrating to cursors requires rethinking how you handle result sets that exceed a single page. We recommend migrating one endpoint at a time, starting with read-only GET endpoints before tackling POST and PATCH endpoints that modify state.

Authentication: Code Examples

Obtaining an access token and using it in subsequent requests:

# Step 1: Get token pair
curl -X POST https://yoursite.com/api/v2/auth/token \
 -H "Content-Type: application/json" \
 -d '{"api_key": "your-key", "api_secret": "your-secret"}'

# Response:
# {"success": true, "data": {"access_token": "eyJ...", "refresh_token": "rf_...", "expires_in": 900}}

# Step 2: Use access token
curl https://yoursite.com/api/v2/posts \
 -H "Authorization: Bearer eyJ..."

# Step 3: Refresh when expired (HTTP 401)
curl -X POST https://yoursite.com/api/v2/auth/refresh \
 -H "Content-Type: application/json" \
 -d '{"refresh_token": "rf_..."}'

Token Storage Best Practices

Store refresh tokens in an encrypted database column or a secrets manager. Never log access or refresh tokens in application logs. In server-to-server integrations, implement automatic token rotation: request a new token pair when the access token is within 60 seconds of expiration, not after it has already expired. This avoids failed requests during the rotation window.

Cursor Pagination: Implementation Details

The cursor value is an opaque, base64-encoded string containing the sort key and record ID. Do not attempt to decode, construct, or modify cursor values. On a table with 100,000 posts, the v1 request ?page=500&per_page=20 takes approximately 1,200ms because MySQL must scan 10,000 rows before returning 20. The equivalent cursor request takes a consistent 15-25ms regardless of position in the result set.

Error Handling in v2

The v2 error format provides structured error information. Key error codes to handle in your integration:

  • AUTH_EXPIRED (HTTP 401): access token expired. Refresh and retry.
  • AUTH_INVALID (HTTP 401): token is malformed or revoked. Re-authenticate from scratch.
  • RATE_LIMITED (HTTP 429): too many requests. Check the Retry-After header for seconds to wait.
  • VALIDATION_FAILED (HTTP 422): request body failed validation. Check the errors array for field-specific messages.
  • NOT_FOUND (HTTP 404): resource does not exist or is not accessible with the current token scope.

v1 to v2 Endpoint Mapping

Reference for updating your integration endpoints:

  • GET /api/v1/posts becomes GET /api/v2/posts
  • POST /api/v1/posts/create becomes POST /api/v2/posts (RESTful)
  • POST /api/v1/posts/update/{id} becomes PATCH /api/v2/posts/{id}
  • POST /api/v1/posts/delete/{id} becomes DELETE /api/v2/posts/{id}
  • GET /api/v1/media/list becomes GET /api/v2/media

The v2 endpoints follow RESTful conventions consistently: resource collections use plural nouns, individual resources use the collection name plus ID, and HTTP methods indicate the action.

Rate Limiting and Throttling

API v2 introduces per-token rate limiting. The default limits are 60 requests per minute for standard tokens and 300 requests per minute for admin tokens. Rate limit headers are included in every response:

  • X-RateLimit-Limit: maximum requests allowed per window
  • X-RateLimit-Remaining: requests remaining in current window
  • X-RateLimit-Reset: Unix timestamp when the window resets

When you hit the limit, the API returns HTTP 429 with a Retry-After header. For bulk operations like importing 10,000 posts from an external CMS, use the /api/v2/bulk/posts endpoint which accepts up to 100 records per request and counts as a single rate-limited call. This reduces a 10,000-request migration to 100 requests, completing in under 2 minutes rather than hitting rate limits for 3+ hours.