API reference
Errors
Every error code the API returns, what causes it, and whether retrying is worth your time.
Failures come back with the same shape every time.
{
"ok": false,
"code": "PRIVATE",
"message": "That post is private, deleted, or age restricted. Public posts only."
}
Branch on code. The message is written for a person to read and the wording may change.
The codes
| Code | Status | Cause | Retry |
|---|---|---|---|
INVALID_URL |
400 | Not an Instagram post link | No |
UNSUPPORTED |
400 | A link type we do not read, such as a Story | No |
PRIVATE |
422 | The post needs a login, is deleted, or is age restricted | No |
TOO_LONG |
422 | Video is over the duration cap | No |
TOO_LARGE |
422 | Audio is over the size the provider accepts | No |
RATE_LIMITED |
429 | You are over your limit | After retry-after |
CHALLENGE_FAILED |
403 | A bot check did not pass. Browser visitors only; API keys skip it | No |
FETCH_FAILED |
502 | Instagram would not serve us the post | Yes, with backoff |
TRANSCRIBE_FAILED |
500 | Something broke on our side | Yes, with backoff |
NOT_CONFIGURED |
503 | Transcription is off for this deployment | No |
The two you will actually see
PRIVATE
The most common failure, and it is permanent. Mark the link as unreadable and move on. A retry an hour later gives you the same answer.
Watch for it in bulk jobs. A run over a large list will hit plenty of these, and treating them as transient will waste the whole budget on retries that cannot succeed.
RATE_LIMITED
Read retry-after and sleep for that many seconds.
if (!body.ok && body.code === "RATE_LIMITED") {
const wait = Number(response.headers.get("retry-after") ?? 60);
await new Promise((resolve) => setTimeout(resolve, wait * 1000));
}
Retrying properly
Only FETCH_FAILED and TRANSCRIBE_FAILED deserve a retry. Use exponential backoff and stop after three attempts.
async function withRetry<T>(run: () => Promise<T>, attempts = 3): Promise<T> {
for (let attempt = 1; ; attempt++) {
try {
return await run();
} catch (error) {
if (attempt >= attempts) throw error;
await new Promise((resolve) => setTimeout(resolve, 2 ** attempt * 1000));
}
}
}
FETCH_FAILED usually means Instagram answered us with a login shell rather than the post. It often clears on its own within a minute or two.