Call Profitlee from your backend.
JSON in / JSON out, Bearer-token auth. Covers Amazon FBA/FBM (US, Germany, Japan) and TikTok Shop (US, FBT + self-fulfilled) from the same endpoint — switch with the platform + mode discriminators. Available to Pro accounts only.
- Subscribe to Pro.
- Open Account → API access and click Generate API token. Copy it immediately — it's shown only once.
- Send requests to
/api/v1/*with the token in anAuthorizationheader.
/api/v1/calculate
Computes a per-unit and monthly profit breakdown. Same engine as the web calculator — no I/O, no Amazon API calls, pure math against country-accurate fee tables.
A discriminated union on mode, scoped by platform. Numbers are in the marketplace's native units: in / lb / $ for Amazon us and TikTok Shop us, cm / kg / € for Amazon de, cm / kg / ¥ for Amazon jp.
Platform + mode matrix
Each platform exposes a different set of modevalues. Sending a mode that doesn't belong to the platform returns 400 invalid_input.
| Field | Type | Description |
|---|---|---|
| amazon | "fba" | "fbm" | Fulfilled by Amazon, or self-fulfilled (FBM). Regions: us, de, jp. |
| tiktok_shop | "fbt" | "self_fulfilled" | Fulfilled by TikTok, or self-fulfilled. Regions: us only (today). |
Common fields
| Field | Type | Description |
|---|---|---|
| platform | "amazon" | "tiktok_shop" (optional) | Marketplace operator. Defaults to "amazon" when omitted so older clients keep working. |
| region | "us" | "de" | "jp" | Marketplace country. TikTok Shop is US-only today; sending de/jp returns invalid_input. |
| mode | "fba" | "fbm" | "fbt" | "self_fulfilled" | Fulfilment model. Allowed values depend on platform — see the matrix above. Determines the per-mode fields below. |
| L, W, H | number | Box dimensions (in or cm). |
| weight | number | Unit weight (lb or kg). |
| fob | number | FOB cost per unit. |
| headShip | number | Head shipping cost per unit. |
| duty | number | Duty per unit, in listing currency. NOT a percentage — convert your tariff rate to a per-unit amount yourself (e.g. 12% × $3.50 FOB → 0.42). |
| price | number | Selling price. |
| ppcAcos | number | PPC / ad-spend ACoS as a 0–1 fraction (e.g. 0.18 = 18%). |
| returnRate | number | Return rate as 0–1. |
| referralPct | number | Referral / commission fee as 0–1. Used directly when referralCategory is null/omitted; otherwise auto-derived from the category + price (callers may send their last manual value). |
| referralCategory | string | null (optional) | Slug from Profitlee's referral rate-card table (e.g. "baby_products", "watches"). Categories are platform-scoped; pass an Amazon slug with platform="amazon", a TikTok slug with platform="tiktok_shop". When set, the server resolves the effective per-unit rate from the category's tier shape and ignores referralPct. |
| monthlyVolume | integer | Monthly units sold (≥ 0). |
| isApparel | boolean | Whether the item is apparel — affects Amazon JP storage rate and US apparel referral surcharges. |
Amazon FBA fields (mode = "fba")
| Field | Type | Description |
|---|---|---|
| inboundOption | "optimized" | "partial" | "single" | US inbound placement option. Ignored on DE / JP (single fulfillment centre). |
| storageMonths | number | How many months the inventory sits in Amazon's FCs. |
| storageSeason | "janSep" | "octDec" | Off-peak vs peak storage rate band. |
Amazon FBM fields (mode = "fbm")
| Field | Type | Description |
|---|---|---|
| outboundShipPerUnit | number | Outbound shipping cost per unit. |
| pickPackPerUnit | number | Pick & pack cost per unit. |
| monthly3plStorage | number | Total monthly 3PL storage (not per unit) — engine divides by monthlyVolume. |
TikTok Shop FBT fields (platform = "tiktok_shop", mode = "fbt")
| Field | Type | Description |
|---|---|---|
| storageMonthsPastFree | number | Months stored BEYOND TikTok's free-storage window. 0 if the inventory turns within the free period. |
TikTok Shop self-fulfilled fields (platform = "tiktok_shop", mode = "self_fulfilled")
| Field | Type | Description |
|---|---|---|
| outboundShipPerUnit | number | Outbound shipping cost per unit. |
| pickPackPerUnit | number | Pick & pack cost per unit. |
| monthly3plStorage | number | Total monthly 3PL storage (not per unit). |
{ result: CalcOutputs }. Selected fields (all numbers rounded to 4 decimal places):
| Field | Type | Description |
|---|---|---|
| result.platform | "amazon" | "tiktok_shop" | Echoed back so multi-platform clients can route on it. |
| result.region | "us" | "de" | "jp" | Echoed back. |
| result.mode | string | Echoed back — one of the four mode values. |
| result.totalCost | number | Per-unit total cost (COGS + platform fees). |
| result.grossProfit | number | price − totalCost. |
| result.netProfitAfterPPC | number | Per-unit profit after PPC and return losses. |
| result.netMarginAfterPPC | number | Margin as 0–1 (multiply by 100 for %). |
| result.monthlyNetAfterPPC | number | netProfitAfterPPC × monthlyVolume. |
| result.sizeTier | string | Resolved size-tier name (Amazon nomenclature is reused for TikTok). |
| result.fulfillmentFee | number | Marketplace fulfilment fee (FBA / FBT) or shipping + pick/pack (FBM / self-fulfilled). |
| result.referralFee | number | Referral / commission fee per unit. |
| result.fixedClosingFee | number | Amazon DE Media closing fee (€0.99) when referralCategory is one of books / music_video_dvd / software / video_games_accessories; 0 otherwise. Always 0 on US / JP / TikTok. |
| result.storageFee | number | Storage fee per unit. JP uses an apparel-aware rate. |
Amazon FBA — US (curl / Node / Python)
curl -X POST https://your-host/api/v1/calculate \
-H "Authorization: Bearer eck_live_xxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{ "platform": "amazon", "region": "us", "mode": "fba", "L": 17, "W": 13, "H": 4, "weight": 1.4, "fob": 3.20, "headShip": 1.10, "duty": 0.96, "inboundOption": "single", "storageMonths": 1, "storageSeason": "janSep", "price": 24.99, "ppcAcos": 0.18, "returnRate": 0.05, "monthlyVolume": 300, "referralPct": 0.15, "isApparel": false }'TikTok Shop FBT — US (request body only)
Same endpoint, same headers — only the body shape changes. storageMonthsPastFree replaces the Amazon storage fields; inboundOption is omitted entirely.
{
"platform": "tiktok_shop",
"region": "us",
"mode": "fbt",
"L": 8, "W": 6, "H": 2,
"weight": 0.5,
"fob": 2.00, "headShip": 0.40, "duty": 0.24,
"storageMonthsPastFree": 0,
"price": 19.99, "ppcAcos": 0.10, "returnRate": 0.05,
"monthlyVolume": 500, "referralPct": 0.08, "isApparel": false
}Sample response (Amazon FBA US example)
{
"result": {
"region": "us",
"mode": "fba",
"sizeTier": "Large Standard",
"totalCost": 18.3407,
"grossProfit": 6.6493,
"netProfitAfterPPC": 1.7007,
"netMarginAfterPPC": 0.0681,
"monthlyNetAfterPPC": 510.2092,
"fulfillmentFee": 8.3731,
"referralFee": 3.7485,
"storageFee": 0.399
}
}/api/v1/scenarios
Returns the authenticated user's saved scenarios, newest-updated first. Each row includes the full inputs + outputs payload as it was computed on save (or last update).
{ scenarios: Scenario[] }, where:
| Field | Type | Description |
|---|---|---|
| scenarios[].id | string | Stable identifier (used in the web detail URL). |
| scenarios[].name | string | User-assigned name. |
| scenarios[].platform | "amazon" | "tiktok_shop" | Marketplace operator (echoed from the inputs). |
| scenarios[].region | "us" | "de" | "jp" | Marketplace country. |
| scenarios[].mode | "fba" | "fbm" | "fbt" | "self_fulfilled" | Fulfilment model — value range depends on platform. |
| scenarios[].inputs | object | The CalcInputs snapshot. |
| scenarios[].outputs | object | The CalcOutputs computed at save (4-decimal precision). |
| scenarios[].createdAt | string (ISO 8601) | First save. |
| scenarios[].updatedAt | string (ISO 8601) | Most recent save/update. |
No pagination yet — pages are user-bounded (typical Pro account has dozens). We'll add ?limit / ?cursor if that ever matters.
curl https://your-host/api/v1/scenarios \
-H "Authorization: Bearer eck_live_xxxxxxxxxxxxxxxxxxxxxx"/api/v1/scenarios
Creates a new saved scenario for the authenticated user. Outputs are recomputed server-side from the supplied inputs and stored alongside them. Also appends a row to the 30-day activity feed.
| Field | Type | Description |
|---|---|---|
| name | string | Display name; 1–120 chars. |
| inputs | CalcInputs | Same shape as POST /api/v1/calculate. See that section for field tables. |
Response is { scenario: Scenario } (the full new row, including server-generated id). HTTP 201 on success.
curl -X POST https://your-host/api/v1/scenarios \
-H "Authorization: Bearer eck_live_xxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{ "name": "Canvas tote — US Q4", "inputs": { "platform": "amazon", "region": "us", "mode": "fba", "L": 17, "W": 13, "H": 4, "weight": 1.4, "fob": 3.20, "headShip": 1.10, "duty": 0.96, "inboundOption": "single", "storageMonths": 1, "storageSeason": "janSep", "price": 24.99, "ppcAcos": 0.18, "returnRate": 0.05, "monthlyVolume": 300, "referralPct": 0.15, "isApparel": false } }'/api/v1/scenarios/{id}
Returns a single scenario by id. Scoped to the authenticated user — requesting an id you don't own returns 404 not_found.
curl https://your-host/api/v1/scenarios/SCENARIO_ID \
-H "Authorization: Bearer eck_live_xxxxxxxxxxxxxxxxxxxxxx"/api/v1/scenarios/{id}
Replaces the scenario's inputs and (optionally) its name. Outputs are recomputed server-side; a fresh activity-feed row is appended so iterations show up alongside saves.
| Field | Type | Description |
|---|---|---|
| inputs | CalcInputs | Required. Replaces the stored inputs verbatim. |
| name | string (optional) | If present (1–120 chars), the scenario is renamed. |
For rename-only, prefer PATCH below — same end state, smaller payload, no history row.
curl -X PUT https://your-host/api/v1/scenarios/SCENARIO_ID \
-H "Authorization: Bearer eck_live_xxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{ "inputs": { "platform": "amazon", "region": "us", "mode": "fba", "L": 17, "W": 13, "H": 4, "weight": 1.4, "fob": 3.20, "headShip": 1.10, "duty": 0.96, "inboundOption": "single", "storageMonths": 1, "storageSeason": "janSep", "price": 24.99, "ppcAcos": 0.18, "returnRate": 0.05, "monthlyVolume": 300, "referralPct": 0.15, "isApparel": false } }'/api/v1/scenarios/{id}
Renames a scenario. Inputs and outputs are untouched; only name and updatedAt change. Body: { name: string }.
curl -X PATCH https://your-host/api/v1/scenarios/SCENARIO_ID \
-H "Authorization: Bearer eck_live_xxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{ "name": "Canvas tote — US Q4 (v2)" }'/api/v1/scenarios/{id}
Permanently removes the scenario and any associated share link (foreign key cascade). The 30-day activity rows it spawned are preserved — they live independently in scenario_history.
curl -X DELETE https://your-host/api/v1/scenarios/SCENARIO_ID \
-H "Authorization: Bearer eck_live_xxxxxxxxxxxxxxxxxxxxxx"Stability & roadmap
- Versioning. The
/v1/namespace is stable — any breaking change ships under/v2/with both running in parallel. - Rate limits.None today. We'll publish the cap ahead of turning anything on.
- Platform coverage. Amazon FBA/FBM ships for US, Germany, Japan; TikTok Shop ships for US (FBT + self-fulfilled). DE/JP for TikTok Shop arrive when the platform officially launches those regions — the engine signature is already platform-scoped.
- Coming next. Share-link management (create / revoke) and PDF download URLs over the API.