Memojin’s AI generates memocards from the text of a content, then questions from its memocards. A generation is asynchronous: the API answers at once 202 Accepted with a job, which you follow with GET /v1/jobs/{jobId}.
How it runs
- Start the generation:
202, withjobIdand the estimate of AI credits (estimate.units,Memojin-Credits-Estimateheader). - Poll the job about every 5 seconds:
pending, thenrunning(withprogressfrom 0 to 100). - On
succeeded, list the content’s memocards or questions. Onfailed(error: "generation_failed") orcancelled, there is nothing to read; quote the job identifier when you write to us.
The full loop
import os, time, uuid, requests
API = "https://api.memojin.com/v1"
H = {"Authorization": f"Bearer {os.environ['MEMOJIN_API_KEY']}"}
# 1. Start the generation: 202 Accepted
job = requests.post(
f"{API}/contents/{content_id}/memocard-generations",
headers={**H, "Idempotency-Key": str(uuid.uuid4())},
timeout=30,
)
job.raise_for_status()
job = job.json() # {"jobId": ..., "status": "pending", "estimate": {"operation": "ai_card", "units": 12}}
# 2. Poll the job every 5 seconds until it is finished
while True:
state = requests.get(f"{API}/jobs/{job['jobId']}", headers=H, timeout=10).json()
if state["status"] in ("succeeded", "failed", "cancelled"):
break
time.sleep(5)
# 3. Read the memocards of the content
if state["status"] == "succeeded":
cards = requests.get(f"{API}/contents/{content_id}/memocards", params={"limit": 100}, headers=H, timeout=30).json()["data"]Refusals before any generation
422 content_too_short: the content’s text is under 100 characters.422 nothing_to_generate: every part of the content already has its memocards.422 no_memocards: the content has no memocards to draw questions from.422 all_memocards_have_questions: every memocard already has its questions.402 insufficient_credits: the account has too few AI credits left.
In the sandbox
With a mj_test_ key, the generation is simulated: the job is succeeded at once, no memocard is created, no credit is used (see sandbox). Being told by webhook when a job ends Coming soon.
The GenerationAccepted object
A generation accepted for asynchronous processing.
| Field | Type | Description |
|---|---|---|
jobId | string (uuid) | Job to follow with GET /v1/jobs/{jobId}. |
status | "pending" | "succeeded" | pending when accepted; succeeded at once in the sandbox (mj_test_), where nothing is generated. |
estimate | object | What the generation plans to use (also in the Memojin-Credits-Estimate header). |
{
"jobId": "9b8a7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"status": "pending",
"estimate": {
"operation": "ai_card",
"units": 12
}
}The Job object
An asynchronous job (an AI generation).
| Field | Type | Description |
|---|---|---|
id | string (uuid) | Job identifier (UUID). |
type | string | What the job does: memocard_generation, question_generation, or other. New values may appear. |
status | string | pending, running, succeeded, failed or cancelled. Poll until succeeded, failed or cancelled. |
progress | integerfrom 0 to 100 | Progress, 0 to 100. |
contentId | string | null | Content the job works on, or null. |
error | string | null | Error code when the job failed (generation_failed), or null. Details stay internal: quote the job id when contacting us. |
createdAt | string (date-time) | Creation instant (ISO 8601, UTC). |
updatedAt | string (date-time) | Last update instant (ISO 8601, UTC). |
{
"id": "9b8a7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"type": "memocard_generation",
"status": "running",
"progress": 40,
"contentId": "3f1c2b0e-8d4a-4f7e-9a51-3c2d1e0f9b87",
"error": null,
"createdAt": "2026-10-04T10:00:00.000Z",
"updatedAt": "2026-10-04T10:00:20.000Z"
}Generate memocards from a content
/v1/contents/{contentId}/memocard-generationsScope generations:writeGenerates memocards from the parts of the content body that have none yet. Asynchronous: answers 202 with a jobId to poll with GET /v1/jobs/{jobId}. Uses the AI credits of the account (one ai_card unit per memocard, see estimate.units and the Memojin-Credits-Estimate header); 402 insufficient_credits when they run out. Business refusals: 422 content_too_short, 422 nothing_to_generate. With a mj_test_ key, nothing is generated and no credit is used.
Parameters
| Field | In | Type | Description |
|---|---|---|---|
contentIdrequired | path | string (uuid) | Content identifier (UUID). |
Idempotency-Key | header | string | Strongly recommended. A unique value per operation (UUID v4), reused unchanged on every retry. Within 24 hours, the same key and the same request replay the first response (Idempotent-Replayed: true) without a second effect or charge; another request with the same key → 422 idempotency_key_reused; still running → 409 idempotency_in_progress. |
Response 202
Generation accepted — A GenerationAccepted object
Errors
| HTTP | Meaning |
|---|---|
400 | validation_error — contentId is not a UUID |
401 | invalid_api_key or revoked_api_key |
402 | insufficient_credits |
403 | insufficient_scope, account_suspended, live_not_enabled or forbidden |
404 | not_found |
406 | not_acceptable — the Accept header excludes application/json |
409 | idempotency_in_progress — retry after Retry-After (1 s) |
422 | idempotency_key_reused, or a business rule (see the description) |
429 | rate_limited or test_quota_exceeded — see the Retry-After and RateLimit-* headers |
500 | internal_error |
503 | unavailable — see the Retry-After header |
curl -X POST "https://api.memojin.com/v1/contents/3f1c2b0e-8d4a-4f7e-9a51-3c2d1e0f9b87/memocard-generations" \
-H "Authorization: Bearer $MEMOJIN_API_KEY" \
-H "Idempotency-Key: 6f1c2b0e-8d4a-4f7e-9a51-3c2d1e0f9b87"{
"jobId": "9b8a7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"status": "pending",
"estimate": {
"operation": "ai_card",
"units": 12
}
}Generate questions from a content
/v1/contents/{contentId}/question-generationsScope generations:writeGenerates practice questions for the memocards of the content that have none yet. Asynchronous: answers 202 with a jobId to poll with GET /v1/jobs/{jobId}. Uses the AI credits of the account (one ai_card unit per question, see estimate.units and the Memojin-Credits-Estimate header); 402 insufficient_credits when they run out. Business refusals: 422 no_memocards, 422 all_memocards_have_questions. With a mj_test_ key, nothing is generated and no credit is used.
Parameters
| Field | In | Type | Description |
|---|---|---|---|
contentIdrequired | path | string (uuid) | Content identifier (UUID). |
Idempotency-Key | header | string | Strongly recommended. A unique value per operation (UUID v4), reused unchanged on every retry. Within 24 hours, the same key and the same request replay the first response (Idempotent-Replayed: true) without a second effect or charge; another request with the same key → 422 idempotency_key_reused; still running → 409 idempotency_in_progress. |
Response 202
Generation accepted — A GenerationAccepted object
Errors
| HTTP | Meaning |
|---|---|
400 | validation_error — contentId is not a UUID |
401 | invalid_api_key or revoked_api_key |
402 | insufficient_credits |
403 | insufficient_scope, account_suspended, live_not_enabled or forbidden |
404 | not_found |
406 | not_acceptable — the Accept header excludes application/json |
409 | idempotency_in_progress — retry after Retry-After (1 s) |
422 | idempotency_key_reused, or a business rule (see the description) |
429 | rate_limited or test_quota_exceeded — see the Retry-After and RateLimit-* headers |
500 | internal_error |
503 | unavailable — see the Retry-After header |
curl -X POST "https://api.memojin.com/v1/contents/3f1c2b0e-8d4a-4f7e-9a51-3c2d1e0f9b87/question-generations" \
-H "Authorization: Bearer $MEMOJIN_API_KEY" \
-H "Idempotency-Key: 6f1c2b0e-8d4a-4f7e-9a51-3c2d1e0f9b87"{
"jobId": "9b8a7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"status": "pending",
"estimate": {
"operation": "ai_card",
"units": 12
}
}Retrieve a job
/v1/jobs/{jobId}Scope jobs:readStatus and progress of an asynchronous generation. Poll it every few seconds (5 s is a good pace) until status is succeeded, failed or cancelled; then list the memocards or questions of the content.
Parameters
| Field | In | Type | Description |
|---|---|---|---|
jobIdrequired | path | string (uuid) | Job identifier (UUID), as returned by a generation. |
Response 200
The job — A Job object
Errors
| HTTP | Meaning |
|---|---|
400 | validation_error — an identifier is not a UUID |
401 | invalid_api_key or revoked_api_key |
403 | insufficient_scope, account_suspended, live_not_enabled or forbidden |
404 | not_found |
406 | not_acceptable — the Accept header excludes application/json |
429 | rate_limited or test_quota_exceeded — see the Retry-After and RateLimit-* headers |
500 | internal_error |
503 | unavailable — see the Retry-After header |
curl "https://api.memojin.com/v1/jobs/9b8a7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d" \
-H "Authorization: Bearer $MEMOJIN_API_KEY"{
"id": "9b8a7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"type": "memocard_generation",
"status": "running",
"progress": 40,
"contentId": "3f1c2b0e-8d4a-4f7e-9a51-3c2d1e0f9b87",
"error": null,
"createdAt": "2026-10-04T10:00:00.000Z",
"updatedAt": "2026-10-04T10:00:20.000Z"
}