On this page
A network failure or a timeout does not tell you whether your request went through. To retry without creating anything twice nor using credits twice, add the Idempotency-Key header to every POST.
Example
POST
/v1/contents/{contentId}/memocardsScope memocards:writeRequest
curl -X POST "https://api.memojin.com/v1/contents/3f1c2b0e-8d4a-4f7e-9a51-3c2d1e0f9b87/memocards" \
-H "Authorization: Bearer $MEMOJIN_API_KEY" \
-H "Idempotency-Key: 6f1c2b0e-8d4a-4f7e-9a51-3c2d1e0f9b87" \
-H "Content-Type: application/json" \
-d '{
"front": "Where does photosynthesis take place?",
"back": "In the chloroplasts, mainly in the leaves."
}'Response 201
{
"id": "c5e8a1b2-3d4f-4a6b-9c8d-7e6f5a4b3c21",
"contentId": "3f1c2b0e-8d4a-4f7e-9a51-3c2d1e0f9b87",
"front": "Where does photosynthesis take place?",
"back": "In the chloroplasts, mainly in the leaves.",
"explanation": null,
"retention": 0.82,
"lastReviewedAt": "2026-10-03T18:12:00.000Z",
"createdAt": "2026-10-01T14:05:00.000Z",
"updatedAt": "2026-10-01T14:05:00.000Z"
}Rules
- One key per operation: 1 to 255 printable ASCII characters, preferably a UUID v4. Generate it before the first attempt and keep it with the operation (in your database, in your job queue) for all its retries.
- For 24 hours, the same key with the same request (same method, same path, same body) replays the first response as is, with
Idempotent-Replayed: true: nothing is created again, no credit is used again. - The same key with another request:
422 idempotency_key_reused. The same request still running:409 idempotency_in_progress, retry afterRetry-After(1 s). - Responses stored and replayed: successes (2xx),
400,404and422. Not stored, so that a retry really runs again:402,409,429and 5xx errors. - Keys belong to your organization and to the environment: a key used in test never replays a live response.
GETrequests do not need one;PATCHandDELETEare protected by If-Match.
Retrying with the same key
import { randomUUID } from 'node:crypto';
const key = randomUUID(); // kept with the operation, reused on every retry
for (const wait of [0, 1000, 5000, 30000]) {
await new Promise((r) => setTimeout(r, wait));
try {
const res = await fetch('https://api.memojin.com/v1/contents/3f1c2b0e-8d4a-4f7e-9a51-3c2d1e0f9b87/memocards', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.MEMOJIN_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': key,
},
body: JSON.stringify(card),
signal: AbortSignal.timeout(30_000),
});
if (res.status === 409 || res.status === 429) {
await new Promise((r) => setTimeout(r, Number(res.headers.get('Retry-After') ?? 1) * 1000));
continue;
}
if (res.status < 500) return await res.json(); // 201, a replay, or an error to fix
} catch {
// network error or timeout: retry with the SAME key
}
}