Submission API

Updated by user · 4 days ago · 5 min read

# Submitting series data Every change to a series — adding one, editing scalars, swapping covers — goes through **one** submission API. Trusted users (contributor+) can apply changes immediately; everyone else's changes queue for moderator review. Same request either way. > [!NOTE] > All endpoints require a **Personal Access Token**: `Authorization: Bearer <token>`. Base path: `https://api.mangabaka.org/v0`. > [!IMPORTANT] > Access requires the **contributor** role (or higher), **or at least 25 approved submissions**. Below that bar the API returns `403 Forbidden` — keep submitting through the site to build up an approved history and the API unlocks automatically. > [!CAUTION] > **Pending limit (regular users):** you can't have more than `min(2 × approved, 250)` submissions awaiting review at once. A `create`/`save` beyond that returns `403 Forbidden` — withdraw a pending one or wait for review to free room. Contributors+ are exempt. (So at 25 approved → 50 pending max; 50 → 100; capped at 250.) ## The shape Two address spaces: you key by the **live resource** before a submission exists, and by the **submission id** afterwards. | Method & path | What it does | | ------------------------------------------------- | --------------------------------------------------------------------- | | `GET /my/submissions` | List your submissions (`?resource=`, `?status=`, paginated) | | `POST /my/submissions/{resource}` | Create a brand-new resource (e.g. a new series) | | `GET /my/submissions/{resource}/{id}` | **Snapshot** — the live resource as a submittable body, + a `version` | | `POST /my/submissions/{resource}/{id}` | Edit an existing resource | | `POST /my/submissions/{resource}/{id}/preview` | Dry-run — returns the diff, writes nothing | | `GET /my/submissions/{submission_id}` | Read one of your submissions (+ its `version`) | | `PATCH /my/submissions/{submission_id}` | Edit a still-pending submission | | `POST /my/submissions/{submission_id}/withdraw` | Withdraw a pending submission | `{resource}` is `series` or `series-images`. `{id}` is the series id; `{submission_id}` is the submission's own id. ## The body Resource data lives under `data`; everything else is ceremony at the root: ```jsonc { "data": { /* the resource fields — see "Partial submissions" */ }, "version": 1781009663785, // optimistic-concurrency token (see below) "user_note": "why I'm making this change", // required "save_mode": "direct", // trusted users only: "direct" (apply now, default) | "review" (queue) } ``` A successful write returns the submission summary **plus `changes`** — the exact field-level diff that was applied (or will apply on review). No separate call needed to see what happened. ## The golden workflow ```text GET /my/submissions/series/222 → { data: { data: {…}, version } } (edit the fields you care about) POST /my/submissions/series/222 → 201 { data: { …summary, changes: [...] } } body: { data: {…edited…}, version, user_note } ``` Fetch the snapshot, change what you want, send it back with the `version` you got. That's it. > [!TIP] > Building or testing a script? Run the same `data` against [`POST …/{id}/preview`](#preview-dry-run) first — it returns the exact `changes` your save would apply but **writes nothing**. Iterate until the diff looks right, then drop `/preview` to commit for real. ## Partial submissions You only send the fields you're changing. Omitted scalar fields keep their current value — the server read-merges your `data` onto the live resource. ```bash # Mark a series completed — nothing else touched. curl -X POST https://api.mangabaka.org/v0/my/submissions/series/222 \ -H "Authorization: Bearer $MB_TOKEN" -H "Content-Type: application/json" \ -d '{ "version": 1781009663785, "user_note": "Series finished publishing", "data": { "overrides": { "status": "completed" } } }' ``` > [!IMPORTANT] > **Collections are full-replace, not merged.** `images`, `series_titles`, `tags`, `links`, and `relationships` replace the whole set when you include them. To add one cover, fetch the snapshot, append to the array, and POST the **complete** list back. Omit a collection entirely to leave it untouched. ## The `version` field (optimistic concurrency) `version` is an opaque integer (unix epoch millis) you get from the snapshot/read. Round-trip it on every mutation so you never silently clobber someone else's change. - **Required** on `POST /{resource}/{id}` (edit), `PATCH /{submission_id}`, and withdraw. - **Not** sent on create (`POST /{resource}`) — nothing exists yet. - Optional on `preview`. > [!WARNING] > If the resource changed since you fetched it, your `version` is stale and the write is rejected with **`409 Conflict`** — nothing is written. Re-fetch the snapshot (new `version` + current data), re-apply your change, and POST again. Don't reuse an old `version`. ## Preview (dry-run) See the exact diff a save would produce — without writing anything. Same `data` as a save (no `user_note` needed; `version` optional, since nothing is written): ```bash curl -X POST https://api.mangabaka.org/v0/my/submissions/series/222/preview \ -H "Authorization: Bearer $MB_TOKEN" -H "Content-Type: application/json" \ -d '{ "data": { "overrides": { "status": "completed" } } }' ``` Returns the same `changes` shape a real save would apply: ```jsonc { "status": 200, "data": { "has_changes": true, "changes": [ { "field": "overrides.status", "type": "changed", "details": { "status": { "old": "releasing", "new": "completed" } }, }, ], }, } ``` ## Create a new series No `version` (nothing exists yet) — send the full `data`: ```bash curl -X POST https://api.mangabaka.org/v0/my/submissions/series \ -H "Authorization: Bearer $MB_TOKEN" -H "Content-Type: application/json" \ -d '{ "user_note": "New standalone series", "data": { /* full series record */ } }' ``` Trusted users get `201 accepted` and the series is materialized; others get `201 pending` for a moderator to accept. > [!TIP] > One mental model: **GET → edit → POST back the `version`.** Send only what changed (full set for collections), include a `user_note`, and read `changes` in the response to confirm the diff.