Partner submission API
HMAC-signed REST endpoint for organisational partners submitting books to the Real Life Stories curation queue. Contact us to receive a key ID and secret.
Endpoint
POST /api/public/books/submit
Authentication
Every request must include these headers:
x-rls-key-id— your public key ID.x-rls-timestamp— unix seconds. Rejected if more than 5 minutes skewed.x-rls-signature—hex(hmac_sha256(sha256(secret), `$${ts}.$${sha256(body)}`)).
The signing key is sha256(secret), not the raw secret. We only store that hash; if you leak your secret, request rotation.
Body
JSON with these fields (see the Zod schema on the server for exact limits):
title— 3–300 chars.synopsis— 20–4000 chars.authorName— optional; author is created if new.language— ISO 639-1 (defaulten).originCountry— ISO 3166-1 alpha-2, optional.category— free-form, ≤ 80 chars.pageCount— integer, 1–50 000.imageCount— integer, default 0.coverUrl,sourceUrl,manuscriptUrl— optional https URLs.manuscriptFormat—epub | pdf | mobi | audio, optional.
Pricing formula
Price is locked at submission: round((pageCount × 4¢ + imageCount × 25¢) × 1.5). 50% flows to the storyteller.
Response
201 Created → { id, slug, status: "submitted" }. The book enters the curation queue with status = "draft" and curation_status = "submitted", and only becomes public after an editor approves it.
Errors: 401 auth, 400 validation, 413 body over 100 KB.
Node.js example
import { createHash, createHmac } from "crypto";
const keyId = process.env.RLS_KEY_ID!;
const secret = process.env.RLS_SECRET!;
const body = JSON.stringify({
title: "The Salt Path",
synopsis: "A memoir of walking the South West Coast Path...",
authorName: "Raynor Winn",
language: "en",
originCountry: "GB",
category: "memoir",
pageCount: 288,
imageCount: 0,
});
const ts = Math.floor(Date.now() / 1000).toString();
const bodyHash = createHash("sha256").update(body).digest("hex");
// Signing key is sha256(secret)
const signingKey = createHash("sha256").update(secret).digest("hex");
const signature = createHmac("sha256", signingKey)
.update(`${ts}.${bodyHash}`)
.digest("hex");
const res = await fetch("https://reallifestories.store/api/public/books/submit", {
method: "POST",
headers: {
"content-type": "application/json",
"x-rls-key-id": keyId,
"x-rls-timestamp": ts,
"x-rls-signature": signature,
},
body,
});
console.log(res.status, await res.json());