API
Read your own recipes, batches, stock and products from a shop, a spreadsheet or a script. Version 1 reads and never writes.
A key
Make one on your account page, under API keys. The key is shown once, when you make it; we keep only a scramble of it, so a lost key is revoked and replaced, not recovered. Anyone holding a key can read your account's records, so keep it on a server, not in a page other people load.
API keys are part of the Business plan.
Start free trial See plansThe first 30 days are free. Paddle takes your card at checkout and charges it only when they end; cancel before then and you pay nothing.
Sending it
With every request, in the Authorization header:
curl -H "Authorization: Bearer sf_your_key" https://soapformulator.com/api/v1/recipes Answers are JSON. Dates are ISO 8601 in UTC. Any site may call the API from a browser (CORS is open), because the key is the whole credential and no cookie is read.
Addresses
| GET | Answers with |
|---|---|
| /api/v1/recipes | Your saved recipes: id, name, product, version, superfatPercent, lye, totalOilGrams, createdAt, updatedAt, url. product is soap, or the calculator a formula was saved from (lotion, balm, candle, bath-bomb, syndet, melt-and-pour), which has no superfat, lye or oil total. Newest change first, up to 500. |
| /api/v1/recipes/{id} | One recipe with its document: for a soap, the oils, lye, superfat, water, scents and additives exactly as saved, and its colour design where it has one (design: the technique, and each portion’s share of the batter and its colours, measured as additives are; for embeds, or the bottom layers, made from another recipe, design.embedRecipe.recipe is a copy of that recipe, taken when it was chosen, with from and version naming the saved recipe it came from). Scents are a fragrances list (up to six); recipes saved before 26 September 2026 carry a single fragrance instead. The document of a formula is its product, the settings of its calculator under fields and its lines under rows, among them the scents its fragrance is blended from (rows.scents: an essential oil as eo:<id>, parts, and the maker’s own IFRA maximum where they gave one). Numbers such as the lye weight are not stored: work them out, or open the url. |
| /api/v1/batches | Your batches: id, code, recipeId, recipeVersion, madeAt, createdAt, updatedAt. Newest first, up to 500. |
| /api/v1/batches/{id} | One batch with its document: the weights, temperatures, notes, outcomes, cure weigh-ins, the recipe snapshot it was made from and what each line cost when it was logged. |
| /api/v1/stock | Your stock items: id, name, kind, group, ingredient, unit, countedIn ("" for pieces, or m, cm, ft, in, yd), onHand, averageCost, reorderAt, supplier, archived, updatedAt. |
| /api/v1/products | Your products: id, name, sku, createdAt, updatedAt and the product document (price, barcode, packaging, label text). |
When something is refused
The answer has an error code that stays the same and a message in English that may change.
| 401 unauthorized | No key, a key in the wrong form, or a revoked key. |
| 402 plan_required | The account the key belongs to is not on Business. |
| 404 not_found | No such address, or nothing with that id on this account. |
| 405 method_not_allowed | Anything but GET. The API reads; it never changes anything. |
| 429 rate_limited | More than 600 requests in an hour, for this key. |
Changes
Fields may be added to version 1. None will be removed or change meaning; that would be version 2, at a new address, with version 1 kept running.