Error Codes
API error responses and how to handle them
Error Codes
When a request fails, the Octopost API returns a JSON error response with a consistent structure.
Error Response Format
{
"error": "Human-readable error message",
"code": "machine_readable_code",
"details": {}
}| Field | Type | Description |
|---|---|---|
error | string | A human-readable description of what went wrong. |
code | string | A machine-readable error code for programmatic handling. |
details | object | undefined | Additional context about the error. Present on validation errors and some other error types. |
Error Codes Reference
400 Bad Request
{
"error": "Request body must be valid JSON",
"code": "bad_request"
}The request was malformed. Common causes:
- Invalid JSON in the request body.
- Missing
Content-Type: application/jsonheader. - Unsupported HTTP method for the endpoint.
401 Unauthorized
{
"error": "Invalid or expired API key",
"code": "unauthorized"
}Authentication failed. Common causes:
- Missing
Authorizationheader. - Malformed header (must be
Bearer <key>). - API key has been revoked.
- Using a test key against a live-only endpoint.
403 Forbidden
{
"error": "API key does not have permission for this action",
"code": "forbidden"
}The API key is valid but lacks the required permission. Common causes:
- Key is scoped to
posts:readbut the request is a write operation. - Attempting to modify a system preset.
- Attempting to access another user's resource.
404 Not Found
{
"error": "Post not found",
"code": "not_found"
}The requested resource does not exist. Common causes:
- Invalid resource ID.
- Resource was deleted.
- Resource belongs to a different user.
409 Conflict
{
"error": "Post has already been published and cannot be modified",
"code": "conflict"
}The request conflicts with the current state of the resource. Common causes:
- Attempting to update a published post.
- Attempting to publish a post that is already publishing.
- Attempting to set a default preset when the operation would create an invalid state.
422 Validation Error
{
"error": "Validation failed",
"code": "validation_error",
"details": {
"fields": {
"content": "Content is required",
"platforms": "At least one platform must be specified"
}
}
}The request body is valid JSON but contains invalid data. The details.fields object maps field names to their specific validation errors.
Common causes:
- Missing required fields.
- Content exceeds a platform's character limit.
- Invalid platform identifier.
scheduled_foris in the past.primary_platformis not included inplatformsarray.- No connected account found for a specified platform.
429 Rate Limited
{
"error": "Rate limit exceeded. Try again in 45 seconds.",
"code": "rate_limited",
"details": {
"limit": 300,
"remaining": 0,
"reset_at": "2026-04-03T12:01:00Z",
"retry_after": 45
}
}Too many requests. See the Rate Limits guide for backoff strategies.
500 Server Error
{
"error": "An unexpected error occurred. Please try again later.",
"code": "server_error"
}Something went wrong on our end. These errors are automatically logged and investigated. If the problem persists, contact support.
Retryable vs Non-Retryable Errors
When building resilient integrations, distinguish between errors that are safe to retry and those that require user intervention.
Retryable
These errors are transient. Retry after a delay.
| Code | HTTP Status | Retry Strategy |
|---|---|---|
rate_limited | 429 | Wait for Retry-After header or details.retry_after seconds. |
server_error | 500 | Retry with exponential backoff (1s, 2s, 4s, 8s). Maximum 5 retries. |
| - | 502 | Retry with exponential backoff. |
| - | 503 | Retry with exponential backoff. |
| - | 504 | Retry with exponential backoff. |
Non-Retryable
These errors require a fix before retrying.
| Code | HTTP Status | Action Required |
|---|---|---|
bad_request | 400 | Fix the request format or parameters. |
unauthorized | 401 | Check or regenerate the API key. |
forbidden | 403 | Use a key with the correct permissions. |
not_found | 404 | Verify the resource ID exists. |
conflict | 409 | Check the resource's current state before retrying the operation. |
validation_error | 422 | Fix the request body based on details.fields. |
Example: Error Handling in TypeScript
interface OctopostError {
error: string;
code: string;
details?: Record<string, unknown>;
}
async function createPost(content: string, platforms: string[]) {
const response = await fetch("https://api.octopost.ink/v1/posts", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.OCTOPOST_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ content, platforms }),
});
if (!response.ok) {
const error: OctopostError = await response.json();
switch (error.code) {
case "unauthorized":
throw new Error("API key is invalid. Check your configuration.");
case "validation_error":
console.error("Validation errors:", error.details);
throw new Error(`Validation failed: ${error.error}`);
case "rate_limited":
const retryAfter = (error.details as any)?.retry_after ?? 60;
console.log(`Rate limited. Retrying in ${retryAfter}s...`);
await new Promise((r) => setTimeout(r, retryAfter * 1000));
return createPost(content, platforms); // retry
case "server_error":
throw new Error("Octopost server error. Try again later.");
default:
throw new Error(`API error: ${error.error}`);
}
}
return response.json();
}