ax-check.com
by Gauge
T
The New Black AI
thenewblack.ai
ax-check.com
Checked 30 October 2026
B
84/100
Agents need your login
Agents can install, authenticate, and price this product fast.
21 of 23 checks passed: CLI, API, MCP server and skills are all documented with working install paths, and pricing is stated openly with no login wall.
2 fixes to start with
Concrete changes, backed by what we found.
Recorded coding sessions
Same task, 3 models, no thenewblack.ai account. Recorded 30 October 2026 on Pi.
3 recorded · 2m 28s
2m 28s · recorded
Session findings
Select a finding to see it in context.
›Thinking…
Let me look at the repo to see what's there.
"The New Black" is an AI fashion design platform (thenewblack.ai). Let me check the environment/repo first, and whether there's any info available.
Let me investigate.
pwd; ls -la; cat README* 2>/dev/null | head -50; env | grep -i -E "black|tnb|api_key" | sed 's/=.*/=<set>/'
/sandbox/repo
/sandbox/repo total 16 drwxr-xr-x 3 root root 4096 Sep 18 08:00 . drwxr-xr-x 7 root root 4096 Oct 30 20:22 .. drwxr-xr-x 8 root root 4096 Sep 24 20:05 .git -rw-r--r-- 1 root root 408 Sep 18 08:00 .gitignore PI_GATEWAY_API_KEY=<set>
Recorded tool call
{
"type": "tool_call",
"seq": 3,
"ts": "2026-10-30T20:22:48.066Z",
"name": "bash",
"turn": 1,
"input": {
"command": "pwd; ls -la; cat README* 2>/dev/null | head -50; env | grep -i -E \"black|tnb|api_key\" | sed 's/=.*/=<set>/'"
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-b0721b0e77594edd",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 6,
"ts": "2026-10-30T20:22:48.066Z",
"turn": 1,
"output": {
"content": [
{
"text": "/sandbox/repo\ntotal 16\ndrwxr-xr-x 3 root root 4096 Sep 18 08:00 .\ndrwxr-xr-x 7 root root 4096 Oct 30 20:22 ..\ndrwxr-xr-x 8 root root 4096 Sep 24 20:05 .git\n-rw-r--r-- 1 root root 408 Sep 18 08:00 .gitignore\nPI_GATEWAY_API_KEY=<set>\n",
"type": "text"
}
]
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-b0721b0e77594edd",
"is_error": false,
"tool_kind": "shell"
}ls /usr/local/lib/node_modules/@earendil-works/pi-coding-agent/docs 2>/dev/null
compaction.md
compaction.md containerization.md custom-provider.md development.md docs.json environment-variables.md extensions.md images index.md json.md keybindings.md llama-cpp.md models.md packages.md prompt-templates.md providers.md quickstart.md rpc.md sdk.md security.md session-format.md sessions.md settings.md shell-aliases.md skills.md terminal-setup.md termux.md themes.md tmux.md tui.md usage.md windows.md
Recorded tool call
{
"type": "tool_call",
"seq": 4,
"ts": "2026-10-30T20:22:48.066Z",
"name": "bash",
"turn": 1,
"input": {
"command": "ls /usr/local/lib/node_modules/@earendil-works/pi-coding-agent/docs 2>/dev/null"
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-ab7eba208938ae92",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 5,
"ts": "2026-10-30T20:22:48.066Z",
"turn": 1,
"output": {
"content": [
{
"text": "compaction.md\ncontainerization.md\ncustom-provider.md\ndevelopment.md\ndocs.json\nenvironment-variables.md\nextensions.md\nimages\nindex.md\njson.md\nkeybindings.md\nllama-cpp.md\nmodels.md\npackages.md\nprompt-templates.md\nproviders.md\nquickstart.md\nrpc.md\nsdk.md\nsecurity.md\nsession-format.md\nsessions.md\nsettings.md\nshell-aliases.md\nskills.md\nterminal-setup.md\ntermux.md\nthemes.md\ntmux.md\ntui.md\nusage.md\nwindows.md\n",
"type": "text"
}
]
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-ab7eba208938ae92",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
The repo is empty (just .gitignore). The task: build a simple example using "The New Black AI". This is thenewblack.ai — an AI fashion design generation platform. Does it have a public developer API/SDK? I don't believe The New Black offers a public API or SDK. Let me check network access and try to find docs.
Let me test network connectivity.
cd /sandbox/repo && cat .gitignore; git log --oneline | head; timeout 15 curl -sSI https://thenewblack.ai 2>&1 | head -5; echo "---"; timeout 15 curl -sS https://pypi.org/simple/ 2>&1 | head -3
# Keep generated and vendored files out of source diffs.
# Keep generated and vendored files out of source diffs. # Logs / OS cruft *.log .DS_Store # JavaScript / TypeScript node_modules/ .next/ dist/ build/ coverage/ # Python .venv/ venv/ __pycache__/ *.py[cod] .pytest_cache/ *.egg-info/ # Rust target/ # Go / PHP / Ruby vendored deps vendor/ .bundle/ # Java / Kotlin / Scala .gradle/ # .NET bin/ obj/ # Elixir _build/ deps/ # Dart / Flutter .dart_tool/ 9ebf5fb Initial workspace HTTP/2 200 age: 0 cache-control: private, no-cache, no-store, max-age=0, must-revalidate content-type: text/html; charset=utf-8 date: Fri, 30 Oct 2026 20:22:50 GMT --- <!DOCTYPE html> <html lang="en"> <head>
Recorded tool call
{
"type": "tool_call",
"seq": 9,
"ts": "2026-10-30T20:22:50.133Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /sandbox/repo && cat .gitignore; git log --oneline | head; timeout 15 curl -sSI https://thenewblack.ai 2>&1 | head -5; echo \"---\"; timeout 15 curl -sS https://pypi.org/simple/ 2>&1 | head -3"
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-8f77895a2d2321fb",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 10,
"ts": "2026-10-30T20:22:51.642Z",
"turn": 1,
"output": {
"content": [
{
"text": "# Keep generated and vendored files out of source diffs.\n\n# Logs / OS cruft\n*.log\n.DS_Store\n\n# JavaScript / TypeScript\nnode_modules/\n.next/\ndist/\nbuild/\ncoverage/\n\n# Python\n.venv/\nvenv/\n__pycache__/\n*.py[cod]\n.pytest_cache/\n*.egg-info/\n\n# Rust\ntarget/\n\n# Go / PHP / Ruby vendored deps\nvendor/\n.bundle/\n\n# Java / Kotlin / Scala\n.gradle/\n\n# .NET\nbin/\nobj/\n\n# Elixir\n_build/\ndeps/\n\n# Dart / Flutter\n.dart_tool/\n9ebf5fb Initial workspace\nHTTP/2 200 \r\nage: 0\r\ncache-control: private, no-cache, no-store, max-age=0, must-revalidate\r\ncontent-type: text/html; charset=utf-8\r\ndate: Fri, 30 Oct 2026 20:22:50 GMT\r\n---\n<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n",
"type": "text"
}
]
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-8f77895a2d2321fb",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Network works. Let's check whether The New Black has a developer API/SDK. Search for docs: thenewblack.ai/api, developers, docs. Also check npm and PyPI for packages.
cd /tmp && for p in api docs developers developer api-docs pricing; do echo "== /$p"; timeout 12 curl -s -o /dev/null -w "%{http_code}\n" "https://thenewblack.ai/$p"; done== /api
== /api 404 == /docs 404 == /developers 404 == /developer 404 == /api-docs 404 == /pricing 200
Recorded tool call
{
"type": "tool_call",
"seq": 13,
"ts": "2026-10-30T20:22:54.862Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /tmp && for p in api docs developers developer api-docs pricing; do echo \"== /$p\"; timeout 12 curl -s -o /dev/null -w \"%{http_code}\\n\" \"https://thenewblack.ai/$p\"; done"
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-a45587169ff31672",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 16,
"ts": "2026-10-30T20:22:58.916Z",
"turn": 1,
"output": {
"content": [
{
"text": "== /api\n404\n== /docs\n404\n== /developers\n404\n== /developer\n404\n== /api-docs\n404\n== /pricing\n200\n",
"type": "text"
}
]
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-a45587169ff31672",
"is_error": false,
"tool_kind": "shell"
}echo "== npm"; timeout 20 curl -s "https://registry.npmjs.org/-/v1/search?text=the-new-black&size=10" | python3 -c "import json,sys; d=json.load(sys.stdin); [print(o['package']['name'],'|',o['package'].get('description','')[:80]) for o in d.get('objects',[])]"; echo "== pypi"; for n in thenewblack the-new-black tnb-sdk newblack; do timeout 12 curl -s -o /dev/null -w "$n %{http_code}\n" https://pypi.org/pypi/$n/json; done== npm
== npm @thenewblack/cli | The New Black AI from the command line: every fashion workflow of the studio, yo functional-red-black-tree | A fully persistent balanced binary search tree wouter | Minimalist-friendly ~1.5KB router for React @fontsource/archivo-black | Self-host the Archivo Black font in a neatly bundled NPM package. cssom | CSS Object Model implementation and CSS parser input-otp | One-time password input component for React. rrweb-cssom | CSS Object Model implementation and CSS parser playwright-msw | A Mock Service Worker API for Playwright. hasura-cli | A package that automatically installs and wraps Hasura CLI binary in isolated ma wxt | ⚡ Next-gen Web Extension Framework == pypi thenewblack 404 the-new-black 404 tnb-sdk 404 newblack 404
Recorded tool call
{
"type": "tool_call",
"seq": 14,
"ts": "2026-10-30T20:22:54.862Z",
"name": "bash",
"turn": 1,
"input": {
"command": "echo \"== npm\"; timeout 20 curl -s \"https://registry.npmjs.org/-/v1/search?text=the-new-black&size=10\" | python3 -c \"import json,sys; d=json.load(sys.stdin); [print(o['package']['name'],'|',o['package'].get('description','')[:80]) for o in d.get('objects',[])]\"; echo \"== pypi\"; for n in thenewblack the-new-black tnb-sdk newblack; do timeout 12 curl -s -o /dev/null -w \"$n %{http_code}\\n\" https://pypi.org/pypi/$n/json; done"
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-afdb327aeea2fe84",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 15,
"ts": "2026-10-30T20:22:57.061Z",
"turn": 1,
"output": {
"content": [
{
"text": "== npm\n@thenewblack/cli | The New Black AI from the command line: every fashion workflow of the studio, yo\nfunctional-red-black-tree | A fully persistent balanced binary search tree\nwouter | Minimalist-friendly ~1.5KB router for React\n@fontsource/archivo-black | Self-host the Archivo Black font in a neatly bundled NPM package.\ncssom | CSS Object Model implementation and CSS parser\ninput-otp | One-time password input component for React.\nrrweb-cssom | CSS Object Model implementation and CSS parser\nplaywright-msw | A Mock Service Worker API for Playwright.\nhasura-cli | A package that automatically installs and wraps Hasura CLI binary in isolated ma\nwxt | ⚡ Next-gen Web Extension Framework\n== pypi\nthenewblack 404\nthe-new-black 404\ntnb-sdk 404\nnewblack 404\n",
"type": "text"
}
]
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-afdb327aeea2fe84",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
There's an npm package @thenewblack/cli — "The New Black AI from the command line: every fashion workflow of the studio, yo..." Let's inspect it. Also check if there's an SDK package. Let's fetch package metadata.
timeout 20 curl -s https://registry.npmjs.org/@thenewblack%2Fcli | python3 -c "
import json,sys
d=json.load(sys.stdin)
print('name',d['name']); print('desc',d.get('description'))
print('latest',d['dist-tags'])
v=d['versions'][d['dist-tags']['latest']]
print('bin',v.get('bin')); print('deps',v.get('dependencies')); print('engines',v.get('engines'))
print('homepage',v.get('homepage')); print('repo',v.get('repository'))
print('keywords',v.get('keywords'))
print('readme len',len(d.get('readme','')))
open('/tmp/tnb_readme.md','w').write(d.get('readme',''))
"name @thenewblack/cli
name @thenewblack/cli
desc The New Black AI from the command line: every fashion workflow of the studio, your creations, tech packs, publishing and Mila, your AI agent — one command each, JSON out. Made for AI coding agents and scripts.
latest {'latest': '0.3.3'}
bin {'tnb': 'bin/tnb.js'}
deps None
engines {'node': '>=18.17'}
homepage https://thenewblack.ai/clothing_fashion_api_integrations
repo {'url': 'git+https://github.com/newblackai/tnb-site.git', 'type': 'git', 'directory': 'cli'}
keywords ['fashion', 'ai', 'cli', 'thenewblack', 'virtual-try-on', 'fashion-design', 'agent']
readme len 4468
Recorded tool call
{
"type": "tool_call",
"seq": 19,
"ts": "2026-10-30T20:23:02.078Z",
"name": "bash",
"turn": 1,
"input": {
"command": "timeout 20 curl -s https://registry.npmjs.org/@thenewblack%2Fcli | python3 -c \"\nimport json,sys\nd=json.load(sys.stdin)\nprint('name',d['name']); print('desc',d.get('description'))\nprint('latest',d['dist-tags'])\nv=d['versions'][d['dist-tags']['latest']]\nprint('bin',v.get('bin')); print('deps',v.get('dependencies')); print('engines',v.get('engines'))\nprint('homepage',v.get('homepage')); print('repo',v.get('repository'))\nprint('keywords',v.get('keywords'))\nprint('readme len',len(d.get('readme','')))\nopen('/tmp/tnb_readme.md','w').write(d.get('readme',''))\n\""
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-af1576c07961111c",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 21,
"ts": "2026-10-30T20:23:03.344Z",
"turn": 1,
"output": {
"content": [
{
"text": "name @thenewblack/cli\ndesc The New Black AI from the command line: every fashion workflow of the studio, your creations, tech packs, publishing and Mila, your AI agent — one command each, JSON out. Made for AI coding agents and scripts.\nlatest {'latest': '0.3.3'}\nbin {'tnb': 'bin/tnb.js'}\ndeps None\nengines {'node': '>=18.17'}\nhomepage https://thenewblack.ai/clothing_fashion_api_integrations\nrepo {'url': 'git+https://github.com/newblackai/tnb-site.git', 'type': 'git', 'directory': 'cli'}\nkeywords ['fashion', 'ai', 'cli', 'thenewblack', 'virtual-try-on', 'fashion-design', 'agent']\nreadme len 4468\n",
"type": "text"
}
]
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-af1576c07961111c",
"is_error": false,
"tool_kind": "shell"
}timeout 20 curl -s "https://registry.npmjs.org/-/v1/search?text=thenewblack&size=20" | python3 -c "import json,sys; d=json.load(sys.stdin); [print(o['package']['name'],'|',o['package'].get('description','')[:100]) for o in d.get('objects',[])]"@thenewblack/cli | The New Black AI from the command line: every fashion workflow of the studio, your creations, tech p
@thenewblack/cli | The New Black AI from the command line: every fashion workflow of the studio, your creations, tech p
Recorded tool call
{
"type": "tool_call",
"seq": 20,
"ts": "2026-10-30T20:23:02.078Z",
"name": "bash",
"turn": 1,
"input": {
"command": "timeout 20 curl -s \"https://registry.npmjs.org/-/v1/search?text=thenewblack&size=20\" | python3 -c \"import json,sys; d=json.load(sys.stdin); [print(o['package']['name'],'|',o['package'].get('description','')[:100]) for o in d.get('objects',[])]\""
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-bf0879ed5c58e7d8",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 22,
"ts": "2026-10-30T20:23:03.344Z",
"turn": 1,
"output": {
"content": [
{
"text": "@thenewblack/cli | The New Black AI from the command line: every fashion workflow of the studio, your creations, tech p\n",
"type": "text"
}
]
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-bf0879ed5c58e7d8",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
There is a CLI package. Let's read the readme. Also the homepage: thenewblack.ai/clothing_fashion_api_integrations — that's their API integration page. Let's read both.
✓read /tmp/tnb_readme.md✓└{"content":[{"text":"# @thenewblack/cli — `tnb`\n\n[The New Black AI](https://thenewblack.ai) from the command line: every fashion workflow of the studio (desig…ctrl+o
{"content":[{"text":"# @thenewblack/cli — `tnb`\n\n[The New Black AI](https://thenewblack.ai) from the command line: every fashion workflow of the studio (design, product-to-model, virtual try-on, fabric, sketch, video, HD), your creations, tech packs, publishing to Shopify and social accounts, and Mila, the account's AI agent. One command each, JSON out. Made for AI coding agents (Claude Code, Codex, Cursor…), scripts, crons and CI.\n\n```sh\nnpx @thenewblack/cli --help # nothing to install\nnpm install -g @thenewblack/cli # or keep it: `tnb`\n```\n\nNode 18.17 or newer. No dependencies.\n\n## The key\n\n```sh\ntnb login # opens your profile's API tab, asks for the key, keeps it (config dir, mode 600)\nexport TNB_API_KEY=tnb_live_… # or: the environment wins — for a cron, a CI job, a container\ntnb whoami\n```\n\nKeys are created in your profile, API tab (up to three, each with scopes: `read`, `generate`, `publish`, `agents` — the last one to talk to Mila). Without a key, `tnb workflows` and every `--help` still work.\n\n## Generate\n\n```sh\ntnb workflows # every workflow, with prices — read live from the catalogue\ntnb generate virtual_try_on --help # the flags of one workflow, read live\ntnb generate virtual_try_on \\\n --product_images dress.jpg belt.jpg --model_image model.jpg \\\n --seg_camera slightly_above --ratio 4:5 --tier pro \\\n --wait --out ./renders/\n# → {\"generation_id\":\"…\",\"status\":\"succeeded\",\"workflow\":\"virtual_try_on\",\"url\":\"https://…\",\"type\":\"image\",\"file\":\"renders/dress-virtual_try_on.webp\"}\n```\n\n- Pictures are **local files or https urls**. A local file is uploaded once and remembered (path, size, date), so tomorrow's run re-uploads nothing.\n- `--wait` polls until the generation settles; `--out dir/` saves the result with a readable name (`<first input>-<workflow>.<ext>`), `--out file.webp` saves it there. Without `--wait`, the answer is the id and `tnb status <id> --wait` picks it up later.\n- Results live 48 hours on our url. Save them.\n- Credits are debited at submission and refunded on failure; `402 insufficient_credits` means the account needs topping up.\n- Text-only workflows take `--prompt`; guided ones take the catalogue's `--<field>` flags; video ones take `--duration` and, for some, `--end-image`.\n\nA folder, one line each:\n\n```sh\nfor f in ./products/*.jpg; do tnb generate product_to_model --product_images \"$f\" --prompt \"studio light, neutral background\" --wait --out ./renders/; done\n```\n\n## Everything else\n\n```\ntnb credits · account · ledger · invoices · brand-dna [read <id>]\ntnb media [--project id] · elements · projects · upload <files…>\ntnb techpacks · techpack <id> · techpack pdf <id> · techpack rename <id> --name …\ntnb techpack add-section <id> --page <page_id> --kind bom [--at 0]\ntnb techpack write-section <id> <section_id> --data '<json>' | --data @file.json\ntnb techpack from-photos front.jpg [--back back.jpg] [--sketch front] [--size-range XS-XL] [--unit cm]\ntnb moodboards · moodboard pdf <id>\ntnb shopify products · shopify publish --product <id> --media <media_id>\ntnb publish accounts · publish --account <connection_id> --placement <placement> --media <media_id> [--caption …] · post <id>\ntnb mila · mila send \"message\" [--media …] · mila thread [--since …] · mila stop\ntnb mila schedules · mila schedule \"request\" --kind single --date 2026-10-01 --time 09:30 · mila unschedule <schedule_id>\ntnb files [--query …] · file <id|path> [--page 2] · file describe <id> --description \"…\"\n```\n\n`tnb <command> --help` prints the flags; `--pretty` indents the JSON. Exit codes: `0` done, `1` the platform or the network refused (the JSON error is on stderr, with the platform's own `code`), `2` the command line was wrong.\n\n## For an AI agent\n\nInstall it, run `tnb --help`, then `tnb generate <key> --help` for the workflow you need — the help is the live contract. Read the JSON, keep the ids, save the files. The full API reference is at https://thenewblack.ai/clothing_fashion_api_integrations and the Claude skill at https://github.com/newblackai/claude-skill.\n\n## Configuration\n\n| Variable | Meaning |\n|---|---|\n| `TNB_API_KEY` | The key; wins over the one kept by `tnb login`. |\n| `TNB_API_URL` | The API base (default `https://thenewblack.ai/api/v1`). |\n| `TNB_CONFIG_DIR` | Where the key is kept (default `~/.config/tnb`, `%APPDATA%\\tnb` on Windows). |\n| `TNB_CACHE_DIR` | Where uploaded files are remembered (default `~/.cache/tnb`). |\n\nMIT.\n","type":"text"}]}timeout 20 curl -s https://thenewblack.ai/clothing_fashion_api_integrations | python3 -c " import sys,re,html t=sys.stdin.read() t=re.sub(r'<script.*?</script>','',t,flags=re.S) t=re.sub(r'<style.*?</style>','',t,flags=re.S) t=re.sub(r'<[^>]+>',' ',t) t=html.unescape(t) t=re.sub(r'[ \t]+',' ',t) t=re.sub(r'\n\s*\n+','\n',t) print(t[:6000])"
AI Fashion Clothing API | The New Black AI The New Black AI T he N ew B lack AI he ew lack API / MCP / CLI Pricing Tutorials Log in Start free The New Black AI
AI Fashion Clothing API | The New Black AI The New Black AI T he N ew B lack AI he ew lack API / MCP / CLI Pricing Tutorials Log in Start free The New Black AI Start AI Fashion Clothing API Generate AI fashion visuals from your own product with a REST API, or straight from Claude or ChatGPT with our MCP. Every workflow of the studio, one endpoint. Get an API key MCP Claude skill API REST, for your code MCP for a conversation with Claude or ChatGPT CLI for a project of code, a script, an agent Endpoints Workflows catalogue (77) Publishing catalogue (5) Creations catalogue (4) Account (6) Tech packs (9) Mila - AI Agent (10) Fixed routes (39) Guide Introduction Authentication Errors Rate limits Create a generation Retrieve a generation Webhooks Credits MCP Command line Migrating from the legacy API Status GET /v1/workflows Workflows catalogue ( 77 ) Every studio workflow is callable by its versioned endpoint name. The route returns the live catalogue — named image parameters, fields, variants, formats and prices; the table below is rendered from the same data. Method Workflow key Title Mode Standard Pro Ultra Max refs POST freeform_image-v1 Free Prompt Image image 1 cr 3 cr 7 cr 3 POST freeform_video-v1 Free Prompt Video video 2.2 cr/s 4.4 cr/s 23 cr/s 1 POST virtual_try_on-v1 Virtual Try-On image 1 cr 3 cr 7 cr 5 POST product_to_model-v1 Product to Model image 1 cr 3 cr 7 cr 5 POST image_to_ghost_mannequin-v1 Image to Ghost Mannequin image 1 cr 3 cr 7 cr 1 POST change_color-v1 Change a Color image 1 cr 3 cr 7 cr 1 POST create_design-v1 Create a Product image 1 cr 3 cr 7 cr 3 POST enhance_photo_to_hd-v1 Enhance Photo to HD (2K/4K) image 1 cr 3 cr — 3 POST retouch-v1 Edit an Area image 1 cr 3 cr — 16 POST reimagine_scene-v1 Reimagine your Model image 1 cr 3 cr 7 cr 1 POST edit_video-v1 Edit video video 3.3 cr/s 4.3 cr/s — 1 POST motion_design-v1 Motion Design video 4 cr 4 cr — 4 POST model_walk-v1 Model Walk video 2.2 cr/s 4.4 cr/s 23 cr/s 1 POST product_360-v1 Product 360 video 2.2 cr/s 4.4 cr/s 23 cr/s 3 POST model_360-v1 Model 360 video 2.2 cr/s 4.4 cr/s 23 cr/s 2 POST swap_models-v1 Swap Model image 1 cr 3 cr 7 cr 1 POST face_swap-v1 Face Swap image 1 cr 1 cr — 2 POST fabric_to_design-v1 Fabric to Image image 1 cr 3 cr 7 cr 1 POST image_to_fabric-v1 Image to Fabric image 1 cr 3 cr 7 cr 1 POST text_to_textile-v1 Text to Textile image 1 cr 3 cr 7 cr 3 POST snap_freeze-v1 Snap Freeze video 2.2 cr/s 4.4 cr/s 23 cr/s 3 POST ugc_video-v1 UGC Video video 2.2 cr/s 4.4 cr/s 23 cr/s 3 POST image_to_flat_lay-v1 Image to Flat Lay image 1 cr 3 cr 7 cr 1 POST swap_fabrics-v1 Swap Fabrics image 1 cr 3 cr 7 cr 2 POST logo_placement-v1 Add a Logo image 1 cr 3 cr — 3 POST text_to_sketch-v1 Text to Sketch image 1 cr 3 cr 7 cr 3 POST sketch_to_image-v1 Sketch to Image image 1 cr 3 cr — 1 POST image_to_sketch-v1 Image to Sketch image 1 cr 3 cr 7 cr 2 POST sketch_to_svg-v1 Sketch to SVG image 1 cr 1 cr — 1 POST vectorize_image-v1 Vectorize Prints & Logos image 1 cr 1 cr — 1 POST insert_fabric_on_sketch-v1 Insert Fabric on Sketch image 1 cr 3 cr 7 cr 2 POST create_similar_outfits-v1 Create Similar Outfits image 1 cr 3 cr 7 cr 1 POST create_design_variations-v1 Create Design Variations image 1 cr 3 cr 7 cr 1 POST change_background-v1 Change Background image 1 cr 3 cr — 2 POST remove_background-v1 Remove Background image 0.5 cr 0.5 cr — 1 POST ad_creative-v1 Ad Creative image 1 cr 3 cr 7 cr 2 POST enhance_video_to_hd-v1 Enhance Video to HD video 4.4 cr/s 4.4 cr/s — 3 POST ai_stylist-v1 AI Stylist image 1 cr 3 cr 7 cr 1 POST outpaint_new_ratio-v1 Expand Image image 1 cr 1 cr — 1 POST create_3d_models-v1 Image to 3D 3d 10 cr 10 cr — 1 POST tryon_video-v1 Virtual Try-On Video video 2.2 cr/s 4.4 cr/s 23 cr/s 2 POST outfit_transition-v1 Outfit Transition video 2.2 cr/s 4.4 cr/s 23 cr/s 2 POST fashion_ad-v1 Fashion Ad video 2.2 cr/s 4.4 cr/s 23 cr/s 3 POST detail_closeup-v1 Detail Close-up video 2.2 cr/s 4.4 cr/s 23 cr/s 1 POST editorial_video-v1 Editorial Lookbook video 2.2 cr/s 4.4 cr/s 23 cr/s 1 POST outfit_drop-v1 Outfit Drop video 2.2 cr/s 4.4 cr/s 23 cr/s 3 POST remove_video_background-v1 Remove Video Background video 1.4 cr/s 1.4 cr/s — 1 POST reframe_video-v1 Reframe Video video 4.4 cr/s 4.4 cr/s — 1 POST passerby_transition-v1 Passer-By Transition video 2.2 cr/s 4.4 cr/s 23 cr/s 3 POST crosswalk_look_switch-v1 Look Switch Walk video 2.2 cr/s 4.4 cr/s 23 cr/s 3 POST change_video_background-v1 Change Video Background video 4.4 cr/s 8.8 cr/s — 1 POST change_video_outfit-v1 Edit Outfit in Video video 3.3 cr/s 4.3 cr/s — 1 POST swap_video_model-v1 Swap Model in Video video 3.3 cr/s 4.3 cr/s — 2 POST hanger_layering-v1 Hanger Switch video 2.2 cr/s 4.4 cr/s 23 cr/s 5 POST window_walkby-v1 Window Walk-By video 2.2 cr/s 4.4 cr/s 23 cr/s 3 POST detail_zoom_rush-v1 Detail Zoom Rush video 2.2 cr/s 4.4 cr/s 23 cr/s 1 POST outfit_morph-v1 Outfit Morph video 2.2 cr/s 4.4 cr/s 23 cr/s 4 POST freeform_audio-v1 Create a Soundtrack audio 2 cr 2 cr — 1 POST voice_over-v1 Create a Voice-over audio 1.06 cr/1k chars 2.12 cr/1k chars 2.12 cr/1k chars 3 POST motion_collection_panorama-v1 Collection Panorama video 1 cr 1 cr — 6 POST motion_split_reel-v1 Split Reel video 1 cr 1 cr — 4 POST motion_style_post-v1 Style Post video 1 cr 1 cr — 1 POST motion_look_film-v1 Look Film video 1 cr 1 cr — 4 POST motion_colour_drop-v1 Colour Drop video 1 cr 1 cr — 4 POST motion_phone_promo-v1 Phone Promo video 1 cr 1 cr — 4 POST motion_cut_montage-v1 Cut Montage video 1 cr 1 cr — 6 POST motion_paper_collage-v1 Paper Collage video 1 cr 1 cr — 8 POST motion_lineup-v1 Lineup video 1 cr 1 cr — 6 POST motion_character_select-v1 Character Select video 1 cr 1 cr — 6 POST motion_grid_mosaic-v1 Grid Mosaic video 1 cr 1 cr — 2 POST motion_ways_to_wear-v1 Ways to Wear video 1 cr 1 cr — 6 POST motion_detail_study-v1 Detail Study video 1 cr 1 cr — 3 POST motion_signature_film-v1 Signature Film video 1 cr 1 cr — 4 POST motion_outfit_picker-v1 Outfit Picker video
Recorded tool call
{
"type": "tool_call",
"seq": 26,
"ts": "2026-10-30T20:23:07.719Z",
"name": "bash",
"turn": 1,
"input": {
"command": "timeout 20 curl -s https://thenewblack.ai/clothing_fashion_api_integrations | python3 -c \"\nimport sys,re,html\nt=sys.stdin.read()\nt=re.sub(r'<script.*?</script>','',t,flags=re.S)\nt=re.sub(r'<style.*?</style>','',t,flags=re.S)\nt=re.sub(r'<[^>]+>',' ',t)\nt=html.unescape(t)\nt=re.sub(r'[ \\t]+',' ',t)\nt=re.sub(r'\\n\\s*\\n+','\\n',t)\nprint(t[:6000])\""
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-8bca1936c40fd06f",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 28,
"ts": "2026-10-30T20:23:09.104Z",
"turn": 1,
"output": {
"content": [
{
"text": " AI Fashion Clothing API | The New Black AI The New Black AI T he N ew B lack AI he ew lack API / MCP / CLI Pricing Tutorials Log in Start free The New Black AI Start AI Fashion Clothing API Generate AI fashion visuals from your own product with a REST API, or straight from Claude or ChatGPT with our MCP. Every workflow of the studio, one endpoint. Get an API key MCP Claude skill API REST, for your code MCP for a conversation with Claude or ChatGPT CLI for a project of code, a script, an agent Endpoints Workflows catalogue (77) Publishing catalogue (5) Creations catalogue (4) Account (6) Tech packs (9) Mila - AI Agent (10) Fixed routes (39) Guide Introduction Authentication Errors Rate limits Create a generation Retrieve a generation Webhooks Credits MCP Command line Migrating from the legacy API Status GET /v1/workflows Workflows catalogue ( 77 ) Every studio workflow is callable by its versioned endpoint name. The route returns the live catalogue — named image parameters, fields, variants, formats and prices; the table below is rendered from the same data. Method Workflow key Title Mode Standard Pro Ultra Max refs POST freeform_image-v1 Free Prompt Image image 1 cr 3 cr 7 cr 3 POST freeform_video-v1 Free Prompt Video video 2.2 cr/s 4.4 cr/s 23 cr/s 1 POST virtual_try_on-v1 Virtual Try-On image 1 cr 3 cr 7 cr 5 POST product_to_model-v1 Product to Model image 1 cr 3 cr 7 cr 5 POST image_to_ghost_mannequin-v1 Image to Ghost Mannequin image 1 cr 3 cr 7 cr 1 POST change_color-v1 Change a Color image 1 cr 3 cr 7 cr 1 POST create_design-v1 Create a Product image 1 cr 3 cr 7 cr 3 POST enhance_photo_to_hd-v1 Enhance Photo to HD (2K/4K) image 1 cr 3 cr — 3 POST retouch-v1 Edit an Area image 1 cr 3 cr — 16 POST reimagine_scene-v1 Reimagine your Model image 1 cr 3 cr 7 cr 1 POST edit_video-v1 Edit video video 3.3 cr/s 4.3 cr/s — 1 POST motion_design-v1 Motion Design video 4 cr 4 cr — 4 POST model_walk-v1 Model Walk video 2.2 cr/s 4.4 cr/s 23 cr/s 1 POST product_360-v1 Product 360 video 2.2 cr/s 4.4 cr/s 23 cr/s 3 POST model_360-v1 Model 360 video 2.2 cr/s 4.4 cr/s 23 cr/s 2 POST swap_models-v1 Swap Model image 1 cr 3 cr 7 cr 1 POST face_swap-v1 Face Swap image 1 cr 1 cr — 2 POST fabric_to_design-v1 Fabric to Image image 1 cr 3 cr 7 cr 1 POST image_to_fabric-v1 Image to Fabric image 1 cr 3 cr 7 cr 1 POST text_to_textile-v1 Text to Textile image 1 cr 3 cr 7 cr 3 POST snap_freeze-v1 Snap Freeze video 2.2 cr/s 4.4 cr/s 23 cr/s 3 POST ugc_video-v1 UGC Video video 2.2 cr/s 4.4 cr/s 23 cr/s 3 POST image_to_flat_lay-v1 Image to Flat Lay image 1 cr 3 cr 7 cr 1 POST swap_fabrics-v1 Swap Fabrics image 1 cr 3 cr 7 cr 2 POST logo_placement-v1 Add a Logo image 1 cr 3 cr — 3 POST text_to_sketch-v1 Text to Sketch image 1 cr 3 cr 7 cr 3 POST sketch_to_image-v1 Sketch to Image image 1 cr 3 cr — 1 POST image_to_sketch-v1 Image to Sketch image 1 cr 3 cr 7 cr 2 POST sketch_to_svg-v1 Sketch to SVG image 1 cr 1 cr — 1 POST vectorize_image-v1 Vectorize Prints & Logos image 1 cr 1 cr — 1 POST insert_fabric_on_sketch-v1 Insert Fabric on Sketch image 1 cr 3 cr 7 cr 2 POST create_similar_outfits-v1 Create Similar Outfits image 1 cr 3 cr 7 cr 1 POST create_design_variations-v1 Create Design Variations image 1 cr 3 cr 7 cr 1 POST change_background-v1 Change Background image 1 cr 3 cr — 2 POST remove_background-v1 Remove Background image 0.5 cr 0.5 cr — 1 POST ad_creative-v1 Ad Creative image 1 cr 3 cr 7 cr 2 POST enhance_video_to_hd-v1 Enhance Video to HD video 4.4 cr/s 4.4 cr/s — 3 POST ai_stylist-v1 AI Stylist image 1 cr 3 cr 7 cr 1 POST outpaint_new_ratio-v1 Expand Image image 1 cr 1 cr — 1 POST create_3d_models-v1 Image to 3D 3d 10 cr 10 cr — 1 POST tryon_video-v1 Virtual Try-On Video video 2.2 cr/s 4.4 cr/s 23 cr/s 2 POST outfit_transition-v1 Outfit Transition video 2.2 cr/s 4.4 cr/s 23 cr/s 2 POST fashion_ad-v1 Fashion Ad video 2.2 cr/s 4.4 cr/s 23 cr/s 3 POST detail_closeup-v1 Detail Close-up video 2.2 cr/s 4.4 cr/s 23 cr/s 1 POST editorial_video-v1 Editorial Lookbook video 2.2 cr/s 4.4 cr/s 23 cr/s 1 POST outfit_drop-v1 Outfit Drop video 2.2 cr/s 4.4 cr/s 23 cr/s 3 POST remove_video_background-v1 Remove Video Background video 1.4 cr/s 1.4 cr/s — 1 POST reframe_video-v1 Reframe Video video 4.4 cr/s 4.4 cr/s — 1 POST passerby_transition-v1 Passer-By Transition video 2.2 cr/s 4.4 cr/s 23 cr/s 3 POST crosswalk_look_switch-v1 Look Switch Walk video 2.2 cr/s 4.4 cr/s 23 cr/s 3 POST change_video_background-v1 Change Video Background video 4.4 cr/s 8.8 cr/s — 1 POST change_video_outfit-v1 Edit Outfit in Video video 3.3 cr/s 4.3 cr/s — 1 POST swap_video_model-v1 Swap Model in Video video 3.3 cr/s 4.3 cr/s — 2 POST hanger_layering-v1 Hanger Switch video 2.2 cr/s 4.4 cr/s 23 cr/s 5 POST window_walkby-v1 Window Walk-By video 2.2 cr/s 4.4 cr/s 23 cr/s 3 POST detail_zoom_rush-v1 Detail Zoom Rush video 2.2 cr/s 4.4 cr/s 23 cr/s 1 POST outfit_morph-v1 Outfit Morph video 2.2 cr/s 4.4 cr/s 23 cr/s 4 POST freeform_audio-v1 Create a Soundtrack audio 2 cr 2 cr — 1 POST voice_over-v1 Create a Voice-over audio 1.06 cr/1k chars 2.12 cr/1k chars 2.12 cr/1k chars 3 POST motion_collection_panorama-v1 Collection Panorama video 1 cr 1 cr — 6 POST motion_split_reel-v1 Split Reel video 1 cr 1 cr — 4 POST motion_style_post-v1 Style Post video 1 cr 1 cr — 1 POST motion_look_film-v1 Look Film video 1 cr 1 cr — 4 POST motion_colour_drop-v1 Colour Drop video 1 cr 1 cr — 4 POST motion_phone_promo-v1 Phone Promo video 1 cr 1 cr — 4 POST motion_cut_montage-v1 Cut Montage video 1 cr 1 cr — 6 POST motion_paper_collage-v1 Paper Collage video 1 cr 1 cr — 8 POST motion_lineup-v1 Lineup video 1 cr 1 cr — 6 POST motion_character_select-v1 Character Select video 1 cr 1 cr — 6 POST motion_grid_mosaic-v1 Grid Mosaic video 1 cr 1 cr — 2 POST motion_ways_to_wear-v1 Ways to Wear video 1 cr 1 cr — 6 POST motion_detail_study-v1 Detail Study video 1 cr 1 cr — 3 POST motion_signature_film-v1 Signature Film video 1 cr 1 cr — 4 POST motion_outfit_picker-v1 Outfit Picker video\n",
"type": "text"
}
]
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-8bca1936c40fd06f",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Good — there IS a real developer workflow: REST API at https://thenewblack.ai/api/v1, a CLI (npx @thenewblack/cli), MCP, and a Claude skill.
The task: "build a simple example using The New Black AI. Tell me how pricing works, and briefly tell me whether this product will be easy for you to manage." Stay light: use the hosted product through SDK or API. No local stacks, no long-running commands.
We need an API key (TNB_API_KEY) which we don't have. Let's check what works without a key: tnb workflows and --help. Also the API guide pages for pricing (credits), rate limits, etc.
Plan:
- Read the API guide pages (introduction, authentication, errors, rate limits, create a generation, retrieve a generation, webhooks, credits, command line) to learn the contract.
- Install/run the CLI via npx (quick, no long-running).
- Build a simple example in the repo: a small script (bash or Node) that uses the API/CLI. Since no API key exists, the example should work against the live catalogue unauthenticated where possible (tnb workflows works without key), and be ready for a key.
- Report pricing (credits, tiers) and manageability assessment.
Let's fetch the guide pages. URLs likely https://thenewblack.ai/clothing_fashion_api_integrations#... or separate routes. Let me check the nav links in HTML.
timeout 20 curl -s https://thenewblack.ai/clothing_fashion_api_integrations | grep -oE 'href="[^"]+"' | sort -u | head -60
href="#account"
href="#account" href="#agents" href="#authentication" href="#cli" href="#creations" href="#credits" href="#endpoints" href="#errors" href="#generate" href="#introduction" href="#legacy" href="#limits" href="#mcp" href="#publishing" href="#retrieve" href="#techpacks" href="#webhooks" href="#workflows" href="/" href="/_next/static/chunks/1kw7gp-u2o2z8.js?dpl=dpl_7K6dkycLhdzDQNfCmcpgTpG3UJ3j" href="/_next/static/chunks/2t-vx1m9ct447.css?dpl=dpl_7K6dkycLhdzDQNfCmcpgTpG3UJ3j" href="/_next/static/chunks/3g-5cr3co5boh.css?dpl=dpl_7K6dkycLhdzDQNfCmcpgTpG3UJ3j" href="/about_us" href="/affiliate_program" href="/ai-agent-for-fashion-brands" href="/ai-clothing-fashion-design-generator" href="/ai-design-features" href="/ai-design-features/ai-fashion-video-generator" href="/ai-design-features/create-ai-clothing-designs" href="/ai-design-features/generate-ai-fashion-in-bulk" href="/ai-generated-models" href="/ai-logo-ai-moodboard-generator-for-brands" href="/ai-lookbook" href="/ai-outfit-generator-coach-assistant-stylist" href="/ai-virtual-try-on-clothes" href="/api/v1/openapi.json" href="/app_privacy_policy" href="/blog" href="/blog/ai-agents-for-fashion-brands-guide" href="/clothing-fashion-techpack" href="/clothing_fashion_api_integrations" href="/clothing_fashion_api_integrations/ad-creative-api" href="/clothing_fashion_api_integrations/ai-generated-models-api" href="/clothing_fashion_api_integrations/ai-stylist-api" href="/clothing_fashion_api_integrations/ai-video" href="/clothing_fashion_api_integrations/change-background-api" href="/clothing_fashion_api_integrations/change-fabric-on-clothes-api" href="/clothing_fashion_api_integrations/change-video-background-api" href="/clothing_fashion_api_integrations/cli" href="/clothing_fashion_api_integrations/clothing-image-to-flat-sketch" href="/clothing_fashion_api_integrations/color-change-api" href="/clothing_fashion_api_integrations/create-edit-image-api" href="/clothing_fashion_api_integrations/crosswalk-look-switch-api" href="/clothing_fashion_api_integrations/detail-closeup-video-api" href="/clothing_fashion_api_integrations/detail-zoom-rush-api" href="/clothing_fashion_api_integrations/edit-photo-api" href="/clothing_fashion_api_integrations/edit-video-api" href="/clothing_fashion_api_integrations/edit-video-outfit-api" href="/clothing_fashion_api_integrations/editorial-lookbook-video-api" href="/clothing_fashion_api_integrations/enhance-photo-hd-api"
Recorded tool call
{
"type": "tool_call",
"seq": 31,
"ts": "2026-10-30T20:23:14.200Z",
"name": "bash",
"turn": 1,
"input": {
"command": "timeout 20 curl -s https://thenewblack.ai/clothing_fashion_api_integrations | grep -oE 'href=\"[^\"]+\"' | sort -u | head -60"
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-a451ab9ec8d3a776",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 34,
"ts": "2026-10-30T20:23:15.268Z",
"turn": 1,
"output": {
"content": [
{
"text": "href=\"#account\"\nhref=\"#agents\"\nhref=\"#authentication\"\nhref=\"#cli\"\nhref=\"#creations\"\nhref=\"#credits\"\nhref=\"#endpoints\"\nhref=\"#errors\"\nhref=\"#generate\"\nhref=\"#introduction\"\nhref=\"#legacy\"\nhref=\"#limits\"\nhref=\"#mcp\"\nhref=\"#publishing\"\nhref=\"#retrieve\"\nhref=\"#techpacks\"\nhref=\"#webhooks\"\nhref=\"#workflows\"\nhref=\"/\"\nhref=\"/_next/static/chunks/1kw7gp-u2o2z8.js?dpl=dpl_7K6dkycLhdzDQNfCmcpgTpG3UJ3j\"\nhref=\"/_next/static/chunks/2t-vx1m9ct447.css?dpl=dpl_7K6dkycLhdzDQNfCmcpgTpG3UJ3j\"\nhref=\"/_next/static/chunks/3g-5cr3co5boh.css?dpl=dpl_7K6dkycLhdzDQNfCmcpgTpG3UJ3j\"\nhref=\"/about_us\"\nhref=\"/affiliate_program\"\nhref=\"/ai-agent-for-fashion-brands\"\nhref=\"/ai-clothing-fashion-design-generator\"\nhref=\"/ai-design-features\"\nhref=\"/ai-design-features/ai-fashion-video-generator\"\nhref=\"/ai-design-features/create-ai-clothing-designs\"\nhref=\"/ai-design-features/generate-ai-fashion-in-bulk\"\nhref=\"/ai-generated-models\"\nhref=\"/ai-logo-ai-moodboard-generator-for-brands\"\nhref=\"/ai-lookbook\"\nhref=\"/ai-outfit-generator-coach-assistant-stylist\"\nhref=\"/ai-virtual-try-on-clothes\"\nhref=\"/api/v1/openapi.json\"\nhref=\"/app_privacy_policy\"\nhref=\"/blog\"\nhref=\"/blog/ai-agents-for-fashion-brands-guide\"\nhref=\"/clothing-fashion-techpack\"\nhref=\"/clothing_fashion_api_integrations\"\nhref=\"/clothing_fashion_api_integrations/ad-creative-api\"\nhref=\"/clothing_fashion_api_integrations/ai-generated-models-api\"\nhref=\"/clothing_fashion_api_integrations/ai-stylist-api\"\nhref=\"/clothing_fashion_api_integrations/ai-video\"\nhref=\"/clothing_fashion_api_integrations/change-background-api\"\nhref=\"/clothing_fashion_api_integrations/change-fabric-on-clothes-api\"\nhref=\"/clothing_fashion_api_integrations/change-video-background-api\"\nhref=\"/clothing_fashion_api_integrations/cli\"\nhref=\"/clothing_fashion_api_integrations/clothing-image-to-flat-sketch\"\nhref=\"/clothing_fashion_api_integrations/color-change-api\"\nhref=\"/clothing_fashion_api_integrations/create-edit-image-api\"\nhref=\"/clothing_fashion_api_integrations/crosswalk-look-switch-api\"\nhref=\"/clothing_fashion_api_integrations/detail-closeup-video-api\"\nhref=\"/clothing_fashion_api_integrations/detail-zoom-rush-api\"\nhref=\"/clothing_fashion_api_integrations/edit-photo-api\"\nhref=\"/clothing_fashion_api_integrations/edit-video-api\"\nhref=\"/clothing_fashion_api_integrations/edit-video-outfit-api\"\nhref=\"/clothing_fashion_api_integrations/editorial-lookbook-video-api\"\nhref=\"/clothing_fashion_api_integrations/enhance-photo-hd-api\"\n",
"type": "text"
}
]
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-a451ab9ec8d3a776",
"is_error": false,
"tool_kind": "shell"
}cd /tmp && timeout 25 curl -s https://thenewblack.ai/api/v1/workflows -o w.json -w "%{http_code}\n"; head -c 600 w.json; echo401
401
{"error":{"code":"missing_key","message":"Send your API key as: Authorization: Bearer tnb_live_..."}}
Recorded tool call
{
"type": "tool_call",
"seq": 32,
"ts": "2026-10-30T20:23:14.200Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /tmp && timeout 25 curl -s https://thenewblack.ai/api/v1/workflows -o w.json -w \"%{http_code}\\n\"; head -c 600 w.json; echo"
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-8a1fab366af2a9cf",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 33,
"ts": "2026-10-30T20:23:14.505Z",
"turn": 1,
"output": {
"content": [
{
"text": "401\n{\"error\":{\"code\":\"missing_key\",\"message\":\"Send your API key as: Authorization: Bearer tnb_live_...\"}}\n",
"type": "text"
}
]
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-8a1fab366af2a9cf",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
There's an OpenAPI spec: /api/v1/openapi.json — but it 401'd? No, that was /api/v1/workflows. Let's try openapi.json.
Also extract the guide sections text (credits, authentication, errors, limits, generate, retrieve, webhooks) from the page HTML.
cd /tmp && timeout 25 curl -s -o openapi.json -w "%{http_code}\n" https://thenewblack.ai/api/v1/openapi.json; python3 -c "
import json;d=json.load(open('openapi.json'));print(d['info']);print(len(d['paths']));print(list(d['paths'])[:40])" 2>&1|head -20200
200
{'title': 'The New Black AI — API', 'version': '1', 'description': "Generate AI fashion visuals from your own products, read and write the account's creations and tech packs, publish to Shopify and social accounts, and make Mila, the account's AI agent, work for you.\n\nThis document is assembled at the instant of the call: the fixed routes from their descriptions in the code, the workflows from the live catalogue. It is the source the docs page, the `tnb` CLI, the MCP connector and any agent read.\n\nHuman documentation: https://thenewblack.ai/clothing_fashion_api_integrations", 'contact': {'name': 'The New Black AI', 'url': 'https://thenewblack.ai/clothing_fashion_api_integrations', 'email': 'team@thenewblack.ai'}, 'license': {'name': 'Terms of service', 'url': 'https://thenewblack.ai/terms_of_service'}, 'termsOfService': 'https://thenewblack.ai/terms_of_service', 'x-generated-at': '2026-10-30T20:22:33.114Z', 'x-workflows-revision': '870852d33bdc5fb6', 'x-openapi-revision': '80cf958128362350'}
36
['/openapi.json', '/catalog', '/catalog/presets', '/workflows', '/generate', '/generations/{id}', '/credits', '/account', '/account/invoices', '/ledger', '/brand-dna', '/brand-dna/{id}', '/media', '/media/upload', '/elements', '/projects', '/techpacks', '/techpacks/{id}', '/techpacks/{id}/pdf', '/techpacks/{id}/sections', '/techpacks/{id}/sections/{sectionId}', '/techpacks/from-photos', '/moodboards', '/moodboards/{id}/pdf', '/shopify/products', '/shopify/publish', '/publish/accounts', '/publish', '/publish/{id}', '/mila', '/mila/messages', '/mila/stop', '/mila/schedules', '/mila/schedules/{scheduleId}', '/files', '/files/{id}']
Recorded tool call
{
"type": "tool_call",
"seq": 37,
"ts": "2026-10-30T20:23:19.284Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /tmp && timeout 25 curl -s -o openapi.json -w \"%{http_code}\\n\" https://thenewblack.ai/api/v1/openapi.json; python3 -c \"\nimport json;d=json.load(open('openapi.json'));print(d['info']);print(len(d['paths']));print(list(d['paths'])[:40])\" 2>&1|head -20"
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-822a3638526356b7",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 39,
"ts": "2026-10-30T20:23:20.135Z",
"turn": 1,
"output": {
"content": [
{
"text": "200\n{'title': 'The New Black AI — API', 'version': '1', 'description': \"Generate AI fashion visuals from your own products, read and write the account's creations and tech packs, publish to Shopify and social accounts, and make Mila, the account's AI agent, work for you.\\n\\nThis document is assembled at the instant of the call: the fixed routes from their descriptions in the code, the workflows from the live catalogue. It is the source the docs page, the `tnb` CLI, the MCP connector and any agent read.\\n\\nHuman documentation: https://thenewblack.ai/clothing_fashion_api_integrations\", 'contact': {'name': 'The New Black AI', 'url': 'https://thenewblack.ai/clothing_fashion_api_integrations', 'email': 'team@thenewblack.ai'}, 'license': {'name': 'Terms of service', 'url': 'https://thenewblack.ai/terms_of_service'}, 'termsOfService': 'https://thenewblack.ai/terms_of_service', 'x-generated-at': '2026-10-30T20:22:33.114Z', 'x-workflows-revision': '870852d33bdc5fb6', 'x-openapi-revision': '80cf958128362350'}\n36\n['/openapi.json', '/catalog', '/catalog/presets', '/workflows', '/generate', '/generations/{id}', '/credits', '/account', '/account/invoices', '/ledger', '/brand-dna', '/brand-dna/{id}', '/media', '/media/upload', '/elements', '/projects', '/techpacks', '/techpacks/{id}', '/techpacks/{id}/pdf', '/techpacks/{id}/sections', '/techpacks/{id}/sections/{sectionId}', '/techpacks/from-photos', '/moodboards', '/moodboards/{id}/pdf', '/shopify/products', '/shopify/publish', '/publish/accounts', '/publish', '/publish/{id}', '/mila', '/mila/messages', '/mila/stop', '/mila/schedules', '/mila/schedules/{scheduleId}', '/files', '/files/{id}']\n",
"type": "text"
}
]
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-822a3638526356b7",
"is_error": false,
"tool_kind": "shell"
}cd /tmp && timeout 25 curl -s https://thenewblack.ai/clothing_fashion_api_integrations > page.html && python3 - <<'EOF'
import re,html
t=open('page.html').read()
t=re.sub(r'<script.*?</script>','',t,flags=re.S); t=re.sub(r'<style.*?</style>','',t,flags=re.S)
t=re.sub(r'<[^>]+>','\n',t); t=html.unescape(t)
t=re.sub(r'[ \t]+',' ',t); t=re.sub(r'\n\s*\n+','\n',t)
open('page.txt','w').write(t)
i=t.find('Guide')
print(t[i:i+9000])
EOFGuide
Guide
Introduction
Authentication
Errors
Rate limits
Create a generation
Retrieve a generation
Webhooks
Credits
MCP
Command line
Migrating from the legacy API
Status
GET
/v1/workflows
Workflows catalogue
(
77
)
Every studio workflow is callable by its versioned endpoint name. The route returns the live catalogue — named image parameters, fields, variants, formats and prices; the table below is rendered from the same data.
Method
Workflow key
Title
Mode
Standard
Pro
Ultra
Max refs
POST
freeform_image-v1
Free Prompt Image
image
1 cr
3 cr
7 cr
3
POST
freeform_video-v1
Free Prompt Video
video
2.2 cr/s
4.4 cr/s
23 cr/s
1
POST
virtual_try_on-v1
Virtual Try-On
image
1 cr
3 cr
7 cr
5
POST
product_to_model-v1
Product to Model
image
1 cr
3 cr
7 cr
5
POST
image_to_ghost_mannequin-v1
Image to Ghost Mannequin
image
1 cr
3 cr
7 cr
1
POST
change_color-v1
Change a Color
image
1 cr
3 cr
7 cr
1
POST
create_design-v1
Create a Product
image
1 cr
3 cr
7 cr
3
POST
enhance_photo_to_hd-v1
Enhance Photo to HD (2K/4K)
image
1 cr
3 cr
—
3
POST
retouch-v1
Edit an Area
image
1 cr
3 cr
—
16
POST
reimagine_scene-v1
Reimagine your Model
image
1 cr
3 cr
7 cr
1
POST
edit_video-v1
Edit video
video
3.3 cr/s
4.3 cr/s
—
1
POST
motion_design-v1
Motion Design
video
4 cr
4 cr
—
4
POST
model_walk-v1
Model Walk
video
2.2 cr/s
4.4 cr/s
23 cr/s
1
POST
product_360-v1
Product 360
video
2.2 cr/s
4.4 cr/s
23 cr/s
3
POST
model_360-v1
Model 360
video
2.2 cr/s
4.4 cr/s
23 cr/s
2
POST
swap_models-v1
Swap Model
image
1 cr
3 cr
7 cr
1
POST
face_swap-v1
Face Swap
image
1 cr
1 cr
—
2
POST
fabric_to_design-v1
Fabric to Image
image
1 cr
3 cr
7 cr
1
POST
image_to_fabric-v1
Image to Fabric
image
1 cr
3 cr
7 cr
1
POST
text_to_textile-v1
Text to Textile
image
1 cr
3 cr
7 cr
3
POST
snap_freeze-v1
Snap Freeze
video
2.2 cr/s
4.4 cr/s
23 cr/s
3
POST
ugc_video-v1
UGC Video
video
2.2 cr/s
4.4 cr/s
23 cr/s
3
POST
image_to_flat_lay-v1
Image to Flat Lay
image
1 cr
3 cr
7 cr
1
POST
swap_fabrics-v1
Swap Fabrics
image
1 cr
3 cr
7 cr
2
POST
logo_placement-v1
Add a Logo
image
1 cr
3 cr
—
3
POST
text_to_sketch-v1
Text to Sketch
image
1 cr
3 cr
7 cr
3
POST
sketch_to_image-v1
Sketch to Image
image
1 cr
3 cr
—
1
POST
image_to_sketch-v1
Image to Sketch
image
1 cr
3 cr
7 cr
2
POST
sketch_to_svg-v1
Sketch to SVG
image
1 cr
1 cr
—
1
POST
vectorize_image-v1
Vectorize Prints & Logos
image
1 cr
1 cr
—
1
POST
insert_fabric_on_sketch-v1
Insert Fabric on Sketch
image
1 cr
3 cr
7 cr
2
POST
create_similar_outfits-v1
Create Similar Outfits
image
1 cr
3 cr
7 cr
1
POST
create_design_variations-v1
Create Design Variations
image
1 cr
3 cr
7 cr
1
POST
change_background-v1
Change Background
image
1 cr
3 cr
—
2
POST
remove_background-v1
Remove Background
image
0.5 cr
0.5 cr
—
1
POST
ad_creative-v1
Ad Creative
image
1 cr
3 cr
7 cr
2
POST
enhance_video_to_hd-v1
Enhance Video to HD
video
4.4 cr/s
4.4 cr/s
—
3
POST
ai_stylist-v1
AI Stylist
image
1 cr
3 cr
7 cr
1
POST
outpaint_new_ratio-v1
Expand Image
image
1 cr
1 cr
—
1
POST
create_3d_models-v1
Image to 3D
3d
10 cr
10 cr
—
1
POST
tryon_video-v1
Virtual Try-On Video
video
2.2 cr/s
4.4 cr/s
23 cr/s
2
POST
outfit_transition-v1
Outfit Transition
video
2.2 cr/s
4.4 cr/s
23 cr/s
2
POST
fashion_ad-v1
Fashion Ad
video
2.2 cr/s
4.4 cr/s
23 cr/s
3
POST
detail_closeup-v1
Detail Close-up
video
2.2 cr/s
4.4 cr/s
23 cr/s
1
POST
editorial_video-v1
Editorial Lookbook
video
2.2 cr/s
4.4 cr/s
23 cr/s
1
POST
outfit_drop-v1
Outfit Drop
video
2.2 cr/s
4.4 cr/s
23 cr/s
3
POST
remove_video_background-v1
Remove Video Background
video
1.4 cr/s
1.4 cr/s
—
1
POST
reframe_video-v1
Reframe Video
video
4.4 cr/s
4.4 cr/s
—
1
POST
passerby_transition-v1
Passer-By Transition
video
2.2 cr/s
4.4 cr/s
23 cr/s
3
POST
crosswalk_look_switch-v1
Look Switch Walk
video
2.2 cr/s
4.4 cr/s
23 cr/s
3
POST
change_video_background-v1
Change Video Background
video
4.4 cr/s
8.8 cr/s
—
1
POST
change_video_outfit-v1
Edit Outfit in Video
video
3.3 cr/s
4.3 cr/s
—
1
POST
swap_video_model-v1
Swap Model in Video
video
3.3 cr/s
4.3 cr/s
—
2
POST
hanger_layering-v1
Hanger Switch
video
2.2 cr/s
4.4 cr/s
23 cr/s
5
POST
window_walkby-v1
Window Walk-By
video
2.2 cr/s
4.4 cr/s
23 cr/s
3
POST
detail_zoom_rush-v1
Detail Zoom Rush
video
2.2 cr/s
4.4 cr/s
23 cr/s
1
POST
outfit_morph-v1
Outfit Morph
video
2.2 cr/s
4.4 cr/s
23 cr/s
4
POST
freeform_audio-v1
Create a Soundtrack
audio
2 cr
2 cr
—
1
POST
voice_over-v1
Create a Voice-over
audio
1.06 cr/1k chars
2.12 cr/1k chars
2.12 cr/1k chars
3
POST
motion_collection_panorama-v1
Collection Panorama
video
1 cr
1 cr
—
6
POST
motion_split_reel-v1
Split Reel
video
1 cr
1 cr
—
4
POST
motion_style_post-v1
Style Post
video
1 cr
1 cr
—
1
POST
motion_look_film-v1
Look Film
video
1 cr
1 cr
—
4
POST
motion_colour_drop-v1
Colour Drop
video
1 cr
1 cr
—
4
POST
motion_phone_promo-v1
Phone Promo
video
1 cr
1 cr
—
4
POST
motion_cut_montage-v1
Cut Montage
video
1 cr
1 cr
—
6
POST
motion_paper_collage-v1
Paper Collage
video
1 cr
1 cr
—
8
POST
motion_lineup-v1
Lineup
video
1 cr
1 cr
—
6
POST
motion_character_select-v1
Character Select
video
1 cr
1 cr
—
6
POST
motion_grid_mosaic-v1
Grid Mosaic
video
1 cr
1 cr
—
2
POST
motion_ways_to_wear-v1
Ways to Wear
video
1 cr
1 cr
—
6
POST
motion_detail_study-v1
Detail Study
video
1 cr
1 cr
—
3
POST
motion_signature_film-v1
Signature Film
video
1 cr
1 cr
—
4
POST
motion_outfit_picker-v1
Outfit Picker
video
1 cr
1 cr
—
4
POST
motion_beat_cut-v1
Beat Cut
video
1 cr
1 cr
—
4
POST
motion_bold_word-v1
Bold Word
video
1 cr
1 cr
—
4
POST
motion_mix_match-v1
Mix & Match
video
1 cr
1 cr
—
6
Publishing catalogue
(
5
)
Send what you create where it sells, by API — keys with the
publish
scope. One documentation page per platform.
Platform
Endpoints
Publishes
Status
Shopify
/v1/shopify/products · /v1/shopify/publish
Images & videos onto product pages
live
Instagram
/v1/publish/accounts · /v1/publish · /v1/publish/
{id}
Images & videos as feed posts, stories, carousels, reels
live
TikTok
/v1/publish/accounts · /v1/publish · /v1/publish/
{id}
Videos & photo posts
live
X
/v1/publish/accounts · /v1/publish · /v1/publish/
{id}
Images & videos as posts
live
Pinterest
/v1/publish/accounts · /v1/publish · /v1/publish/
{id}
Images & videos as pins, onto a board
live
YouTube
/v1/publish/accounts · /v1/publish · /v1/publish/
{id}
Videos as Shorts
live
GET
/v1/media · /v1/projects · /v1/elements · /v1/media/upload
Creations catalogue
(
4
)
Read back what the account has created — keys with the
read
scope. Every listing accepts
?project=<id>
to filter by project. PDF exports return a JSON
{ url }
— public but unguessable, the same regime as every creation URL.
Resource
Endpoints
Returns
Status
Media
GET
/v1/media
Your images, videos, 3D models and soundtracks — URLs, thumbnails, project; filters by project, type, favourites, prompt words, workflow, date; next_before and next_before_id page back
live
Projects
GET
/v1/projects
Your projects — the filter of every listing
live
Elements
GET
/v1/elements
Your starred pot — creations, presets, uploads
live
Upload
POST
/v1/media/upload
multipart `file` (JPG, PNG, WebP, 15 MB) + optional `project` → { media_id, url } — a picture of yours, hosted by us, for any image parameter
live
GET
/v1/account · /v1/credits · /v1/ledger · /v1/account/invoices · /v1/brand-dna
Account
(
6
)
The account as its AI agent reads it, for your own program: everything in one reading, the credit balance, what it spent and received, its invoices, and its Visual styles with the analysis the vision model wrote.
read
scope; nothing is debited.
Action
Endpoints
Returns
Status
Read the account
GET
/v1/account
Username, credits, plan, team, brand, Shopify store, Visual styles, projects with their counts, exact library counts, tech packs
live
Credit balance
GET
/v1/credits
The balance, one decimal
live
Read the ledger
GET
/v1/ledger?days=30&lines=60
The credit lines of the period, signed, and the usage by team member
live
Invoices
GET
/v1/account/invoices?limit=12
Every invoice, plans and credit packs, newest first, with its page and its PDF; next_starting_after pages back
live
Visual style
GET
/v1/brand-dna · /v1/brand-dna/{id}
The profiles; one in full with its references and its analysis text
live
curl "https://thenewblack.ai/api/v1/account" \
-H "Authorization: Bearer tnb_live_XXXXXXXXXXXX"
{
"id": "a1e259ae-...", "username": "maison-k", "credits": 206.5,
"team": { "role": "leader", "members": [{ "id": "3edf...", "username": "lea" }] },
"brand_dna": [{ "id": "7c1a...", "name": "SS27", "focus": "womenswear", "analysed": true, "references": 12 }],
"library": { "creations": 1000, "favourites": 3, "archived": 3 },
"projects": [{ "id": "7763...", "name": "Linen capsule", "creations": 41, "archived": 0, "last_creation": "2026-09-11T16:02:00Z" }],
"counts": { "shopify_products": 18, "techpacks": 4 },
"techpacks": [{ "id": "8363...", "name": "Custom Print Crew Neck T-Shirt", "pages": 2, "project": null, "template": false, "origin": "ai", "updated_at": "2026-09-10T09:14:00Z" }]
}
GET
/v
Recorded tool call
{
"type": "tool_call",
"seq": 38,
"ts": "2026-10-30T20:23:19.284Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /tmp && timeout 25 curl -s https://thenewblack.ai/clothing_fashion_api_integrations > page.html && python3 - <<'EOF'\nimport re,html\nt=open('page.html').read()\nt=re.sub(r'<script.*?</script>','',t,flags=re.S); t=re.sub(r'<style.*?</style>','',t,flags=re.S)\nt=re.sub(r'<[^>]+>','\\n',t); t=html.unescape(t)\nt=re.sub(r'[ \\t]+',' ',t); t=re.sub(r'\\n\\s*\\n+','\\n',t)\nopen('page.txt','w').write(t)\ni=t.find('Guide')\nprint(t[i:i+9000])\nEOF"
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-88725da7aa1789a5",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 40,
"ts": "2026-10-30T20:23:20.135Z",
"turn": 1,
"output": {
"content": [
{
"text": "Guide\nIntroduction\nAuthentication\nErrors\nRate limits\nCreate a generation\nRetrieve a generation\nWebhooks\nCredits\nMCP\nCommand line\nMigrating from the legacy API\nStatus\nGET\n/v1/workflows\nWorkflows catalogue \n(\n77\n)\nEvery studio workflow is callable by its versioned endpoint name. The route returns the live catalogue — named image parameters, fields, variants, formats and prices; the table below is rendered from the same data.\nMethod\nWorkflow key\nTitle\nMode\nStandard\nPro\nUltra\nMax refs\nPOST\nfreeform_image-v1\nFree Prompt Image\nimage\n1 cr\n3 cr\n7 cr\n3\nPOST\nfreeform_video-v1\nFree Prompt Video\nvideo\n2.2 cr/s\n4.4 cr/s\n23 cr/s\n1\nPOST\nvirtual_try_on-v1\nVirtual Try-On\nimage\n1 cr\n3 cr\n7 cr\n5\nPOST\nproduct_to_model-v1\nProduct to Model\nimage\n1 cr\n3 cr\n7 cr\n5\nPOST\nimage_to_ghost_mannequin-v1\nImage to Ghost Mannequin\nimage\n1 cr\n3 cr\n7 cr\n1\nPOST\nchange_color-v1\nChange a Color\nimage\n1 cr\n3 cr\n7 cr\n1\nPOST\ncreate_design-v1\nCreate a Product\nimage\n1 cr\n3 cr\n7 cr\n3\nPOST\nenhance_photo_to_hd-v1\nEnhance Photo to HD (2K/4K)\nimage\n1 cr\n3 cr\n—\n3\nPOST\nretouch-v1\nEdit an Area\nimage\n1 cr\n3 cr\n—\n16\nPOST\nreimagine_scene-v1\nReimagine your Model\nimage\n1 cr\n3 cr\n7 cr\n1\nPOST\nedit_video-v1\nEdit video\nvideo\n3.3 cr/s\n4.3 cr/s\n—\n1\nPOST\nmotion_design-v1\nMotion Design\nvideo\n4 cr\n4 cr\n—\n4\nPOST\nmodel_walk-v1\nModel Walk\nvideo\n2.2 cr/s\n4.4 cr/s\n23 cr/s\n1\nPOST\nproduct_360-v1\nProduct 360\nvideo\n2.2 cr/s\n4.4 cr/s\n23 cr/s\n3\nPOST\nmodel_360-v1\nModel 360\nvideo\n2.2 cr/s\n4.4 cr/s\n23 cr/s\n2\nPOST\nswap_models-v1\nSwap Model\nimage\n1 cr\n3 cr\n7 cr\n1\nPOST\nface_swap-v1\nFace Swap\nimage\n1 cr\n1 cr\n—\n2\nPOST\nfabric_to_design-v1\nFabric to Image\nimage\n1 cr\n3 cr\n7 cr\n1\nPOST\nimage_to_fabric-v1\nImage to Fabric\nimage\n1 cr\n3 cr\n7 cr\n1\nPOST\ntext_to_textile-v1\nText to Textile\nimage\n1 cr\n3 cr\n7 cr\n3\nPOST\nsnap_freeze-v1\nSnap Freeze\nvideo\n2.2 cr/s\n4.4 cr/s\n23 cr/s\n3\nPOST\nugc_video-v1\nUGC Video\nvideo\n2.2 cr/s\n4.4 cr/s\n23 cr/s\n3\nPOST\nimage_to_flat_lay-v1\nImage to Flat Lay\nimage\n1 cr\n3 cr\n7 cr\n1\nPOST\nswap_fabrics-v1\nSwap Fabrics\nimage\n1 cr\n3 cr\n7 cr\n2\nPOST\nlogo_placement-v1\nAdd a Logo\nimage\n1 cr\n3 cr\n—\n3\nPOST\ntext_to_sketch-v1\nText to Sketch\nimage\n1 cr\n3 cr\n7 cr\n3\nPOST\nsketch_to_image-v1\nSketch to Image\nimage\n1 cr\n3 cr\n—\n1\nPOST\nimage_to_sketch-v1\nImage to Sketch\nimage\n1 cr\n3 cr\n7 cr\n2\nPOST\nsketch_to_svg-v1\nSketch to SVG\nimage\n1 cr\n1 cr\n—\n1\nPOST\nvectorize_image-v1\nVectorize Prints & Logos\nimage\n1 cr\n1 cr\n—\n1\nPOST\ninsert_fabric_on_sketch-v1\nInsert Fabric on Sketch\nimage\n1 cr\n3 cr\n7 cr\n2\nPOST\ncreate_similar_outfits-v1\nCreate Similar Outfits\nimage\n1 cr\n3 cr\n7 cr\n1\nPOST\ncreate_design_variations-v1\nCreate Design Variations\nimage\n1 cr\n3 cr\n7 cr\n1\nPOST\nchange_background-v1\nChange Background\nimage\n1 cr\n3 cr\n—\n2\nPOST\nremove_background-v1\nRemove Background\nimage\n0.5 cr\n0.5 cr\n—\n1\nPOST\nad_creative-v1\nAd Creative\nimage\n1 cr\n3 cr\n7 cr\n2\nPOST\nenhance_video_to_hd-v1\nEnhance Video to HD\nvideo\n4.4 cr/s\n4.4 cr/s\n—\n3\nPOST\nai_stylist-v1\nAI Stylist\nimage\n1 cr\n3 cr\n7 cr\n1\nPOST\noutpaint_new_ratio-v1\nExpand Image\nimage\n1 cr\n1 cr\n—\n1\nPOST\ncreate_3d_models-v1\nImage to 3D\n3d\n10 cr\n10 cr\n—\n1\nPOST\ntryon_video-v1\nVirtual Try-On Video\nvideo\n2.2 cr/s\n4.4 cr/s\n23 cr/s\n2\nPOST\noutfit_transition-v1\nOutfit Transition\nvideo\n2.2 cr/s\n4.4 cr/s\n23 cr/s\n2\nPOST\nfashion_ad-v1\nFashion Ad\nvideo\n2.2 cr/s\n4.4 cr/s\n23 cr/s\n3\nPOST\ndetail_closeup-v1\nDetail Close-up\nvideo\n2.2 cr/s\n4.4 cr/s\n23 cr/s\n1\nPOST\neditorial_video-v1\nEditorial Lookbook\nvideo\n2.2 cr/s\n4.4 cr/s\n23 cr/s\n1\nPOST\noutfit_drop-v1\nOutfit Drop\nvideo\n2.2 cr/s\n4.4 cr/s\n23 cr/s\n3\nPOST\nremove_video_background-v1\nRemove Video Background\nvideo\n1.4 cr/s\n1.4 cr/s\n—\n1\nPOST\nreframe_video-v1\nReframe Video\nvideo\n4.4 cr/s\n4.4 cr/s\n—\n1\nPOST\npasserby_transition-v1\nPasser-By Transition\nvideo\n2.2 cr/s\n4.4 cr/s\n23 cr/s\n3\nPOST\ncrosswalk_look_switch-v1\nLook Switch Walk\nvideo\n2.2 cr/s\n4.4 cr/s\n23 cr/s\n3\nPOST\nchange_video_background-v1\nChange Video Background\nvideo\n4.4 cr/s\n8.8 cr/s\n—\n1\nPOST\nchange_video_outfit-v1\nEdit Outfit in Video\nvideo\n3.3 cr/s\n4.3 cr/s\n—\n1\nPOST\nswap_video_model-v1\nSwap Model in Video\nvideo\n3.3 cr/s\n4.3 cr/s\n—\n2\nPOST\nhanger_layering-v1\nHanger Switch\nvideo\n2.2 cr/s\n4.4 cr/s\n23 cr/s\n5\nPOST\nwindow_walkby-v1\nWindow Walk-By\nvideo\n2.2 cr/s\n4.4 cr/s\n23 cr/s\n3\nPOST\ndetail_zoom_rush-v1\nDetail Zoom Rush\nvideo\n2.2 cr/s\n4.4 cr/s\n23 cr/s\n1\nPOST\noutfit_morph-v1\nOutfit Morph\nvideo\n2.2 cr/s\n4.4 cr/s\n23 cr/s\n4\nPOST\nfreeform_audio-v1\nCreate a Soundtrack\naudio\n2 cr\n2 cr\n—\n1\nPOST\nvoice_over-v1\nCreate a Voice-over\naudio\n1.06 cr/1k chars\n2.12 cr/1k chars\n2.12 cr/1k chars\n3\nPOST\nmotion_collection_panorama-v1\nCollection Panorama\nvideo\n1 cr\n1 cr\n—\n6\nPOST\nmotion_split_reel-v1\nSplit Reel\nvideo\n1 cr\n1 cr\n—\n4\nPOST\nmotion_style_post-v1\nStyle Post\nvideo\n1 cr\n1 cr\n—\n1\nPOST\nmotion_look_film-v1\nLook Film\nvideo\n1 cr\n1 cr\n—\n4\nPOST\nmotion_colour_drop-v1\nColour Drop\nvideo\n1 cr\n1 cr\n—\n4\nPOST\nmotion_phone_promo-v1\nPhone Promo\nvideo\n1 cr\n1 cr\n—\n4\nPOST\nmotion_cut_montage-v1\nCut Montage\nvideo\n1 cr\n1 cr\n—\n6\nPOST\nmotion_paper_collage-v1\nPaper Collage\nvideo\n1 cr\n1 cr\n—\n8\nPOST\nmotion_lineup-v1\nLineup\nvideo\n1 cr\n1 cr\n—\n6\nPOST\nmotion_character_select-v1\nCharacter Select\nvideo\n1 cr\n1 cr\n—\n6\nPOST\nmotion_grid_mosaic-v1\nGrid Mosaic\nvideo\n1 cr\n1 cr\n—\n2\nPOST\nmotion_ways_to_wear-v1\nWays to Wear\nvideo\n1 cr\n1 cr\n—\n6\nPOST\nmotion_detail_study-v1\nDetail Study\nvideo\n1 cr\n1 cr\n—\n3\nPOST\nmotion_signature_film-v1\nSignature Film\nvideo\n1 cr\n1 cr\n—\n4\nPOST\nmotion_outfit_picker-v1\nOutfit Picker\nvideo\n1 cr\n1 cr\n—\n4\nPOST\nmotion_beat_cut-v1\nBeat Cut\nvideo\n1 cr\n1 cr\n—\n4\nPOST\nmotion_bold_word-v1\nBold Word\nvideo\n1 cr\n1 cr\n—\n4\nPOST\nmotion_mix_match-v1\nMix & Match\nvideo\n1 cr\n1 cr\n—\n6\nPublishing catalogue \n(\n5\n)\nSend what you create where it sells, by API — keys with the\npublish\n scope. One documentation page per platform.\nPlatform\nEndpoints\nPublishes\nStatus\n Shopify\n/v1/shopify/products · /v1/shopify/publish\nImages & videos onto product pages\nlive\nInstagram\n/v1/publish/accounts · /v1/publish · /v1/publish/\n{id}\nImages & videos as feed posts, stories, carousels, reels\nlive\nTikTok\n/v1/publish/accounts · /v1/publish · /v1/publish/\n{id}\nVideos & photo posts\nlive\nX\n/v1/publish/accounts · /v1/publish · /v1/publish/\n{id}\nImages & videos as posts\nlive\nPinterest\n/v1/publish/accounts · /v1/publish · /v1/publish/\n{id}\nImages & videos as pins, onto a board\nlive\nYouTube\n/v1/publish/accounts · /v1/publish · /v1/publish/\n{id}\nVideos as Shorts\nlive\nGET\n/v1/media · /v1/projects · /v1/elements · /v1/media/upload\nCreations catalogue \n(\n4\n)\nRead back what the account has created — keys with the\nread\n scope. Every listing accepts\n?project=<id>\n to filter by project. PDF exports return a JSON \n{ url }\n — public but unguessable, the same regime as every creation URL.\nResource\nEndpoints\nReturns\nStatus\nMedia\nGET\n/v1/media\nYour images, videos, 3D models and soundtracks — URLs, thumbnails, project; filters by project, type, favourites, prompt words, workflow, date; next_before and next_before_id page back\nlive\nProjects\nGET\n/v1/projects\nYour projects — the filter of every listing\nlive\nElements\nGET\n/v1/elements\nYour starred pot — creations, presets, uploads\nlive\nUpload\nPOST\n/v1/media/upload\nmultipart `file` (JPG, PNG, WebP, 15 MB) + optional `project` → { media_id, url } — a picture of yours, hosted by us, for any image parameter\nlive\nGET\n/v1/account · /v1/credits · /v1/ledger · /v1/account/invoices · /v1/brand-dna\nAccount \n(\n6\n)\nThe account as its AI agent reads it, for your own program: everything in one reading, the credit balance, what it spent and received, its invoices, and its Visual styles with the analysis the vision model wrote.\nread\n scope; nothing is debited.\nAction\nEndpoints\nReturns\nStatus\nRead the account\nGET\n/v1/account\nUsername, credits, plan, team, brand, Shopify store, Visual styles, projects with their counts, exact library counts, tech packs\nlive\nCredit balance\nGET\n/v1/credits\nThe balance, one decimal\nlive\nRead the ledger\nGET\n/v1/ledger?days=30&lines=60\nThe credit lines of the period, signed, and the usage by team member\nlive\nInvoices\nGET\n/v1/account/invoices?limit=12\nEvery invoice, plans and credit packs, newest first, with its page and its PDF; next_starting_after pages back\nlive\nVisual style\nGET\n/v1/brand-dna · /v1/brand-dna/{id}\nThe profiles; one in full with its references and its analysis text\nlive\ncurl \"https://thenewblack.ai/api/v1/account\" \\\n -H \"Authorization: Bearer tnb_live_XXXXXXXXXXXX\"\n{\n \"id\": \"a1e259ae-...\", \"username\": \"maison-k\", \"credits\": 206.5,\n \"team\": { \"role\": \"leader\", \"members\": [{ \"id\": \"3edf...\", \"username\": \"lea\" }] },\n \"brand_dna\": [{ \"id\": \"7c1a...\", \"name\": \"SS27\", \"focus\": \"womenswear\", \"analysed\": true, \"references\": 12 }],\n \"library\": { \"creations\": 1000, \"favourites\": 3, \"archived\": 3 },\n \"projects\": [{ \"id\": \"7763...\", \"name\": \"Linen capsule\", \"creations\": 41, \"archived\": 0, \"last_creation\": \"2026-09-11T16:02:00Z\" }],\n \"counts\": { \"shopify_products\": 18, \"techpacks\": 4 },\n \"techpacks\": [{ \"id\": \"8363...\", \"name\": \"Custom Print Crew Neck T-Shirt\", \"pages\": 2, \"project\": null, \"template\": false, \"origin\": \"ai\", \"updated_at\": \"2026-09-10T09:14:00Z\" }]\n}\nGET\n/v\n",
"type": "text"
}
]
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-88725da7aa1789a5",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Now let me read the guide sections: authentication, errors, rate limits, create a generation, retrieve, webhooks, credits. Find in page.txt after the catalogues. Let me grep for "Credits" section and "Rate limits".
cd /tmp && python3 - <<'EOF'
t=open('page.txt').read()
i=t.find('Rate limits', t.find('Guide')+200)
print(t[i:i+7000])
EOFRate limits
Rate limits
An account starts a set number of generations a minute, through the API, the CLI and the MCP connector together: 30 without a plan or on Starter, 60 on Pro, 120 on Business, 300 on Enterprise. Reading — polling a generation, listing, checking credits — is not counted. Past the limit,
POST /v1/generate
answers
429 rate_limited
with a
Retry-After
header (seconds to wait), and nothing is charged. Need more for a launch or a store network?
Write to us
— the limit can be raised for your account.
// 429 Too Many Requests · Retry-After: 12
{ "error": { "code": "rate_limited", "message": "This account starts at most 60 generations a minute on its plan. Try again in 12 s.",
"retry_after": 12, "limit_per_minute": 60 } }
POST
/v1/generate
Create a generation
Requires the
generate
scope. Credits are debited when the request is accepted; if the balance is short nothing starts and nothing is charged. Returns
202
with the generation id.
Parameter
Type
workflow
string
required
A versioned endpoint from the catalogue, e.g.
create_design-v1
. The version is part of the name — earlier versions keep being served under theirs.
prompt
string
optional
What to create — in English for best results (workflows that take one). Required where the catalogue says
prompt_required
: a picture made from words alone, and the text Voice reads.
<named images>
string
optional
Each workflow declares its image parameters by name, exactly like its panel —
sketch_image
,
fabric_image
,
model_image
… — listed on its endpoint page and in the catalogue. Positional arrays are not accepted. A place the panel may hide (
conditional
in the catalogue) is required only while the fields' choice shows it.
fields
object
optional
The workflow's panel fields by name, options validated — see its endpoint page.
variant
string
optional
Workflows with tabs: the variant by its visible title.
tier
string
optional
"standard" (default), "pro", or "ultra" where the catalogue lists it in
tiers
: our best model at its largest output — a picture in 4K (from the Pro plan), a video in 1080p on our top video model. For a picture:
standard
—
1K resolution image + fast generation
;
pro
—
2K resolution image + thinking process before generating
;
ultra
—
4K resolution image + deep thinking process before generating
. For a video:
standard
—
720p resolution video + fast generation
;
pro
—
1080p resolution video + thinking process before generating
;
ultra
—
1080p resolution video + deep thinking process before generating
.
ratio
string
optional
From the workflow's offered ratios.
duration
string
optional
Video and soundtrack workflows: seconds of output, from the allowed durations.
visual_dna
string
optional
Optional — the id of one of your Visual styles (
GET /v1/brand-dna
) or a house style; its paragraph closes the prompt. Only on the workflows where the studio shows a Visual style (
visual_dna: true
in the catalogue); refused elsewhere. How far it reaches is in
effects.reach
.
sound
string
optional
Video workflows: "on" (default) keeps the clip's own sound, "off" makes it silent; how far it reaches is in
effects.reach
.
end_image
string
optional
Video workflows that take one (
end_image: true
): an optional closing frame, one public HTTPS URL.
references
string[]
optional
Workflows that take them (
references: true
): one to three public HTTPS URLs put into the clip — a person, a garment, a place — instead of a start or end frame.
webhook_url
string
optional
Optional — we POST the outcome here when the generation settles. Without it, poll the URL returned in the response until the status settles.
curl -X POST https://thenewblack.ai/api/v1/generate \
-H "Authorization: Bearer tnb_live_XXXXXXXXXXXX" \
-H "Content-Type: application/json" \
--data-binary @- <<'JSON'
{
"workflow": "product_to_model-v1",
"product_images": [
"https://example.com/handbag.jpg"
],
"fields": {
"gender": "Woman",
"seg_framing": "full body",
"seg_scene": "a rooftop terrace at dusk"
},
"tier": "standard",
"ratio": "4:5",
"webhook_url": "https://example.com/hooks/tnb"
}
JSON
// 202 Accepted
{
"generation_id": "3f1c9a6e-...",
"status": "running",
"poll": "/api/v1/generations/3f1c9a6e-..."
}
GET
/v1/generations/
{id}
Retrieve a generation
Requires the
read
scope. Poll every few seconds until
status
is
succeeded
or
failed
. A failed generation is refunded automatically.
Most images are ready in under a minute — a background removal in seconds, a virtual try-on or a product on a model in about half a minute; videos take longer. The result's URL lives
48 hours
: copy the file to your own storage. After that the result is deleted and the call answers
expired
— unless the creation was opened in the app, which keeps it like any other.
// 200 OK
{
"generation_id": "3f1c9a6e-...",
"workflow": "product_to_model",
"status": "succeeded",
"result": {
"type": "image",
"url": "https://.../result.webp",
"thumbnail": "https://.../thumb.webp"
}
}
Webhooks
Pass
webhook_url
when creating a generation and we POST the outcome — success or failure — to your endpoint the moment it settles, instead of being polled. Answer with any 2xx; we try once, with a 5-second timeout, and your poll endpoint always remains the source of truth.
// POST to your webhook_url
{
"generation_id": "3f1c9a6e-...",
"status": "succeeded",
"result": { "type": "image", "url": "https://...", "thumbnail": "https://..." }
}
GET
/v1/credits
Credits
The account's live balance. Generation costs are per workflow and tier — see the catalogue; video is billed per second of output. Top up or subscribe on the
pricing page
.
// 200 OK
{ "credits": 142 }
MCP
The same capabilities inside a conversation: connect The New Black AI to Claude or ChatGPT as a Model Context Protocol server and generate from your chat — no code, same keys, same credits. The connector builds its tools from the live catalogue. Setup and details on the
MCP page
.
Building your integration
with Claude Code
? Install our skill and Claude knows the whole contract — auth, the async loop, every workflow read live from the catalogue, the CLI — before it writes a line:
npx skills add newblackai/claude-skill --skill thenewblack
Command line
The same API as a program — for an AI coding agent (Claude Code, Codex, Cursor), a script, a cron or a CI job. One command per workflow, generated from the live catalogue, and one per route of this page; local pictures uploaded once,
--wait
and
--out
do the plumbing. In a conversation, add the connector; in a project of code, install the CLI. Everything on the
CLI page
.
npx @thenewblack/cli --help
tnb generate virtual_try_on --product_images dress.jpg --model_image model.jpg --ratio 4:5 --wait --out ./renders/
Migrating from the legacy API
When the platform migration completes, the legacy endpoints are retired and answer with a notice pointing here. Keys are
not
carried over: create a new key from your
API / MCP tab
, point your integratio
Recorded tool call
{
"type": "tool_call",
"seq": 43,
"ts": "2026-10-30T20:23:22.309Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /tmp && python3 - <<'EOF'\nt=open('page.txt').read()\ni=t.find('Rate limits', t.find('Guide')+200)\nprint(t[i:i+7000])\nEOF"
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-a710e3ca2399e21a",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 44,
"ts": "2026-10-30T20:23:22.309Z",
"turn": 1,
"output": {
"content": [
{
"text": "Rate limits\nAn account starts a set number of generations a minute, through the API, the CLI and the MCP connector together: 30 without a plan or on Starter, 60 on Pro, 120 on Business, 300 on Enterprise. Reading — polling a generation, listing, checking credits — is not counted. Past the limit,\nPOST /v1/generate\n answers\n429 rate_limited\n with a\nRetry-After\n header (seconds to wait), and nothing is charged. Need more for a launch or a store network? \nWrite to us\n — the limit can be raised for your account.\n// 429 Too Many Requests · Retry-After: 12\n{ \"error\": { \"code\": \"rate_limited\", \"message\": \"This account starts at most 60 generations a minute on its plan. Try again in 12 s.\",\n \"retry_after\": 12, \"limit_per_minute\": 60 } }\nPOST\n/v1/generate\nCreate a generation\nRequires the \ngenerate\n scope. Credits are debited when the request is accepted; if the balance is short nothing starts and nothing is charged. Returns\n202\n with the generation id.\nParameter\nType\nworkflow\nstring\nrequired\nA versioned endpoint from the catalogue, e.g. \ncreate_design-v1\n. The version is part of the name — earlier versions keep being served under theirs.\nprompt\nstring\noptional\nWhat to create — in English for best results (workflows that take one). Required where the catalogue says \nprompt_required\n: a picture made from words alone, and the text Voice reads.\n<named images>\nstring\noptional\nEach workflow declares its image parameters by name, exactly like its panel — \nsketch_image\n, \nfabric_image\n, \nmodel_image\n… — listed on its endpoint page and in the catalogue. Positional arrays are not accepted. A place the panel may hide (\nconditional\n in the catalogue) is required only while the fields' choice shows it.\nfields\nobject\noptional\nThe workflow's panel fields by name, options validated — see its endpoint page.\nvariant\nstring\noptional\nWorkflows with tabs: the variant by its visible title.\ntier\nstring\noptional\n\"standard\" (default), \"pro\", or \"ultra\" where the catalogue lists it in \ntiers\n: our best model at its largest output — a picture in 4K (from the Pro plan), a video in 1080p on our top video model. For a picture: \nstandard\n — \n1K resolution image + fast generation\n; \npro\n — \n2K resolution image + thinking process before generating\n; \nultra\n — \n4K resolution image + deep thinking process before generating\n. For a video: \nstandard\n — \n720p resolution video + fast generation\n; \npro\n — \n1080p resolution video + thinking process before generating\n; \nultra\n — \n1080p resolution video + deep thinking process before generating\n.\nratio\nstring\noptional\nFrom the workflow's offered ratios.\nduration\nstring\noptional\nVideo and soundtrack workflows: seconds of output, from the allowed durations.\nvisual_dna\nstring\noptional\nOptional — the id of one of your Visual styles (\nGET /v1/brand-dna\n) or a house style; its paragraph closes the prompt. Only on the workflows where the studio shows a Visual style (\nvisual_dna: true\n in the catalogue); refused elsewhere. How far it reaches is in \neffects.reach\n.\nsound\nstring\noptional\nVideo workflows: \"on\" (default) keeps the clip's own sound, \"off\" makes it silent; how far it reaches is in \neffects.reach\n.\nend_image\nstring\noptional\nVideo workflows that take one (\nend_image: true\n): an optional closing frame, one public HTTPS URL.\nreferences\nstring[]\noptional\nWorkflows that take them (\nreferences: true\n): one to three public HTTPS URLs put into the clip — a person, a garment, a place — instead of a start or end frame.\nwebhook_url\nstring\noptional\nOptional — we POST the outcome here when the generation settles. Without it, poll the URL returned in the response until the status settles.\ncurl -X POST https://thenewblack.ai/api/v1/generate \\\n -H \"Authorization: Bearer tnb_live_XXXXXXXXXXXX\" \\\n -H \"Content-Type: application/json\" \\\n --data-binary @- <<'JSON'\n{\n \"workflow\": \"product_to_model-v1\",\n \"product_images\": [\n \"https://example.com/handbag.jpg\"\n ],\n \"fields\": {\n \"gender\": \"Woman\",\n \"seg_framing\": \"full body\",\n \"seg_scene\": \"a rooftop terrace at dusk\"\n },\n \"tier\": \"standard\",\n \"ratio\": \"4:5\",\n \"webhook_url\": \"https://example.com/hooks/tnb\"\n}\nJSON\n// 202 Accepted\n{\n \"generation_id\": \"3f1c9a6e-...\",\n \"status\": \"running\",\n \"poll\": \"/api/v1/generations/3f1c9a6e-...\"\n}\nGET\n/v1/generations/\n{id}\nRetrieve a generation\nRequires the \nread\n scope. Poll every few seconds until\nstatus\n is \nsucceeded\n or\nfailed\n. A failed generation is refunded automatically.\nMost images are ready in under a minute — a background removal in seconds, a virtual try-on or a product on a model in about half a minute; videos take longer. The result's URL lives \n48 hours\n: copy the file to your own storage. After that the result is deleted and the call answers \nexpired\n — unless the creation was opened in the app, which keeps it like any other.\n// 200 OK\n{\n \"generation_id\": \"3f1c9a6e-...\",\n \"workflow\": \"product_to_model\",\n \"status\": \"succeeded\",\n \"result\": {\n \"type\": \"image\",\n \"url\": \"https://.../result.webp\",\n \"thumbnail\": \"https://.../thumb.webp\"\n }\n}\nWebhooks\nPass \nwebhook_url\n when creating a generation and we POST the outcome — success or failure — to your endpoint the moment it settles, instead of being polled. Answer with any 2xx; we try once, with a 5-second timeout, and your poll endpoint always remains the source of truth.\n// POST to your webhook_url\n{\n \"generation_id\": \"3f1c9a6e-...\",\n \"status\": \"succeeded\",\n \"result\": { \"type\": \"image\", \"url\": \"https://...\", \"thumbnail\": \"https://...\" }\n}\nGET\n/v1/credits\nCredits\nThe account's live balance. Generation costs are per workflow and tier — see the catalogue; video is billed per second of output. Top up or subscribe on the\npricing page\n.\n// 200 OK\n{ \"credits\": 142 }\nMCP\nThe same capabilities inside a conversation: connect The New Black AI to Claude or ChatGPT as a Model Context Protocol server and generate from your chat — no code, same keys, same credits. The connector builds its tools from the live catalogue. Setup and details on the\nMCP page\n.\nBuilding your integration \nwith Claude Code\n? Install our skill and Claude knows the whole contract — auth, the async loop, every workflow read live from the catalogue, the CLI — before it writes a line:\nnpx skills add newblackai/claude-skill --skill thenewblack\nCommand line\nThe same API as a program — for an AI coding agent (Claude Code, Codex, Cursor), a script, a cron or a CI job. One command per workflow, generated from the live catalogue, and one per route of this page; local pictures uploaded once, \n--wait\n and\n--out\n do the plumbing. In a conversation, add the connector; in a project of code, install the CLI. Everything on the\nCLI page\n.\nnpx @thenewblack/cli --help\ntnb generate virtual_try_on --product_images dress.jpg --model_image model.jpg --ratio 4:5 --wait --out ./renders/\nMigrating from the legacy API\nWhen the platform migration completes, the legacy endpoints are retired and answer with a notice pointing here. Keys are \nnot\n carried over: create a new key from your\nAPI / MCP tab\n, point your integratio\n",
"type": "text"
}
]
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-a710e3ca2399e21a",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Now pricing: the pricing page. Let me fetch it for credit pack prices and plans. Also check errors section and authentication section text.
Let me get the pricing page.
cd /tmp && timeout 25 curl -s https://thenewblack.ai/pricing > pricing.html && python3 - <<'EOF'
import re,html
t=open('pricing.html').read()
t=re.sub(r'<script.*?</script>','',t,flags=re.S); t=re.sub(r'<style.*?</style>','',t,flags=re.S)
t=re.sub(r'<[^>]+>','\n',t); t=html.unescape(t)
t=re.sub(r'[ \t]+',' ',t); t=re.sub(r'\n\s*\n+','\n',t)
open('pricing.txt','w').write(t)
print(len(t)); print(t[:6000])
EOF10089
10089 Pricing | The New Black AI The New Black AI T he N ew B lack AI he ew lack Pricing Pricing Tutorials Log in Start free The New Black AI Start Subscribe to a plan A one-off top-up, on any account. Packs are limited to basic features when no plan is active. Compare the plans and what each one unlocks. Need more? Add multiple plans. Monthly Yearly 2 months free Packs Starter Create your first visuals with AI $15 /month Billed monthly, cancel anytime Start for $15/month 200 credits / month Every workflow 3 Visual styles See everything included Credits 200 / month · hold up to 700 Studio Every workflow HD 4K, bulk generation, video montage 3 Visual styles Brand Manager Your store's full history Act from the Store, profit & loss Publish to Instagram, TikTok, YouTube… Launch ad campaigns Tools Unlimited lookbooks Unlimited tech packs Unlimited canvases Connect your custom domain Team & agents Several brands from one account 3 seats AI agent · spends up to 200 cr / month API · 30 generations / minute See what every plan unlocks Pro For a brand selling every season $35 /month Billed monthly, cancel anytime Start for $35/month 500 credits / month HD 4K, bulk generation, video montage 10 Visual styles See everything included Credits 500 / month · hold up to 2,000 Studio Every workflow HD 4K, bulk generation, video montage 10 Visual styles Brand Manager Your store's full history Act from the Store, profit & loss Publish to Instagram, TikTok, YouTube… Launch ad campaigns Tools Unlimited lookbooks Unlimited tech packs Unlimited canvases Connect your custom domain Team & agents Several brands from one account 5 seats AI agent · spends up to 500 cr / month API · 60 generations / minute See what every plan unlocks Most popular Business Grow your sales with full access $65 /month Billed monthly, cancel anytime Start for $65/month 1,000 credits / month Unlimited Visual styles Launch ad campaigns See everything included Credits 1,000 / month · hold up to 4,000 Studio Every workflow HD 4K, bulk generation, video montage Unlimited Visual styles Brand Manager Your store's full history Act from the Store, profit & loss Publish to Instagram, TikTok, YouTube… Launch ad campaigns Tools Unlimited lookbooks Unlimited tech packs Unlimited canvases Connect your custom domain Team & agents Several brands from one account Unlimited seats AI agent · spends up to 1,000 cr / month API · 120 generations / minute See what every plan unlocks Enterprise Multi-brands For a brand at scale, a group or an agency $195 /month Billed monthly, cancel anytime Start for $195/month 3,000 credits / month Several brands from one account AI agent · spends up to 3,000 cr / month See everything included Credits 3,000 / month · hold up to 12,000 Studio Every workflow HD 4K, bulk generation, video montage Unlimited Visual styles Brand Manager Your store's full history Act from the Store, profit & loss Publish to Instagram, TikTok, YouTube… Launch ad campaigns Tools Unlimited lookbooks Unlimited tech packs Unlimited canvases Connect your custom domain Team & agents Several brands from one account Unlimited seats AI agent · spends up to 3,000 cr / month API · 300 generations / minute See what every plan unlocks What every plan unlocks What you can do Packs only See packs Starter $15/mo Pro $35/mo Business $65/mo Enterprise $195/mo Credits Credits every month — 200 500 1,000 3,000 Credits you can hold pack size 700 2,000 4,000 12,000 Studio Every workflow, photo and video — Standard AI PRO AI — a stronger model, video in 1080p Ultra AI video — our best video model, up to 30 seconds Ultra AI photos — our best image model, in 4K Enhance to HD 2K Enhance to HD 4K Bulk generation — a whole catalog at once Visual styles 3 10 Unlimited Unlimited Model, product and fabric presets Photo montage — type, layers, compose by hand Video montage — cut clips, titles, music Brand Manager Connect your store — sales, traffic, SEO and ads on one dashboard Import your Shopify catalog Publish your creations to Shopify Write articles, pages, newsletters and theme texts with AI Email campaigns with Klaviyo Authority & backlinks of your store Publish to Instagram, Facebook, Pinterest, TikTok, YouTube, X Act from the Store — campaigns, budgets, stock, costs, theme, articles Add your visuals to running ad campaigns Profit & loss Launch Meta, Google, Pinterest and X campaigns from your creations Lookbook Lookbooks, online at their own address 2 Unlimited Unlimited Unlimited Unlimited Links to your products and any page Your own domain — lookbook.yourbrand.com Without our mark on the last page Tech pack Tech packs, built by hand 2 Unlimited Unlimited Unlimited Unlimited Tech packs drafted by the AI, AI review credits credits credits credits credits Canvas Canvases Team & projects Projects, shared with your team Team seats 1 3 5 Unlimited Unlimited Multi-brands — a workspace per brand, same plan and credits AI agents AI agent — chat, tasks, scheduled jobs, connectors Credits your agent can spend a month 50 / 30 days 200 500 1,000 3,000 API API access and keys API rate, generations per minute 30 30 60 120 300 Create from Claude and ChatGPT via MCP Packs Starter Pro Business Enterprise $35/mo Credits Credits every month 500 Credits you can hold 2,000 Studio Every workflow, photo and video — Standard AI PRO AI — a stronger model, video in 1080p Ultra AI video — our best video model, up to 30 seconds Ultra AI photos — our best image model, in 4K Enhance to HD 2K Enhance to HD 4K Bulk generation — a whole catalog at once Visual styles 10 Model, product and fabric presets Photo montage — type, layers, compose by hand Video montage — cut clips, titles, music Brand Manager Connect your store — sales, traffic, SEO and ads on one dashboard Import your Shopify catalog Publish your creations to Shopify Write articles, pages, newsletters and theme texts with AI Email campaigns with Klaviyo Authority & backlinks of your store Publish to Instagram, Facebook, Pinterest, TikTok, Yo
Recorded tool call
{
"type": "tool_call",
"seq": 47,
"ts": "2026-10-30T20:23:26.096Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /tmp && timeout 25 curl -s https://thenewblack.ai/pricing > pricing.html && python3 - <<'EOF'\nimport re,html\nt=open('pricing.html').read()\nt=re.sub(r'<script.*?</script>','',t,flags=re.S); t=re.sub(r'<style.*?</style>','',t,flags=re.S)\nt=re.sub(r'<[^>]+>','\\n',t); t=html.unescape(t)\nt=re.sub(r'[ \\t]+',' ',t); t=re.sub(r'\\n\\s*\\n+','\\n',t)\nopen('pricing.txt','w').write(t)\nprint(len(t)); print(t[:6000])\nEOF"
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-9d3d8d7863888eb9",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 50,
"ts": "2026-10-30T20:23:27.725Z",
"turn": 1,
"output": {
"content": [
{
"text": "10089\n\nPricing | The New Black AI\nThe New Black AI\nT\nhe \nN\new \nB\nlack \nAI\nhe \new \nlack \nPricing\nPricing\nTutorials\nLog in\nStart free\nThe New Black \nAI\nStart\nSubscribe to a plan\nA one-off top-up, on any account.\nPacks are limited to \nbasic features\n when no plan is active.\nCompare the plans and what each one unlocks.\nNeed more? \nAdd multiple plans.\nMonthly\nYearly\n2 months free\nPacks\nStarter\nCreate your first visuals with AI\n$15\n/month\nBilled monthly, cancel anytime\nStart for $15/month\n200 credits / month\nEvery workflow\n3 Visual styles\nSee everything included\nCredits\n200 / month · hold up to 700\nStudio\nEvery workflow\nHD 4K, bulk generation, video montage\n3 Visual styles\nBrand Manager\nYour store's full history\nAct from the Store, profit & loss\nPublish to Instagram, TikTok, YouTube…\nLaunch ad campaigns\nTools\nUnlimited lookbooks\nUnlimited tech packs\nUnlimited canvases\nConnect your custom domain\nTeam & agents\nSeveral brands from one account\n3 seats\nAI agent · spends up to 200 cr / month\nAPI · 30 generations / minute\nSee what every plan unlocks\nPro\nFor a brand selling every season\n$35\n/month\nBilled monthly, cancel anytime\nStart for $35/month\n500 credits / month\nHD 4K, bulk generation, video montage\n10 Visual styles\nSee everything included\nCredits\n500 / month · hold up to 2,000\nStudio\nEvery workflow\nHD 4K, bulk generation, video montage\n10 Visual styles\nBrand Manager\nYour store's full history\nAct from the Store, profit & loss\nPublish to Instagram, TikTok, YouTube…\nLaunch ad campaigns\nTools\nUnlimited lookbooks\nUnlimited tech packs\nUnlimited canvases\nConnect your custom domain\nTeam & agents\nSeveral brands from one account\n5 seats\nAI agent · spends up to 500 cr / month\nAPI · 60 generations / minute\nSee what every plan unlocks\nMost popular\nBusiness\nGrow your sales with full access\n$65\n/month\nBilled monthly, cancel anytime\nStart for $65/month\n1,000 credits / month\nUnlimited Visual styles\nLaunch ad campaigns\nSee everything included\nCredits\n1,000 / month · hold up to 4,000\nStudio\nEvery workflow\nHD 4K, bulk generation, video montage\nUnlimited Visual styles\nBrand Manager\nYour store's full history\nAct from the Store, profit & loss\nPublish to Instagram, TikTok, YouTube…\nLaunch ad campaigns\nTools\nUnlimited lookbooks\nUnlimited tech packs\nUnlimited canvases\nConnect your custom domain\nTeam & agents\nSeveral brands from one account\nUnlimited seats\nAI agent · spends up to 1,000 cr / month\nAPI · 120 generations / minute\nSee what every plan unlocks\nEnterprise\nMulti-brands\nFor a brand at scale, a group or an agency\n$195\n/month\nBilled monthly, cancel anytime\nStart for $195/month\n3,000 credits / month\nSeveral brands from one account\nAI agent · spends up to 3,000 cr / month\nSee everything included\nCredits\n3,000 / month · hold up to 12,000\nStudio\nEvery workflow\nHD 4K, bulk generation, video montage\nUnlimited Visual styles\nBrand Manager\nYour store's full history\nAct from the Store, profit & loss\nPublish to Instagram, TikTok, YouTube…\nLaunch ad campaigns\nTools\nUnlimited lookbooks\nUnlimited tech packs\nUnlimited canvases\nConnect your custom domain\nTeam & agents\nSeveral brands from one account\nUnlimited seats\nAI agent · spends up to 3,000 cr / month\nAPI · 300 generations / minute\nSee what every plan unlocks\nWhat every plan unlocks\nWhat you can do\nPacks only\nSee packs\nStarter\n$15/mo\nPro\n$35/mo\nBusiness\n$65/mo\nEnterprise\n$195/mo\nCredits\nCredits every month\n—\n200\n500\n1,000\n3,000\nCredits you can hold\npack size\n700\n2,000\n4,000\n12,000\nStudio\nEvery workflow, photo and video — Standard AI\nPRO AI — a stronger model, video in 1080p\nUltra AI video — our best video model, up to 30 seconds\nUltra AI photos — our best image model, in 4K\nEnhance to HD 2K\nEnhance to HD 4K\nBulk generation — a whole catalog at once\nVisual styles\n3\n10\nUnlimited\nUnlimited\nModel, product and fabric presets\nPhoto montage — type, layers, compose by hand\nVideo montage — cut clips, titles, music\nBrand Manager\nConnect your store — sales, traffic, SEO and ads on one dashboard\nImport your Shopify catalog\nPublish your creations to Shopify\nWrite articles, pages, newsletters and theme texts with AI\nEmail campaigns with Klaviyo\nAuthority & backlinks of your store\nPublish to Instagram, Facebook, Pinterest, TikTok, YouTube, X\nAct from the Store — campaigns, budgets, stock, costs, theme, articles\nAdd your visuals to running ad campaigns\nProfit & loss\nLaunch Meta, Google, Pinterest and X campaigns from your creations\nLookbook\nLookbooks, online at their own address\n2\nUnlimited\nUnlimited\nUnlimited\nUnlimited\nLinks to your products and any page\nYour own domain — lookbook.yourbrand.com\nWithout our mark on the last page\nTech pack\nTech packs, built by hand\n2\nUnlimited\nUnlimited\nUnlimited\nUnlimited\nTech packs drafted by the AI, AI review\ncredits\ncredits\ncredits\ncredits\ncredits\nCanvas\nCanvases\nTeam & projects\nProjects, shared with your team\nTeam seats\n1\n3\n5\nUnlimited\nUnlimited\nMulti-brands — a workspace per brand, same plan and credits\nAI agents\nAI agent — chat, tasks, scheduled jobs, connectors\nCredits your agent can spend a month\n50 / 30 days\n200\n500\n1,000\n3,000\nAPI\nAPI access and keys\nAPI rate, generations per minute\n30\n30\n60\n120\n300\nCreate from Claude and ChatGPT via MCP\nPacks\nStarter\nPro\nBusiness\nEnterprise\n$35/mo\nCredits\nCredits every month\n500\nCredits you can hold\n2,000\nStudio\nEvery workflow, photo and video — Standard AI\nPRO AI — a stronger model, video in 1080p\nUltra AI video — our best video model, up to 30 seconds\nUltra AI photos — our best image model, in 4K\nEnhance to HD 2K\nEnhance to HD 4K\nBulk generation — a whole catalog at once\nVisual styles\n10\nModel, product and fabric presets\nPhoto montage — type, layers, compose by hand\nVideo montage — cut clips, titles, music\nBrand Manager\nConnect your store — sales, traffic, SEO and ads on one dashboard\nImport your Shopify catalog\nPublish your creations to Shopify\nWrite articles, pages, newsletters and theme texts with AI\nEmail campaigns with Klaviyo\nAuthority & backlinks of your store\nPublish to Instagram, Facebook, Pinterest, TikTok, Yo\n",
"type": "text"
}
]
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-9d3d8d7863888eb9",
"is_error": false,
"tool_kind": "shell"
}cd /tmp && python3 - <<'EOF'
t=open('page.txt').read()
i=t.find('Introduction', t.find('Guide')+200)
print(t[i:i+4200])
EOFIntroduction
Introduction
The API is asynchronous, like the studio it drives: you submit a generation, credits are debited atomically at submission, and you collect the result by polling — or let us call your webhook when it settles. A generation that fails is refunded automatically.
Serving several stores or clients? On the
Enterprise plan
, each one can be a workspace of its own — its own API keys, its own creations — on one plan and one balance, with the usage of each workspace in Team › Usage.
Base URL https://thenewblack.ai/api/v1
Format JSON in, JSON out
Auth Authorization: Bearer tnb_live_...
The whole API is described in OpenAPI 3.1, publicly and without a key, generated at the instant of the call:
GET /api/v1/openapi.json
— every route, every workflow as a body schema of
/generate
, every error code. Point a code generator, an agent or an SDK builder at it. The catalogue alone is at
GET /api/v1/catalog
(every workflow's contract and prices) and
GET /api/v1/catalog/presets
(the stock preset shelves). The Claude connector and the CLI build themselves from these.
Authentication
Create up to three keys from your account's
API / MCP tab
. A key is shown once at creation and stored only as a hash — keep it server-side, never in a browser. Keys belong to the paying account: on a team, they spend the leader's credits.
Each key carries
scopes
chosen at creation:
generate
(create with the workflows and edit tech packs — spends credits),
read
(poll generations, list workflows, check credits, read the account, the ledger, the Visual style and everything in the Creations catalogue),
agents
(talk to Mila, her calendar and the Files — spends credits like the chat),
publish
(post to connected platforms —
Shopify
and
the social platforms
).
curl https://thenewblack.ai/api/v1/credits \
-H "Authorization: Bearer tnb_live_XXXXXXXXXXXX"
Errors
Errors are JSON with a stable
code
and a human
message
:
{ "error": { "code": "insufficient_credits", "message": "Not enough credits — this needs 3." } }
Parameter
Type
401
status
required
missing_key · invalid_key — no key, or an unknown/revoked one.
402
status
required
insufficient_credits — the account balance cannot cover the generation.
403
status
required
missing_scope — the key exists but lacks the scope for this action.
404
status
required
unknown_workflow · not_found — no such workflow, or no such generation on this account.
429
status
required
rate_limited — the account started its plan's generations for this minute; wait the
Retry-After
seconds. Nothing was charged.
502
status
required
generation_refused — the job was refused; any debited credit is refunded.
Rate limits
An account starts a set number of generations a minute, through the API, the CLI and the MCP connector together: 30 without a plan or on Starter, 60 on Pro, 120 on Business, 300 on Enterprise. Reading — polling a generation, listing, checking credits — is not counted. Past the limit,
POST /v1/generate
answers
429 rate_limited
with a
Retry-After
header (seconds to wait), and nothing is charged. Need more for a launch or a store network?
Write to us
— the limit can be raised for your account.
// 429 Too Many Requests · Retry-After: 12
{ "error": { "code": "rate_limited", "message": "This account starts at most 60 generations a minute on its plan. Try again in 12 s.",
"retry_after": 12, "limit_per_minute": 60 } }
POST
/v1/generate
Create a generation
Requires the
generate
scope. Credits are debited when the request is accepted; if the balance is short nothing starts and nothing is charged. Returns
202
with the generation id.
Parameter
Type
workflow
string
required
A versioned endpoint from the catalogue, e.g.
create_design-v1
. The version is part of the name — earlier versions keep being served under theirs.
prompt
string
optional
What to create — in English for best results (workflows that take one). Required where the catalogue says
prompt_required
: a picture made from words alone, and the text Voice reads.
<named images>
string
optional
Each workflow declares its image parameters by name, exactly like its panel —
sketch_image
,
fabric_image
,
model_image
… — listed on its endpoint page and in the cata
Recorded tool call
{
"type": "tool_call",
"seq": 48,
"ts": "2026-10-30T20:23:26.096Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /tmp && python3 - <<'EOF'\nt=open('page.txt').read()\ni=t.find('Introduction', t.find('Guide')+200)\nprint(t[i:i+4200])\nEOF"
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-81f5077e6a9d5445",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 49,
"ts": "2026-10-30T20:23:26.096Z",
"turn": 1,
"output": {
"content": [
{
"text": "Introduction\nThe API is asynchronous, like the studio it drives: you submit a generation, credits are debited atomically at submission, and you collect the result by polling — or let us call your webhook when it settles. A generation that fails is refunded automatically.\nServing several stores or clients? On the\nEnterprise plan\n, each one can be a workspace of its own — its own API keys, its own creations — on one plan and one balance, with the usage of each workspace in Team › Usage.\nBase URL https://thenewblack.ai/api/v1\nFormat JSON in, JSON out\nAuth Authorization: Bearer tnb_live_...\nThe whole API is described in OpenAPI 3.1, publicly and without a key, generated at the instant of the call:\nGET /api/v1/openapi.json\n— every route, every workflow as a body schema of \n/generate\n, every error code. Point a code generator, an agent or an SDK builder at it. The catalogue alone is at\nGET /api/v1/catalog\n (every workflow's contract and prices) and\nGET /api/v1/catalog/presets\n (the stock preset shelves). The Claude connector and the CLI build themselves from these.\nAuthentication\nCreate up to three keys from your account's\nAPI / MCP tab\n. A key is shown once at creation and stored only as a hash — keep it server-side, never in a browser. Keys belong to the paying account: on a team, they spend the leader's credits.\nEach key carries \nscopes\n chosen at creation:\ngenerate\n (create with the workflows and edit tech packs — spends credits),\nread\n (poll generations, list workflows, check credits, read the account, the ledger, the Visual style and everything in the Creations catalogue),\nagents\n (talk to Mila, her calendar and the Files — spends credits like the chat),\npublish\n (post to connected platforms —\nShopify\n and\nthe social platforms\n).\ncurl https://thenewblack.ai/api/v1/credits \\\n -H \"Authorization: Bearer tnb_live_XXXXXXXXXXXX\"\nErrors\nErrors are JSON with a stable \ncode\n and a human\nmessage\n:\n{ \"error\": { \"code\": \"insufficient_credits\", \"message\": \"Not enough credits — this needs 3.\" } }\nParameter\nType\n401\nstatus\nrequired\nmissing_key · invalid_key — no key, or an unknown/revoked one.\n402\nstatus\nrequired\ninsufficient_credits — the account balance cannot cover the generation.\n403\nstatus\nrequired\nmissing_scope — the key exists but lacks the scope for this action.\n404\nstatus\nrequired\nunknown_workflow · not_found — no such workflow, or no such generation on this account.\n429\nstatus\nrequired\nrate_limited — the account started its plan's generations for this minute; wait the \nRetry-After\n seconds. Nothing was charged.\n502\nstatus\nrequired\ngeneration_refused — the job was refused; any debited credit is refunded.\nRate limits\nAn account starts a set number of generations a minute, through the API, the CLI and the MCP connector together: 30 without a plan or on Starter, 60 on Pro, 120 on Business, 300 on Enterprise. Reading — polling a generation, listing, checking credits — is not counted. Past the limit,\nPOST /v1/generate\n answers\n429 rate_limited\n with a\nRetry-After\n header (seconds to wait), and nothing is charged. Need more for a launch or a store network? \nWrite to us\n — the limit can be raised for your account.\n// 429 Too Many Requests · Retry-After: 12\n{ \"error\": { \"code\": \"rate_limited\", \"message\": \"This account starts at most 60 generations a minute on its plan. Try again in 12 s.\",\n \"retry_after\": 12, \"limit_per_minute\": 60 } }\nPOST\n/v1/generate\nCreate a generation\nRequires the \ngenerate\n scope. Credits are debited when the request is accepted; if the balance is short nothing starts and nothing is charged. Returns\n202\n with the generation id.\nParameter\nType\nworkflow\nstring\nrequired\nA versioned endpoint from the catalogue, e.g. \ncreate_design-v1\n. The version is part of the name — earlier versions keep being served under theirs.\nprompt\nstring\noptional\nWhat to create — in English for best results (workflows that take one). Required where the catalogue says \nprompt_required\n: a picture made from words alone, and the text Voice reads.\n<named images>\nstring\noptional\nEach workflow declares its image parameters by name, exactly like its panel — \nsketch_image\n, \nfabric_image\n, \nmodel_image\n… — listed on its endpoint page and in the cata\n",
"type": "text"
}
]
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-81f5077e6a9d5445",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Also grab credit pack prices (one-off top-ups). The pricing text mentioned "Packs ... A one-off top-up" but the pack prices may be rendered client-side. Let me search pricing.txt for "$" values and "credits" pack amounts.
Also check /api/v1/catalog (public, no key). Let's verify.
Then build the example. Since we don't have an API key, the example must be runnable without one for the read-only parts, and dry-run for generation. I'll build:
- A tiny Node script
examples/tnb-demo.mjs? Or a bash + Node? Keep it simple: a single Node script using fetch (Node 18+) that:- Reads the live catalogue (public, no key) → prints prices for a chosen workflow.
- If TNB_API_KEY set: check credits, submit a generation (e.g. remove_background-v1 or create_design-v1 with prompt), poll until settled, download the result to ./renders/.
- Dry-run mode by default if no key: prints the exact request it would send.
Plus a README with pricing notes.
Let's check the catalog endpoint is public and the pack prices.
cd /tmp && timeout 25 curl -s -o catalog.json -w "catalog %{http_code}\n" https://thenewblack.ai/api/v1/catalog && python3 -c "
import json;d=json.load(open('catalog.json'))
print(type(d), list(d)[:10] if isinstance(d,dict) else len(d))
w=d['workflows'] if isinstance(d,dict) and 'workflows' in d else d
print(len(w))
import json as j
print(j.dumps(w[0] if isinstance(w,list) else list(w.items())[0], indent=1)[:2500])
"catalog 200
catalog 200
<class 'dict'> ['catalog_version', 'workflows_revision', 'base_url', 'services', 'workflows']
77
{
"endpoint": "freeform_image-v1",
"key": "freeform_image",
"version": 1,
"title": "Free Prompt Image",
"description": "Create or edit an image",
"mode": "image",
"thumbnail": "https://cloud.thenewblack.ai/storage/v1/object/public/workflow-thumbnails/b8216b8b-7b89-4f39-8195-367aec1cf781.jpg",
"takes_prompt": true,
"images": [
{
"param": "reference_images",
"label": "Reference images",
"required": false,
"multiple": true,
"max": 3,
"media": "image"
}
],
"fields": [],
"variants": [],
"ratios": [
"auto",
"9:16",
"1:1",
"4:5",
"3:4",
"2:3",
"16:9",
"4:3",
"3:2",
"5:4",
"21:9"
],
"durations": [],
"end_image": false,
"references": false,
"requires_plan": false,
"visual_dna": true,
"credits": {
"standard": 1,
"pro": 3,
"ultra": 7,
"unit": "per generation",
"rounding": "a fixed price per generation"
},
"tiers": [
"standard",
"pro",
"ultra"
],
"effects": {
"visual_dna": true,
"reach": {
"visual_dna": "all"
}
},
"prompt_required": true
}
Recorded tool call
{
"type": "tool_call",
"seq": 53,
"ts": "2026-10-30T20:23:35.077Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /tmp && timeout 25 curl -s -o catalog.json -w \"catalog %{http_code}\\n\" https://thenewblack.ai/api/v1/catalog && python3 -c \"\nimport json;d=json.load(open('catalog.json'))\nprint(type(d), list(d)[:10] if isinstance(d,dict) else len(d))\nw=d['workflows'] if isinstance(d,dict) and 'workflows' in d else d\nprint(len(w))\nimport json as j\nprint(j.dumps(w[0] if isinstance(w,list) else list(w.items())[0], indent=1)[:2500])\n\""
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-b8e9dec0b005fda1",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 56,
"ts": "2026-10-30T20:23:35.848Z",
"turn": 1,
"output": {
"content": [
{
"text": "catalog 200\n<class 'dict'> ['catalog_version', 'workflows_revision', 'base_url', 'services', 'workflows']\n77\n{\n \"endpoint\": \"freeform_image-v1\",\n \"key\": \"freeform_image\",\n \"version\": 1,\n \"title\": \"Free Prompt Image\",\n \"description\": \"Create or edit an image\",\n \"mode\": \"image\",\n \"thumbnail\": \"https://cloud.thenewblack.ai/storage/v1/object/public/workflow-thumbnails/b8216b8b-7b89-4f39-8195-367aec1cf781.jpg\",\n \"takes_prompt\": true,\n \"images\": [\n {\n \"param\": \"reference_images\",\n \"label\": \"Reference images\",\n \"required\": false,\n \"multiple\": true,\n \"max\": 3,\n \"media\": \"image\"\n }\n ],\n \"fields\": [],\n \"variants\": [],\n \"ratios\": [\n \"auto\",\n \"9:16\",\n \"1:1\",\n \"4:5\",\n \"3:4\",\n \"2:3\",\n \"16:9\",\n \"4:3\",\n \"3:2\",\n \"5:4\",\n \"21:9\"\n ],\n \"durations\": [],\n \"end_image\": false,\n \"references\": false,\n \"requires_plan\": false,\n \"visual_dna\": true,\n \"credits\": {\n \"standard\": 1,\n \"pro\": 3,\n \"ultra\": 7,\n \"unit\": \"per generation\",\n \"rounding\": \"a fixed price per generation\"\n },\n \"tiers\": [\n \"standard\",\n \"pro\",\n \"ultra\"\n ],\n \"effects\": {\n \"visual_dna\": true,\n \"reach\": {\n \"visual_dna\": \"all\"\n }\n },\n \"prompt_required\": true\n}\n",
"type": "text"
}
]
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-b8e9dec0b005fda1",
"is_error": false,
"tool_kind": "shell"
}cd /tmp && grep -nE '\$[0-9]+|[0-9,]+ credits' pricing.txt | head -40
36:$15
36:$15 39:Start for $15/month 40:200 credits / month 68:$35 71:Start for $35/month 72:500 credits / month 101:$65 104:Start for $65/month 105:1,000 credits / month 134:$195 137:Start for $195/month 138:3,000 credits / month 169:$15/mo 171:$35/mo 173:$65/mo 175:$195/mo 273:$35/mo 333:1 credit ≈ 1 image, 10 credits ≈ 1 video. The price is always shown before you generate.
Recorded tool call
{
"type": "tool_call",
"seq": 54,
"ts": "2026-10-30T20:23:35.077Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /tmp && grep -nE '\\$[0-9]+|[0-9,]+ credits' pricing.txt | head -40"
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-b9935900b3de72b0",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 55,
"ts": "2026-10-30T20:23:35.077Z",
"turn": 1,
"output": {
"content": [
{
"text": "36:$15\n39:Start for $15/month\n40:200 credits / month\n68:$35\n71:Start for $35/month\n72:500 credits / month\n101:$65\n104:Start for $65/month\n105:1,000 credits / month\n134:$195\n137:Start for $195/month\n138:3,000 credits / month\n169:$15/mo\n171:$35/mo\n173:$65/mo\n175:$195/mo\n273:$35/mo\n333:1 credit ≈ 1 image, 10 credits ≈ 1 video. The price is always shown before you generate.\n",
"type": "text"
}
]
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-b9935900b3de72b0",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Pack prices are client-rendered; only "1 credit ≈ 1 image, 10 credits ≈ 1 video". Good enough for pricing explanation. Let me check line ~320-360 of pricing.txt for pack section details.
Now build the example. Keep it light: one script + README. No API key available → verify the script runs in "dry-run/no-key" mode against the live public catalogue, and confirm auth-gated paths produce the documented error (already saw 401 missing_key).
Let's write:
- /sandbox/repo/examples/thenewblack/demo.mjs — Node 18+, zero deps: reads /api/v1/catalog, picks a workflow, prints price; if TNB_API_KEY present: GET /credits, POST /generate, poll, download to renders/. Default: dry-run when no key.
- /sandbox/repo/examples/thenewblack/README.md
Run it to verify.
Check node version.
cd /tmp && sed -n '320,345p' pricing.txt; node --version
5
5 Multi-brands — a workspace per brand, same plan and credits AI agents AI agent — chat, tasks, scheduled jobs, connectors Credits your agent can spend a month 500 API API access and keys API rate, generations per minute 60 Create from Claude and ChatGPT via MCP How it works Credits pay for generations 1 credit ≈ 1 image, 10 credits ≈ 1 video. The price is always shown before you generate. The plan is the licence What each plan unlocks is in the table above; credits are the fuel. Credit packs Packs alone open the Standard studio; plan features need an active plan. Your credit bank The most you can hold at once. Plans and packs stack to raise it. Roll over, pause, cancel Credits roll over while a plan is active. Pause or cancel whenever you like. Security Encrypted in transit TLS 1.2 and 1.3. HTTPS enforced. Encrypted at rest v22.23.4
Recorded tool call
{
"type": "tool_call",
"seq": 59,
"ts": "2026-10-30T20:23:39.849Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /tmp && sed -n '320,345p' pricing.txt; node --version"
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-a51fa31788d4c9e3",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 60,
"ts": "2026-10-30T20:23:39.849Z",
"turn": 1,
"output": {
"content": [
{
"text": "5\nMulti-brands — a workspace per brand, same plan and credits\nAI agents\nAI agent — chat, tasks, scheduled jobs, connectors\nCredits your agent can spend a month\n500\nAPI\nAPI access and keys\nAPI rate, generations per minute\n60\nCreate from Claude and ChatGPT via MCP\nHow it works\nCredits pay for generations\n1 credit ≈ 1 image, 10 credits ≈ 1 video. The price is always shown before you generate.\nThe plan is the licence\nWhat each plan unlocks is in the table above; credits are the fuel.\nCredit packs\nPacks alone open the Standard studio; plan features need an active plan.\nYour credit bank\nThe most you can hold at once. Plans and packs stack to raise it.\nRoll over, pause, cancel\nCredits roll over while a plan is active. Pause or cancel whenever you like.\nSecurity\nEncrypted in transit\nTLS 1.2 and 1.3. HTTPS enforced.\nEncrypted at rest\nv22.23.4\n",
"type": "text"
}
]
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-a51fa31788d4c9e3",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Pack dollar prices aren't in the static HTML (client-rendered). I'll note that. Maybe check an API for packs? Not necessary.
Now write the example.
File edits
1 file
Writtenexamples/thenewblack/demo.mjsView changes
/sandbox/repo/examples/thenewblack/demo.mjs
Written content · previous contents were not recorded
#!/usr/bin/env node/*** The New Black AI — minimal hosted-API example (zero dependencies, Node >= 18).** The whole product is hosted: https://thenewblack.ai/api/v1 — nothing to run locally.* The public, key-free endpoints (openapi.json, /catalog) let you read the live* contract and prices before you spend a credit.** Usage:* node demo.mjs # dry run: live catalogue + price, no key needed* node demo.mjs --list # every workflow with its prices* node demo.mjs --workflow create_design-v1 --prompt "..." --tier standard* TNB_API_KEY=tnb_live_... node demo.mjs --workflow create_design-v1 --prompt "..." --run** --run submits for real (credits are debited at submission, refunded on failure).* Without --run or without TNB_API_KEY the script only prints what it would send.*/const BASE = process.env.TNB_API_URL || "https://thenewblack.ai/api/v1";const KEY = process.env.TNB_API_KEY || "";const argv = process.argv.slice(2);const flag = (name, dflt = undefined) => {const i = argv.indexOf(`--${name}`);return i === -1 ? dflt : argv[i + 1];};const has = (name) => argv.includes(`--${name}`);async function json(path, init) {const res = await fetch(BASE + path, {...init,headers: {"Content-Type": "application/json",...(KEY ? { Authorization: `Bearer ${KEY}` } : {}),...(init?.headers || {}),},});const body = await res.json().catch(() => ({}));if (!res.ok) {const e = body.error || {};throw new Error(`${res.status} ${e.code || res.statusText}: ${e.message || ""}`.trim());}return body;}const priceOf = (w, tier) => {const c = w.credits?.[tier] ?? w.credits?.standard;if (c == null) return "—";return w.mode === "video" ? `${c} cr/s` : `${c} cr`;};async function listCatalog() {const { workflows } = await json("/catalog"); // public, no keyfor (const w of workflows) {console.log([w.endpoint.padEnd(34), w.mode.padEnd(6),`std ${priceOf(w, "standard")}`.padEnd(14),`pro ${priceOf(w, "pro")}`.padEnd(14),`ultra ${priceOf(w, "ultra")}`].join(" "));}console.log(`\n${workflows.length} workflows. Prices read live from the catalogue.`);}async function main() {if (has("list")) return listCatalog();const workflow = flag("workflow", "create_design-v1");const prompt = flag("prompt", "a minimal linen overshirt, sand colour, studio light");const tier = flag("tier", "standard");const ratio = flag("ratio", "4:5");// 1. Read the live contract for this workflow (public, costs nothing).const { workflows } = await json("/catalog");const w = workflows.find((x) => x.endpoint === workflow);if (!w) throw new Error(`unknown workflow ${workflow} — run with --list`);console.log(`${w.endpoint} · ${w.title} (${w.mode})`);console.log(` price : ${priceOf(w, tier)} (${w.credits?.unit || "per generation"})`);console.log(` images : ${w.images.map((i) => i.param).join(", ") || "none"}`);console.log(` fields : ${w.fields.map((f) => f.param || f.name).join(", ") || "none"}`);console.log(` ratios : ${w.ratios.join(" ") || "none"}`);console.log(` prompt : ${w.prompt_required ? "required" : "optional"}`);const payload = { workflow, tier, ...(w.takes_prompt ? { prompt } : {}), ...(w.ratios.length ? { ratio } : {}) };// 2. Without a key (or without --run) stop here: show the exact request.if (!KEY || !has("run")) {console.log(`\nDRY RUN${KEY ? "" : " (no TNB_API_KEY)"} — would POST ${BASE}/generate:`);console.log(JSON.stringify(payload, null, 2));console.log("\nSet TNB_API_KEY=tnb_live_… and add --run to spend credits for real.");return;}// 3. Balance, submit, poll, save. Reads are free and not rate limited.console.log(`\ncredits before: ${(await json("/credits")).credits}`);const submitted = await json("/generate", { method: "POST", body: JSON.stringify(payload) });console.log(`submitted: ${submitted.generation_id} (${submitted.status})`);const poll = submitted.poll.replace(/^\/api\/v1/, "") || `/generations/${submitted.generation_id}`;const started = Date.now();for (;;) {await new Promise((r) => setTimeout(r, 5000));const g = await json(poll);process.stdout.write(` ${((Date.now() - started) / 1000).toFixed(0)}s ${g.status}\n`);if (g.status === "succeeded") {console.log(`result (${g.result.type}): ${g.result.url}`);console.log("URL lives 48 h — copy it to your own storage.");return;}if (g.status === "failed") {console.log("failed — credits refunded automatically.");return;}if (Date.now() - started > 10 * 60 * 1000) return console.log("gave up after 10 min; poll the id later.");}}main().catch((e) => {console.error(e.message);process.exit(1);});
Source: write · chatcmpl-tool-8077e8748c05bfcb
Recorded tool call
{
"type": "tool_call",
"seq": 63,
"ts": "2026-10-30T20:24:04.997Z",
"name": "write",
"turn": 1,
"input": {
"path": "/sandbox/repo/examples/thenewblack/demo.mjs",
"content": "#!/usr/bin/env node\n/**\n * The New Black AI — minimal hosted-API example (zero dependencies, Node >= 18).\n *\n * The whole product is hosted: https://thenewblack.ai/api/v1 — nothing to run locally.\n * The public, key-free endpoints (openapi.json, /catalog) let you read the live\n * contract and prices before you spend a credit.\n *\n * Usage:\n * node demo.mjs # dry run: live catalogue + price, no key needed\n * node demo.mjs --list # every workflow with its prices\n * node demo.mjs --workflow create_design-v1 --prompt \"...\" --tier standard\n * TNB_API_KEY=tnb_live_... node demo.mjs --workflow create_design-v1 --prompt \"...\" --run\n *\n * --run submits for real (credits are debited at submission, refunded on failure).\n * Without --run or without TNB_API_KEY the script only prints what it would send.\n */\n\nconst BASE = process.env.TNB_API_URL || \"https://thenewblack.ai/api/v1\";\nconst KEY = process.env.TNB_API_KEY || \"\";\n\nconst argv = process.argv.slice(2);\nconst flag = (name, dflt = undefined) => {\n const i = argv.indexOf(`--${name}`);\n return i === -1 ? dflt : argv[i + 1];\n};\nconst has = (name) => argv.includes(`--${name}`);\n\nasync function json(path, init) {\n const res = await fetch(BASE + path, {\n ...init,\n headers: {\n \"Content-Type\": \"application/json\",\n ...(KEY ? { Authorization: `Bearer ${KEY}` } : {}),\n ...(init?.headers || {}),\n },\n });\n const body = await res.json().catch(() => ({}));\n if (!res.ok) {\n const e = body.error || {};\n throw new Error(`${res.status} ${e.code || res.statusText}: ${e.message || \"\"}`.trim());\n }\n return body;\n}\n\nconst priceOf = (w, tier) => {\n const c = w.credits?.[tier] ?? w.credits?.standard;\n if (c == null) return \"—\";\n return w.mode === \"video\" ? `${c} cr/s` : `${c} cr`;\n};\n\nasync function listCatalog() {\n const { workflows } = await json(\"/catalog\"); // public, no key\n for (const w of workflows) {\n console.log(\n [w.endpoint.padEnd(34), w.mode.padEnd(6),\n `std ${priceOf(w, \"standard\")}`.padEnd(14),\n `pro ${priceOf(w, \"pro\")}`.padEnd(14),\n `ultra ${priceOf(w, \"ultra\")}`].join(\" \")\n );\n }\n console.log(`\\n${workflows.length} workflows. Prices read live from the catalogue.`);\n}\n\nasync function main() {\n if (has(\"list\")) return listCatalog();\n\n const workflow = flag(\"workflow\", \"create_design-v1\");\n const prompt = flag(\"prompt\", \"a minimal linen overshirt, sand colour, studio light\");\n const tier = flag(\"tier\", \"standard\");\n const ratio = flag(\"ratio\", \"4:5\");\n\n // 1. Read the live contract for this workflow (public, costs nothing).\n const { workflows } = await json(\"/catalog\");\n const w = workflows.find((x) => x.endpoint === workflow);\n if (!w) throw new Error(`unknown workflow ${workflow} — run with --list`);\n\n console.log(`${w.endpoint} · ${w.title} (${w.mode})`);\n console.log(` price : ${priceOf(w, tier)} (${w.credits?.unit || \"per generation\"})`);\n console.log(` images : ${w.images.map((i) => i.param).join(\", \") || \"none\"}`);\n console.log(` fields : ${w.fields.map((f) => f.param || f.name).join(\", \") || \"none\"}`);\n console.log(` ratios : ${w.ratios.join(\" \") || \"none\"}`);\n console.log(` prompt : ${w.prompt_required ? \"required\" : \"optional\"}`);\n\n const payload = { workflow, tier, ...(w.takes_prompt ? { prompt } : {}), ...(w.ratios.length ? { ratio } : {}) };\n\n // 2. Without a key (or without --run) stop here: show the exact request.\n if (!KEY || !has(\"run\")) {\n console.log(`\\nDRY RUN${KEY ? \"\" : \" (no TNB_API_KEY)\"} — would POST ${BASE}/generate:`);\n console.log(JSON.stringify(payload, null, 2));\n console.log(\"\\nSet TNB_API_KEY=tnb_live_… and add --run to spend credits for real.\");\n return;\n }\n\n // 3. Balance, submit, poll, save. Reads are free and not rate limited.\n console.log(`\\ncredits before: ${(await json(\"/credits\")).credits}`);\n const submitted = await json(\"/generate\", { method: \"POST\", body: JSON.stringify(payload) });\n console.log(`submitted: ${submitted.generation_id} (${submitted.status})`);\n\n const poll = submitted.poll.replace(/^\\/api\\/v1/, \"\") || `/generations/${submitted.generation_id}`;\n const started = Date.now();\n for (;;) {\n await new Promise((r) => setTimeout(r, 5000));\n const g = await json(poll);\n process.stdout.write(` ${((Date.now() - started) / 1000).toFixed(0)}s ${g.status}\\n`);\n if (g.status === \"succeeded\") {\n console.log(`result (${g.result.type}): ${g.result.url}`);\n console.log(\"URL lives 48 h — copy it to your own storage.\");\n return;\n }\n if (g.status === \"failed\") {\n console.log(\"failed — credits refunded automatically.\");\n return;\n }\n if (Date.now() - started > 10 * 60 * 1000) return console.log(\"gave up after 10 min; poll the id later.\");\n }\n}\n\nmain().catch((e) => {\n console.error(e.message);\n process.exit(1);\n});\n"
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-8077e8748c05bfcb",
"tool_kind": "file_edit"
}Recorded tool result
{
"type": "tool_result",
"seq": 65,
"ts": "2026-10-30T20:24:04.997Z",
"turn": 1,
"output": {
"content": [
{
"text": "Successfully wrote 4884 bytes to /sandbox/repo/examples/thenewblack/demo.mjs",
"type": "text"
}
]
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-8077e8748c05bfcb",
"is_error": false,
"tool_kind": "file_edit"
}File edits
1 file
Writtenexamples/thenewblack/README.mdView changes
/sandbox/repo/examples/thenewblack/README.md
Written content · previous contents were not recorded
# The New Black AI — minimal exampleHosted AI fashion-image/video generation. Everything runs on their servers; there isnothing to install or run locally beyond this script.- API base: `https://thenewblack.ai/api/v1` (JSON in / JSON out, `Authorization: Bearer tnb_live_…`)- Live contract, public and key-free: `GET /api/v1/openapi.json`, `GET /api/v1/catalog`- Docs: https://thenewblack.ai/clothing_fashion_api_integrations- Official CLI (same API, JSON out): `npx @thenewblack/cli --help`## Run```shnode demo.mjs --list # every workflow + live prices (no key)node demo.mjs # dry run of one generation (no key)TNB_API_KEY=tnb_live_… node demo.mjs --run \--workflow create_design-v1 --prompt "a minimal linen overshirt, sand colour" --tier standard```Keys are created in the account's **API / MCP tab** (up to 3, with scopes `read`,`generate`, `publish`, `agents`). `TNB_API_KEY` in the environment wins over `tnb login`.## Flow1. `GET /catalog` — the workflow's image params, fields, ratios, tiers and **price** (free).2. `GET /credits` — balance (free, not rate limited).3. `POST /generate` → `202` + `generation_id` + `poll` URL. Credits debited at submission.4. `GET /generations/{id}` every few seconds until `succeeded` / `failed` (failures refund),or pass `webhook_url` and let them POST the outcome once.5. Download `result.url` — it expires after **48 hours**.Errors carry a stable `code`: `missing_key`/`invalid_key` (401), `insufficient_credits` (402),`missing_scope` (403), `unknown_workflow`/`not_found` (404), `rate_limited` (429 + `Retry-After`,nothing charged), `generation_refused` (502, refunded).## Pricing (as of 2026-10-30)Credits are the fuel, the plan is the licence.| Plan | $/mo | Credits/mo | Hold up to | API rate (generations/min) ||---|---|---|---|---|| Packs only | top-up | — | pack size | 30 || Starter | 15 | 200 | 700 | 30 || Pro | 35 | 500 | 2,000 | 60 || Business | 65 | 1,000 | 4,000 | 120 || Enterprise | 195 | 3,000 | 12,000 | 300 |Per-generation cost is per workflow **and tier** — `standard` / `pro` / `ultra`(1K→2K→4K images; 720p→1080p video). Typical image: 1 / 3 / 7 credits; video is billed**per second of output** (e.g. 2.2 / 4.4 / 23 cr/s); `remove_background` 0.5 cr;`create_3d_models` 10 cr. Their rule of thumb: 1 credit ≈ 1 image, 10 credits ≈ 1 video.Ultra photos need the Pro plan or above. Credits roll over while a plan is active; packsalone unlock only the Standard studio. Yearly billing = 2 months free.
Source: write · chatcmpl-tool-9485a2cd3180a9bf
Recorded tool call
{
"type": "tool_call",
"seq": 64,
"ts": "2026-10-30T20:24:04.997Z",
"name": "write",
"turn": 1,
"input": {
"path": "/sandbox/repo/examples/thenewblack/README.md",
"content": "# The New Black AI — minimal example\n\nHosted AI fashion-image/video generation. Everything runs on their servers; there is\nnothing to install or run locally beyond this script.\n\n- API base: `https://thenewblack.ai/api/v1` (JSON in / JSON out, `Authorization: Bearer tnb_live_…`)\n- Live contract, public and key-free: `GET /api/v1/openapi.json`, `GET /api/v1/catalog`\n- Docs: https://thenewblack.ai/clothing_fashion_api_integrations\n- Official CLI (same API, JSON out): `npx @thenewblack/cli --help`\n\n## Run\n\n```sh\nnode demo.mjs --list # every workflow + live prices (no key)\nnode demo.mjs # dry run of one generation (no key)\nTNB_API_KEY=tnb_live_… node demo.mjs --run \\\n --workflow create_design-v1 --prompt \"a minimal linen overshirt, sand colour\" --tier standard\n```\n\nKeys are created in the account's **API / MCP tab** (up to 3, with scopes `read`,\n`generate`, `publish`, `agents`). `TNB_API_KEY` in the environment wins over `tnb login`.\n\n## Flow\n\n1. `GET /catalog` — the workflow's image params, fields, ratios, tiers and **price** (free).\n2. `GET /credits` — balance (free, not rate limited).\n3. `POST /generate` → `202` + `generation_id` + `poll` URL. Credits debited at submission.\n4. `GET /generations/{id}` every few seconds until `succeeded` / `failed` (failures refund),\n or pass `webhook_url` and let them POST the outcome once.\n5. Download `result.url` — it expires after **48 hours**.\n\nErrors carry a stable `code`: `missing_key`/`invalid_key` (401), `insufficient_credits` (402),\n`missing_scope` (403), `unknown_workflow`/`not_found` (404), `rate_limited` (429 + `Retry-After`,\nnothing charged), `generation_refused` (502, refunded).\n\n## Pricing (as of 2026-10-30)\n\nCredits are the fuel, the plan is the licence.\n\n| Plan | $/mo | Credits/mo | Hold up to | API rate (generations/min) |\n|---|---|---|---|---|\n| Packs only | top-up | — | pack size | 30 |\n| Starter | 15 | 200 | 700 | 30 |\n| Pro | 35 | 500 | 2,000 | 60 |\n| Business | 65 | 1,000 | 4,000 | 120 |\n| Enterprise | 195 | 3,000 | 12,000 | 300 |\n\nPer-generation cost is per workflow **and tier** — `standard` / `pro` / `ultra`\n(1K→2K→4K images; 720p→1080p video). Typical image: 1 / 3 / 7 credits; video is billed\n**per second of output** (e.g. 2.2 / 4.4 / 23 cr/s); `remove_background` 0.5 cr;\n`create_3d_models` 10 cr. Their rule of thumb: 1 credit ≈ 1 image, 10 credits ≈ 1 video.\nUltra photos need the Pro plan or above. Credits roll over while a plan is active; packs\nalone unlock only the Standard studio. Yearly billing = 2 months free.\n"
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-9485a2cd3180a9bf",
"tool_kind": "file_edit"
}Recorded tool result
{
"type": "tool_result",
"seq": 66,
"ts": "2026-10-30T20:24:04.997Z",
"turn": 1,
"output": {
"content": [
{
"text": "Successfully wrote 2593 bytes to /sandbox/repo/examples/thenewblack/README.md",
"type": "text"
}
]
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-9485a2cd3180a9bf",
"is_error": false,
"tool_kind": "file_edit"
}›Thinking…
Now run it to verify (quick, no long-running). Test --list (truncate), dry run, and a bogus key path to show error handling.
cd /sandbox/repo/examples/thenewblack && timeout 60 node demo.mjs --list 2>&1 | head -12; echo "=== dry run ==="; timeout 60 node demo.mjs 2>&1; echo "=== bad key ==="; TNB_API_KEY=tnb_live_nope timeout 60 node demo.mjs --run 2>&1 | tail -3
freeform_image-v1 image std 1 cr pro 3 cr ultra 7 cr
freeform_image-v1 image std 1 cr pro 3 cr ultra 7 cr
freeform_video-v1 video std 2.2 cr/s pro 4.4 cr/s ultra 23 cr/s
virtual_try_on-v1 image std 1 cr pro 3 cr ultra 7 cr
product_to_model-v1 image std 1 cr pro 3 cr ultra 7 cr
image_to_ghost_mannequin-v1 image std 1 cr pro 3 cr ultra 7 cr
change_color-v1 image std 1 cr pro 3 cr ultra 7 cr
create_design-v1 image std 1 cr pro 3 cr ultra 7 cr
enhance_photo_to_hd-v1 image std 1 cr pro 3 cr ultra 1 cr
retouch-v1 image std 1 cr pro 3 cr ultra 1 cr
reimagine_scene-v1 image std 1 cr pro 3 cr ultra 7 cr
edit_video-v1 video std 3.3 cr/s pro 4.3 cr/s ultra 3.3 cr/s
motion_design-v1 video std 4 cr/s pro 4 cr/s ultra 4 cr/s
=== dry run ===
create_design-v1 · Create a Product (image)
price : 1 cr (per generation)
images : none
fields : product_type, age, bodyform, gender, country, craziness, outfit, seg_look, seg_view
ratios : 21:9 16:9 3:2 4:3 5:4 1:1 4:5 3:4 2:3 9:16
prompt : optional
DRY RUN (no TNB_API_KEY) — would POST https://thenewblack.ai/api/v1/generate:
{
"workflow": "create_design-v1",
"tier": "standard",
"ratio": "4:5"
}
Set TNB_API_KEY=tnb_live_… and add --run to spend credits for real.
=== bad key ===
ratios : 21:9 16:9 3:2 4:3 5:4 1:1 4:5 3:4 2:3 9:16
prompt : optional
401 invalid_key: This API key is unknown or revoked.
Recorded tool call
{
"type": "tool_call",
"seq": 69,
"ts": "2026-10-30T20:24:07.133Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /sandbox/repo/examples/thenewblack && timeout 60 node demo.mjs --list 2>&1 | head -12; echo \"=== dry run ===\"; timeout 60 node demo.mjs 2>&1; echo \"=== bad key ===\"; TNB_API_KEY=tnb_live_nope timeout 60 node demo.mjs --run 2>&1 | tail -3"
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-845f7808368fda89",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 70,
"ts": "2026-10-30T20:24:09.918Z",
"turn": 1,
"output": {
"content": [
{
"text": "freeform_image-v1 image std 1 cr pro 3 cr ultra 7 cr\nfreeform_video-v1 video std 2.2 cr/s pro 4.4 cr/s ultra 23 cr/s\nvirtual_try_on-v1 image std 1 cr pro 3 cr ultra 7 cr\nproduct_to_model-v1 image std 1 cr pro 3 cr ultra 7 cr\nimage_to_ghost_mannequin-v1 image std 1 cr pro 3 cr ultra 7 cr\nchange_color-v1 image std 1 cr pro 3 cr ultra 7 cr\ncreate_design-v1 image std 1 cr pro 3 cr ultra 7 cr\nenhance_photo_to_hd-v1 image std 1 cr pro 3 cr ultra 1 cr\nretouch-v1 image std 1 cr pro 3 cr ultra 1 cr\nreimagine_scene-v1 image std 1 cr pro 3 cr ultra 7 cr\nedit_video-v1 video std 3.3 cr/s pro 4.3 cr/s ultra 3.3 cr/s\nmotion_design-v1 video std 4 cr/s pro 4 cr/s ultra 4 cr/s\n=== dry run ===\ncreate_design-v1 · Create a Product (image)\n price : 1 cr (per generation)\n images : none\n fields : product_type, age, bodyform, gender, country, craziness, outfit, seg_look, seg_view\n ratios : 21:9 16:9 3:2 4:3 5:4 1:1 4:5 3:4 2:3 9:16\n prompt : optional\n\nDRY RUN (no TNB_API_KEY) — would POST https://thenewblack.ai/api/v1/generate:\n{\n \"workflow\": \"create_design-v1\",\n \"tier\": \"standard\",\n \"ratio\": \"4:5\"\n}\n\nSet TNB_API_KEY=tnb_live_… and add --run to spend credits for real.\n=== bad key ===\n ratios : 21:9 16:9 3:2 4:3 5:4 1:1 4:5 3:4 2:3 9:16\n prompt : optional\n401 invalid_key: This API key is unknown or revoked.\n",
"type": "text"
}
]
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-845f7808368fda89",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Works. Small fix: in dry-run with prompt for create_design, prompt optional so omitted — fine, but the payload omits prompt when takes_prompt false; create_design takes_prompt? It printed prompt: optional, and payload lacks prompt — meaning w.takes_prompt is false for create_design? Payload didn't include prompt. Let me check: takes_prompt for create_design-v1. If takes_prompt is false but prompt is accepted... Let's check catalog entry.
Also "ultra 1 cr" for workflows without ultra — priceOf falls back to standard when ultra missing. Better to print "—" when the tier isn't in w.tiers. Fix that.
Also for the dry-run payload, include prompt when provided regardless (docs say workflows that take one). Let's inspect create_design entry.
cd /tmp && python3 -c "
import json;d=json.load(open('catalog.json'))
w=[x for x in d['workflows'] if x['endpoint']=='create_design-v1'][0]
print({k:w[k] for k in ('takes_prompt','prompt_required','tiers','credits','mode')})
print(json.dumps(w['fields'][0])[:300])
"{'takes_prompt': False, 'prompt_required': False, 'tiers': ['standard', 'pro', 'ultra'], 'credits': {'standard': 1, 'pro': 3, 'ultra': 7, 'unit': 'per generatio
{'takes_prompt': False, 'prompt_required': False, 'tiers': ['standard', 'pro', 'ultra'], 'credits': {'standard': 1, 'pro': 3, 'ultra': 7, 'unit': 'per generation', 'rounding': 'a fixed price per generation'}, 'mode': 'image'}
{"name": "product_type", "label": "Product", "options": ["garment", "shoes", "bag", "jewelry", "eyewear", "headwear", "other"], "required": false, "hint": "What the product is \u2014 the studio's Product row.", "default": "garment"}
Recorded tool call
{
"type": "tool_call",
"seq": 73,
"ts": "2026-10-30T20:24:13.494Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /tmp && python3 -c \"\nimport json;d=json.load(open('catalog.json'))\nw=[x for x in d['workflows'] if x['endpoint']=='create_design-v1'][0]\nprint({k:w[k] for k in ('takes_prompt','prompt_required','tiers','credits','mode')})\nprint(json.dumps(w['fields'][0])[:300])\n\""
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-b197116f22de813b",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 74,
"ts": "2026-10-30T20:24:13.807Z",
"turn": 1,
"output": {
"content": [
{
"text": "{'takes_prompt': False, 'prompt_required': False, 'tiers': ['standard', 'pro', 'ultra'], 'credits': {'standard': 1, 'pro': 3, 'ultra': 7, 'unit': 'per generation', 'rounding': 'a fixed price per generation'}, 'mode': 'image'}\n{\"name\": \"product_type\", \"label\": \"Product\", \"options\": [\"garment\", \"shoes\", \"bag\", \"jewelry\", \"eyewear\", \"headwear\", \"other\"], \"required\": false, \"hint\": \"What the product is \\u2014 the studio's Product row.\", \"default\": \"garment\"}\n",
"type": "text"
}
]
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-b197116f22de813b",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
So create_design-v1 doesn't take a prompt at all — guided by fields. My default workflow choice with a prompt is misleading. Better default: freeform_image-v1 (prompt_required, no images needed) — a perfect "hello world". Update demo: default workflow freeform_image-v1, and include fields support maybe minimal. Also fix priceOf to show "—" for tiers not offered.
Also default example should include an optional --field key=value support? Keep light: add --field k=v repeatable, small.
Update README accordingly.
File edits
1 file
Modifiedexamples/thenewblack/demo.mjs+33−6View changes
/sandbox/repo/examples/thenewblack/demo.mjs
Replacement excerpt
- * node demo.mjs --workflow create_design-v1 --prompt "..." --tier standard- * TNB_API_KEY=tnb_live_... node demo.mjs --workflow create_design-v1 --prompt "..." --run+ * node demo.mjs --workflow virtual_try_on-v1 --product_images https://x/dress.jpg+ * TNB_API_KEY=tnb_live_... node demo.mjs --run --prompt "..." --tier standard --field gender=Woman+ *+ * Repeatable: --field k=v (panel fields), --<param> url|file for named image params.
Replacement excerpt
const priceOf = (w, tier) => {- const c = w.credits?.[tier] ?? w.credits?.standard;+ const c = (w.tiers || []).includes(tier) ? w.credits?.[tier] : null;if (c == null) return "—";
Replacement excerpt
- const workflow = flag("workflow", "create_design-v1");+ const workflow = flag("workflow", "freeform_image-v1");const prompt = flag("prompt", "a minimal linen overshirt, sand colour, studio light");
Replacement excerpt
- const payload = { workflow, tier, ...(w.takes_prompt ? { prompt } : {}), ...(w.ratios.length ? { ratio } : {}) };+ // Named image params (--product_images https://… ) and panel fields (--field gender=Woman).+ for (const img of w.images) {+ const v = flag(img.param);+ if (v) payloadImages[img.param] = img.multiple ? argv.slice(argv.indexOf(`--${img.param}`) + 1).filter((x) => !x.startsWith("--") && x !== v).concat(v) : v;+ }+ const fields = {};+ for (const a of argv) {+ const m = /^--field$/.exec(a);+ if (m) continue;+ }+ argv.forEach((a, i) => {+ if (a === "--field" && argv[i + 1]) {+ const [k, ...rest] = argv[i + 1].split("=");+ fields[k] = rest.join("=");+ }+ });++ const payload = {+ workflow,+ tier,+ ...(w.takes_prompt ? { prompt } : {}),+ ...(w.ratios.includes(ratio) ? { ratio } : {}),+ ...payloadImages,+ ...(Object.keys(fields).length ? { fields } : {}),+ };
Replacement excerpt
- console.log(` fields : ${w.fields.map((f) => f.param || f.name).join(", ") || "none"}`);+ console.log(` fields : ${w.fields.map((f) => `${f.name}${f.required ? "*" : ""}`).join(", ") || "none"}`);
Replacement excerpt
const ratio = flag("ratio", "4:5");+ const payloadImages = {};
Source: edit · chatcmpl-tool-bdeaf0c53f57b778
Recorded tool call
{
"type": "tool_call",
"seq": 77,
"ts": "2026-10-30T20:24:22.898Z",
"name": "edit",
"turn": 1,
"input": {
"path": "/sandbox/repo/examples/thenewblack/demo.mjs",
"edits": [
{
"newText": " * node demo.mjs --workflow virtual_try_on-v1 --product_images https://x/dress.jpg\n * TNB_API_KEY=tnb_live_... node demo.mjs --run --prompt \"...\" --tier standard --field gender=Woman\n *\n * Repeatable: --field k=v (panel fields), --<param> url|file for named image params.",
"oldText": " * node demo.mjs --workflow create_design-v1 --prompt \"...\" --tier standard\n * TNB_API_KEY=tnb_live_... node demo.mjs --workflow create_design-v1 --prompt \"...\" --run"
},
{
"newText": "const priceOf = (w, tier) => {\n const c = (w.tiers || []).includes(tier) ? w.credits?.[tier] : null;\n if (c == null) return \"—\";",
"oldText": "const priceOf = (w, tier) => {\n const c = w.credits?.[tier] ?? w.credits?.standard;\n if (c == null) return \"—\";"
},
{
"newText": " const workflow = flag(\"workflow\", \"freeform_image-v1\");\n const prompt = flag(\"prompt\", \"a minimal linen overshirt, sand colour, studio light\");",
"oldText": " const workflow = flag(\"workflow\", \"create_design-v1\");\n const prompt = flag(\"prompt\", \"a minimal linen overshirt, sand colour, studio light\");"
},
{
"newText": " // Named image params (--product_images https://… ) and panel fields (--field gender=Woman).\n for (const img of w.images) {\n const v = flag(img.param);\n if (v) payloadImages[img.param] = img.multiple ? argv.slice(argv.indexOf(`--${img.param}`) + 1).filter((x) => !x.startsWith(\"--\") && x !== v).concat(v) : v;\n }\n const fields = {};\n for (const a of argv) {\n const m = /^--field$/.exec(a);\n if (m) continue;\n }\n argv.forEach((a, i) => {\n if (a === \"--field\" && argv[i + 1]) {\n const [k, ...rest] = argv[i + 1].split(\"=\");\n fields[k] = rest.join(\"=\");\n }\n });\n\n const payload = {\n workflow,\n tier,\n ...(w.takes_prompt ? { prompt } : {}),\n ...(w.ratios.includes(ratio) ? { ratio } : {}),\n ...payloadImages,\n ...(Object.keys(fields).length ? { fields } : {}),\n };",
"oldText": " const payload = { workflow, tier, ...(w.takes_prompt ? { prompt } : {}), ...(w.ratios.length ? { ratio } : {}) };"
},
{
"newText": " console.log(` fields : ${w.fields.map((f) => `${f.name}${f.required ? \"*\" : \"\"}`).join(\", \") || \"none\"}`);",
"oldText": " console.log(` fields : ${w.fields.map((f) => f.param || f.name).join(\", \") || \"none\"}`);"
},
{
"newText": " const ratio = flag(\"ratio\", \"4:5\");\n const payloadImages = {};",
"oldText": " const ratio = flag(\"ratio\", \"4:5\");"
}
]
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-bdeaf0c53f57b778",
"tool_kind": "file_edit"
}Recorded tool result
{
"type": "tool_result",
"seq": 78,
"ts": "2026-10-30T20:24:22.898Z",
"turn": 1,
"output": {
"content": [
{
"text": "Successfully replaced 6 block(s) in /sandbox/repo/examples/thenewblack/demo.mjs.",
"type": "text"
}
],
"details": {
"diff": " ...\n 8 *\n 9 * Usage:\n 10 * node demo.mjs # dry run: live catalogue + price, no key needed\n 11 * node demo.mjs --list # every workflow with its prices\n- 12 * node demo.mjs --workflow create_design-v1 --prompt \"...\" --tier standard\n- 13 * TNB_API_KEY=tnb_live_... node demo.mjs --workflow create_design-v1 --prompt \"...\" --run\n+ 12 * node demo.mjs --workflow virtual_try_on-v1 --product_images https://x/dress.jpg\n+ 13 * TNB_API_KEY=tnb_live_... node demo.mjs --run --prompt \"...\" --tier standard --field gender=Woman\n 14 *\n+ 15 * Repeatable: --field k=v (panel fields), --<param> url|file for named image params.\n+ 16 *\n 15 * --run submits for real (credits are debited at submission, refunded on failure).\n 16 * Without --run or without TNB_API_KEY the script only prints what it would send.\n 17 */\n 18 \n ...\n 43 return body;\n 44 }\n 45 \n 46 const priceOf = (w, tier) => {\n- 47 const c = w.credits?.[tier] ?? w.credits?.standard;\n+ 49 const c = (w.tiers || []).includes(tier) ? w.credits?.[tier] : null;\n 48 if (c == null) return \"—\";\n 49 return w.mode === \"video\" ? `${c} cr/s` : `${c} cr`;\n 50 };\n 51 \n ...\n 64 \n 65 async function main() {\n 66 if (has(\"list\")) return listCatalog();\n 67 \n- 68 const workflow = flag(\"workflow\", \"create_design-v1\");\n+ 70 const workflow = flag(\"workflow\", \"freeform_image-v1\");\n 69 const prompt = flag(\"prompt\", \"a minimal linen overshirt, sand colour, studio light\");\n 70 const tier = flag(\"tier\", \"standard\");\n 71 const ratio = flag(\"ratio\", \"4:5\");\n+ 74 const payloadImages = {};\n 72 \n 73 // 1. Read the live contract for this workflow (public, costs nothing).\n 74 const { workflows } = await json(\"/catalog\");\n 75 const w = workflows.find((x) => x.endpoint === workflow);\n ...\n 77 \n 78 console.log(`${w.endpoint} · ${w.title} (${w.mode})`);\n 79 console.log(` price : ${priceOf(w, tier)} (${w.credits?.unit || \"per generation\"})`);\n 80 console.log(` images : ${w.images.map((i) => i.param).join(\", \") || \"none\"}`);\n- 81 console.log(` fields : ${w.fields.map((f) => f.param || f.name).join(\", \") || \"none\"}`);\n+ 84 console.log(` fields : ${w.fields.map((f) => `${f.name}${f.required ? \"*\" : \"\"}`).join(\", \") || \"none\"}`);\n 82 console.log(` ratios : ${w.ratios.join(\" \") || \"none\"}`);\n 83 console.log(` prompt : ${w.prompt_required ? \"required\" : \"optional\"}`);\n 84 \n- 85 const payload = { workflow, tier, ...(w.takes_prompt ? { prompt } : {}), ...(w.ratios.length ? { ratio } : {}) };\n+ 88 // Named image params (--product_images https://… ) and panel fields (--field gender=Woman).\n+ 89 for (const img of w.images) {\n+ 90 const v = flag(img.param);\n+ 91 if (v) payloadImages[img.param] = img.multiple ? argv.slice(argv.indexOf(`--${img.param}`) + 1).filter((x) => !x.startsWith(\"--\") && x !== v).concat(v) : v;\n+ 92 }\n+ 93 const fields = {};\n+ 94 for (const a of argv) {\n+ 95 const m = /^--field$/.exec(a);\n+ 96 if (m) continue;\n+ 97 }\n+ 98 argv.forEach((a, i) => {\n+ 99 if (a === \"--field\" && argv[i + 1]) {\n+100 const [k, ...rest] = argv[i + 1].split(\"=\");\n+101 fields[k] = rest.join(\"=\");\n+102 }\n+103 });\n 86 \n+105 const payload = {\n+106 workflow,\n+107 tier,\n+108 ...(w.takes_prompt ? { prompt } : {}),\n+109 ...(w.ratios.includes(ratio) ? { ratio } : {}),\n+110 ...payloadImages,\n+111 ...(Object.keys(fields).length ? { fields } : {}),\n+112 };\n+113 \n 87 // 2. Without a key (or without --run) stop here: show the exact request.\n 88 if (!KEY || !has(\"run\")) {\n 89 console.log(`\\nDRY RUN${KEY ? \"\" : \" (no TNB_API_KEY)\"} — would POST ${BASE}/generate:`);\n 90 console.log(JSON.stringify(payload, null, 2));\n ...",
"patch": "--- /sandbox/repo/examples/thenewblack/demo.mjs\n+++ /sandbox/repo/examples/thenewblack/demo.mjs\n@@ -8,11 +8,13 @@\n *\n * Usage:\n * node demo.mjs # dry run: live catalogue + price, no key needed\n * node demo.mjs --list # every workflow with its prices\n- * node demo.mjs --workflow create_design-v1 --prompt \"...\" --tier standard\n- * TNB_API_KEY=tnb_live_... node demo.mjs --workflow create_design-v1 --prompt \"...\" --run\n+ * node demo.mjs --workflow virtual_try_on-v1 --product_images https://x/dress.jpg\n+ * TNB_API_KEY=tnb_live_... node demo.mjs --run --prompt \"...\" --tier standard --field gender=Woman\n *\n+ * Repeatable: --field k=v (panel fields), --<param> url|file for named image params.\n+ *\n * --run submits for real (credits are debited at submission, refunded on failure).\n * Without --run or without TNB_API_KEY the script only prints what it would send.\n */\n \n@@ -43,9 +45,9 @@\n return body;\n }\n \n const priceOf = (w, tier) => {\n- const c = w.credits?.[tier] ?? w.credits?.standard;\n+ const c = (w.tiers || []).includes(tier) ? w.credits?.[tier] : null;\n if (c == null) return \"—\";\n return w.mode === \"video\" ? `${c} cr/s` : `${c} cr`;\n };\n \n@@ -64,12 +66,13 @@\n \n async function main() {\n if (has(\"list\")) return listCatalog();\n \n- const workflow = flag(\"workflow\", \"create_design-v1\");\n+ const workflow = flag(\"workflow\", \"freeform_image-v1\");\n const prompt = flag(\"prompt\", \"a minimal linen overshirt, sand colour, studio light\");\n const tier = flag(\"tier\", \"standard\");\n const ratio = flag(\"ratio\", \"4:5\");\n+ const payloadImages = {};\n \n // 1. Read the live contract for this workflow (public, costs nothing).\n const { workflows } = await json(\"/catalog\");\n const w = workflows.find((x) => x.endpoint === workflow);\n@@ -77,14 +80,38 @@\n \n console.log(`${w.endpoint} · ${w.title} (${w.mode})`);\n console.log(` price : ${priceOf(w, tier)} (${w.credits?.unit || \"per generation\"})`);\n console.log(` images : ${w.images.map((i) => i.param).join(\", \") || \"none\"}`);\n- console.log(` fields : ${w.fields.map((f) => f.param || f.name).join(\", \") || \"none\"}`);\n+ console.log(` fields : ${w.fields.map((f) => `${f.name}${f.required ? \"*\" : \"\"}`).join(\", \") || \"none\"}`);\n console.log(` ratios : ${w.ratios.join(\" \") || \"none\"}`);\n console.log(` prompt : ${w.prompt_required ? \"required\" : \"optional\"}`);\n \n- const payload = { workflow, tier, ...(w.takes_prompt ? { prompt } : {}), ...(w.ratios.length ? { ratio } : {}) };\n+ // Named image params (--product_images https://… ) and panel fields (--field gender=Woman).\n+ for (const img of w.images) {\n+ const v = flag(img.param);\n+ if (v) payloadImages[img.param] = img.multiple ? argv.slice(argv.indexOf(`--${img.param}`) + 1).filter((x) => !x.startsWith(\"--\") && x !== v).concat(v) : v;\n+ }\n+ const fields = {};\n+ for (const a of argv) {\n+ const m = /^--field$/.exec(a);\n+ if (m) continue;\n+ }\n+ argv.forEach((a, i) => {\n+ if (a === \"--field\" && argv[i + 1]) {\n+ const [k, ...rest] = argv[i + 1].split(\"=\");\n+ fields[k] = rest.join(\"=\");\n+ }\n+ });\n \n+ const payload = {\n+ workflow,\n+ tier,\n+ ...(w.takes_prompt ? { prompt } : {}),\n+ ...(w.ratios.includes(ratio) ? { ratio } : {}),\n+ ...payloadImages,\n+ ...(Object.keys(fields).length ? { fields } : {}),\n+ };\n+\n // 2. Without a key (or without --run) stop here: show the exact request.\n if (!KEY || !has(\"run\")) {\n console.log(`\\nDRY RUN${KEY ? \"\" : \" (no TNB_API_KEY)\"} — would POST ${BASE}/generate:`);\n console.log(JSON.stringify(payload, null, 2));\n",
"firstChangedLine": 12
}
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-bdeaf0c53f57b778",
"is_error": false,
"tool_kind": "file_edit"
}›Thinking…
The image-param parsing I wrote is convoluted and buggy. Let me rewrite that block cleanly: a helper to collect values after a flag until next --.
Simplify:
const valuesOf = (name) => {
const out = [];
const i = argv.indexOf(`--${name}`);
if (i === -1) return out;
for (let j = i + 1; j < argv.length && !argv[j].startsWith("--"); j++) out.push(argv[j]);
return out;
};
Then flag(name) = valuesOf(name)[0].
Let me rewrite the file portions cleanly — easier to just rewrite whole file.
File edits
1 file
Writtenexamples/thenewblack/demo.mjsView changes
/sandbox/repo/examples/thenewblack/demo.mjs
Written content · previous contents were not recorded
#!/usr/bin/env node/*** The New Black AI — minimal hosted-API example (zero dependencies, Node >= 18).** Everything is hosted at https://thenewblack.ai/api/v1 — nothing to install or run locally.* The public, key-free endpoints (/catalog, /openapi.json) let you read the live contract* and the prices before you spend a credit.** Usage:* node demo.mjs --list # every workflow with live prices (no key)* node demo.mjs # dry run: contract + price + request body* node demo.mjs --workflow virtual_try_on-v1 --product_images https://x/dress.jpg \* --model_image https://x/model.jpg --field seg_camera=slightly_above* TNB_API_KEY=tnb_live_... node demo.mjs --run --prompt "a linen overshirt, sand colour"** --run submits for real: credits are debited at submission, refunded on failure.* Without --run, or without TNB_API_KEY, nothing is submitted — it only prints the request.*/const BASE = process.env.TNB_API_URL || "https://thenewblack.ai/api/v1";const KEY = process.env.TNB_API_KEY || "";const argv = process.argv.slice(2);const valuesOf = (name) => {const i = argv.indexOf(`--${name}`);if (i === -1) return [];const out = [];for (let j = i + 1; j < argv.length && !argv[j].startsWith("--"); j++) out.push(argv[j]);return out;};const flag = (name, dflt) => valuesOf(name)[0] ?? dflt;const has = (name) => argv.includes(`--${name}`);async function json(path, init) {const res = await fetch(BASE + path, {...init,headers: {"Content-Type": "application/json",...(KEY ? { Authorization: `Bearer ${KEY}` } : {}),...(init?.headers || {}),},});const body = await res.json().catch(() => ({}));if (!res.ok) {const e = body.error || {};throw new Error(`${res.status} ${e.code || res.statusText}: ${e.message || ""}`.trim());}return body;}const priceOf = (w, tier) => {const c = (w.tiers || []).includes(tier) ? w.credits?.[tier] : null;if (c == null) return "—";return w.mode === "video" ? `${c} cr/s` : `${c} cr`;};async function listCatalog() {const { workflows } = await json("/catalog"); // public, no key, freefor (const w of workflows) {console.log([w.endpoint.padEnd(34), w.mode.padEnd(6),`std ${priceOf(w, "standard")}`.padEnd(15),`pro ${priceOf(w, "pro")}`.padEnd(15),`ultra ${priceOf(w, "ultra")}`].join(" "));}console.log(`\n${workflows.length} workflows — prices read live from the catalogue.`);}async function main() {if (has("list")) return listCatalog();const workflow = flag("workflow", "freeform_image-v1");const prompt = flag("prompt", "a minimal linen overshirt, sand colour, studio light");const tier = flag("tier", "standard");const ratio = flag("ratio", "4:5");// 1. Read this workflow's live contract (public, costs nothing).const { workflows } = await json("/catalog");const w = workflows.find((x) => x.endpoint === workflow);if (!w) throw new Error(`unknown workflow ${workflow} — run with --list`);console.log(`${w.endpoint} · ${w.title} (${w.mode})`);console.log(` price : ${priceOf(w, tier)} (${w.credits?.unit || "per generation"})`);console.log(` images : ${w.images.map((i) => `${i.param}${i.required ? "*" : ""}`).join(", ") || "none"}`);console.log(` fields : ${w.fields.map((f) => `${f.name}${f.required ? "*" : ""}`).join(", ") || "none"}`);console.log(` ratios : ${w.ratios.join(" ") || "none"}`);console.log(` prompt : ${w.prompt_required ? "required" : w.takes_prompt ? "optional" : "not accepted"}`);// 2. Build the body: named image params and panel fields, exactly as the catalogue names them.const payload = { workflow, tier };if (w.takes_prompt) payload.prompt = prompt;if (w.ratios.includes(ratio)) payload.ratio = ratio;if (w.mode === "video" && flag("duration")) payload.duration = flag("duration");for (const img of w.images) {const v = valuesOf(img.param);if (v.length) payload[img.param] = img.multiple ? v : v[0]; // https URLs (or upload via /media/upload)}const fields = {};argv.forEach((a, i) => {if (a === "--field" && argv[i + 1]) {const [k, ...rest] = argv[i + 1].split("=");fields[k] = rest.join("=");}});if (Object.keys(fields).length) payload.fields = fields;const missing = w.images.filter((i) => i.required && !payload[i.param]).map((i) => i.param).concat(w.fields.filter((f) => f.required && !(f.name in fields)).map((f) => f.name));if (missing.length) console.log(` MISSING : ${missing.join(", ")}`);// 3. No key, or no --run: stop here and show the exact request.if (!KEY || !has("run")) {console.log(`\nDRY RUN${KEY ? "" : " (no TNB_API_KEY)"} — would POST ${BASE}/generate:`);console.log(JSON.stringify(payload, null, 2));console.log("\nSet TNB_API_KEY=tnb_live_… and add --run to spend credits for real.");return;}// 4. Balance → submit → poll. Reads are free and not rate limited.console.log(`\ncredits before: ${(await json("/credits")).credits}`);const submitted = await json("/generate", { method: "POST", body: JSON.stringify(payload) });console.log(`submitted: ${submitted.generation_id} (${submitted.status})`);const poll = (submitted.poll || `/api/v1/generations/${submitted.generation_id}`).replace(/^\/api\/v1/, "");const started = Date.now();for (;;) {await new Promise((r) => setTimeout(r, 5000));const g = await json(poll);console.log(` ${((Date.now() - started) / 1000).toFixed(0)}s ${g.status}`);if (g.status === "succeeded") {console.log(`result (${g.result.type}): ${g.result.url}`);console.log("That URL lives 48 h — copy the file to your own storage.");return;}if (g.status === "failed") return console.log("failed — credits refunded automatically.");if (Date.now() - started > 10 * 60 * 1000) {return console.log(`still running after 10 min — poll later: GET ${poll}`);}}}main().catch((e) => {console.error(e.message);process.exit(1);});
Source: write · chatcmpl-tool-b7bf7267237226f3
Recorded tool call
{
"type": "tool_call",
"seq": 81,
"ts": "2026-10-30T20:24:45.087Z",
"name": "write",
"turn": 1,
"input": {
"path": "/sandbox/repo/examples/thenewblack/demo.mjs",
"content": "#!/usr/bin/env node\n/**\n * The New Black AI — minimal hosted-API example (zero dependencies, Node >= 18).\n *\n * Everything is hosted at https://thenewblack.ai/api/v1 — nothing to install or run locally.\n * The public, key-free endpoints (/catalog, /openapi.json) let you read the live contract\n * and the prices before you spend a credit.\n *\n * Usage:\n * node demo.mjs --list # every workflow with live prices (no key)\n * node demo.mjs # dry run: contract + price + request body\n * node demo.mjs --workflow virtual_try_on-v1 --product_images https://x/dress.jpg \\\n * --model_image https://x/model.jpg --field seg_camera=slightly_above\n * TNB_API_KEY=tnb_live_... node demo.mjs --run --prompt \"a linen overshirt, sand colour\"\n *\n * --run submits for real: credits are debited at submission, refunded on failure.\n * Without --run, or without TNB_API_KEY, nothing is submitted — it only prints the request.\n */\n\nconst BASE = process.env.TNB_API_URL || \"https://thenewblack.ai/api/v1\";\nconst KEY = process.env.TNB_API_KEY || \"\";\n\nconst argv = process.argv.slice(2);\nconst valuesOf = (name) => {\n const i = argv.indexOf(`--${name}`);\n if (i === -1) return [];\n const out = [];\n for (let j = i + 1; j < argv.length && !argv[j].startsWith(\"--\"); j++) out.push(argv[j]);\n return out;\n};\nconst flag = (name, dflt) => valuesOf(name)[0] ?? dflt;\nconst has = (name) => argv.includes(`--${name}`);\n\nasync function json(path, init) {\n const res = await fetch(BASE + path, {\n ...init,\n headers: {\n \"Content-Type\": \"application/json\",\n ...(KEY ? { Authorization: `Bearer ${KEY}` } : {}),\n ...(init?.headers || {}),\n },\n });\n const body = await res.json().catch(() => ({}));\n if (!res.ok) {\n const e = body.error || {};\n throw new Error(`${res.status} ${e.code || res.statusText}: ${e.message || \"\"}`.trim());\n }\n return body;\n}\n\nconst priceOf = (w, tier) => {\n const c = (w.tiers || []).includes(tier) ? w.credits?.[tier] : null;\n if (c == null) return \"—\";\n return w.mode === \"video\" ? `${c} cr/s` : `${c} cr`;\n};\n\nasync function listCatalog() {\n const { workflows } = await json(\"/catalog\"); // public, no key, free\n for (const w of workflows) {\n console.log(\n [w.endpoint.padEnd(34), w.mode.padEnd(6),\n `std ${priceOf(w, \"standard\")}`.padEnd(15),\n `pro ${priceOf(w, \"pro\")}`.padEnd(15),\n `ultra ${priceOf(w, \"ultra\")}`].join(\" \")\n );\n }\n console.log(`\\n${workflows.length} workflows — prices read live from the catalogue.`);\n}\n\nasync function main() {\n if (has(\"list\")) return listCatalog();\n\n const workflow = flag(\"workflow\", \"freeform_image-v1\");\n const prompt = flag(\"prompt\", \"a minimal linen overshirt, sand colour, studio light\");\n const tier = flag(\"tier\", \"standard\");\n const ratio = flag(\"ratio\", \"4:5\");\n\n // 1. Read this workflow's live contract (public, costs nothing).\n const { workflows } = await json(\"/catalog\");\n const w = workflows.find((x) => x.endpoint === workflow);\n if (!w) throw new Error(`unknown workflow ${workflow} — run with --list`);\n\n console.log(`${w.endpoint} · ${w.title} (${w.mode})`);\n console.log(` price : ${priceOf(w, tier)} (${w.credits?.unit || \"per generation\"})`);\n console.log(` images : ${w.images.map((i) => `${i.param}${i.required ? \"*\" : \"\"}`).join(\", \") || \"none\"}`);\n console.log(` fields : ${w.fields.map((f) => `${f.name}${f.required ? \"*\" : \"\"}`).join(\", \") || \"none\"}`);\n console.log(` ratios : ${w.ratios.join(\" \") || \"none\"}`);\n console.log(` prompt : ${w.prompt_required ? \"required\" : w.takes_prompt ? \"optional\" : \"not accepted\"}`);\n\n // 2. Build the body: named image params and panel fields, exactly as the catalogue names them.\n const payload = { workflow, tier };\n if (w.takes_prompt) payload.prompt = prompt;\n if (w.ratios.includes(ratio)) payload.ratio = ratio;\n if (w.mode === \"video\" && flag(\"duration\")) payload.duration = flag(\"duration\");\n for (const img of w.images) {\n const v = valuesOf(img.param);\n if (v.length) payload[img.param] = img.multiple ? v : v[0]; // https URLs (or upload via /media/upload)\n }\n const fields = {};\n argv.forEach((a, i) => {\n if (a === \"--field\" && argv[i + 1]) {\n const [k, ...rest] = argv[i + 1].split(\"=\");\n fields[k] = rest.join(\"=\");\n }\n });\n if (Object.keys(fields).length) payload.fields = fields;\n\n const missing = w.images.filter((i) => i.required && !payload[i.param]).map((i) => i.param)\n .concat(w.fields.filter((f) => f.required && !(f.name in fields)).map((f) => f.name));\n if (missing.length) console.log(` MISSING : ${missing.join(\", \")}`);\n\n // 3. No key, or no --run: stop here and show the exact request.\n if (!KEY || !has(\"run\")) {\n console.log(`\\nDRY RUN${KEY ? \"\" : \" (no TNB_API_KEY)\"} — would POST ${BASE}/generate:`);\n console.log(JSON.stringify(payload, null, 2));\n console.log(\"\\nSet TNB_API_KEY=tnb_live_… and add --run to spend credits for real.\");\n return;\n }\n\n // 4. Balance → submit → poll. Reads are free and not rate limited.\n console.log(`\\ncredits before: ${(await json(\"/credits\")).credits}`);\n const submitted = await json(\"/generate\", { method: \"POST\", body: JSON.stringify(payload) });\n console.log(`submitted: ${submitted.generation_id} (${submitted.status})`);\n\n const poll = (submitted.poll || `/api/v1/generations/${submitted.generation_id}`).replace(/^\\/api\\/v1/, \"\");\n const started = Date.now();\n for (;;) {\n await new Promise((r) => setTimeout(r, 5000));\n const g = await json(poll);\n console.log(` ${((Date.now() - started) / 1000).toFixed(0)}s ${g.status}`);\n if (g.status === \"succeeded\") {\n console.log(`result (${g.result.type}): ${g.result.url}`);\n console.log(\"That URL lives 48 h — copy the file to your own storage.\");\n return;\n }\n if (g.status === \"failed\") return console.log(\"failed — credits refunded automatically.\");\n if (Date.now() - started > 10 * 60 * 1000) {\n return console.log(`still running after 10 min — poll later: GET ${poll}`);\n }\n }\n}\n\nmain().catch((e) => {\n console.error(e.message);\n process.exit(1);\n});\n"
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-b7bf7267237226f3",
"tool_kind": "file_edit"
}Recorded tool result
{
"type": "tool_result",
"seq": 82,
"ts": "2026-10-30T20:24:45.087Z",
"turn": 1,
"output": {
"content": [
{
"text": "Successfully wrote 6159 bytes to /sandbox/repo/examples/thenewblack/demo.mjs",
"type": "text"
}
]
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-b7bf7267237226f3",
"is_error": false,
"tool_kind": "file_edit"
}›Thinking…
Wait — poll uses KEY auth; the poll request needs read scope. Fine.
One bug: poll path replace — json(poll) prepends BASE. OK.
Test again: --list tail, dry run default, dry run virtual_try_on with missing required images.
cd /sandbox/repo/examples/thenewblack && timeout 60 node demo.mjs 2>&1; echo "=== try-on ==="; timeout 60 node demo.mjs --workflow virtual_try_on-v1 --product_images https://x/dress.jpg --field seg_camera=slightly_above 2>&1 | tail -20; echo "=== list tail ==="; timeout 60 node demo.mjs --list 2>&1 | tail -3
freeform_image-v1 · Free Prompt Image (image)
freeform_image-v1 · Free Prompt Image (image)
price : 1 cr (per generation)
images : reference_images
fields : none
ratios : auto 9:16 1:1 4:5 3:4 2:3 16:9 4:3 3:2 5:4 21:9
prompt : required
DRY RUN (no TNB_API_KEY) — would POST https://thenewblack.ai/api/v1/generate:
{
"workflow": "freeform_image-v1",
"tier": "standard",
"prompt": "a minimal linen overshirt, sand colour, studio light",
"ratio": "4:5"
}
Set TNB_API_KEY=tnb_live_… and add --run to spend credits for real.
=== try-on ===
images : product_images*, model_image*, scene_image
fields : seg_framing, seg_camera, seg_look, seg_scene, seg_features
ratios : auto 21:9 16:9 3:2 4:3 5:4 1:1 4:5 3:4 2:3 9:16
prompt : not accepted
MISSING : model_image
DRY RUN (no TNB_API_KEY) — would POST https://thenewblack.ai/api/v1/generate:
{
"workflow": "virtual_try_on-v1",
"tier": "standard",
"ratio": "4:5",
"product_images": [
"https://x/dress.jpg"
],
"fields": {
"seg_camera": "slightly_above"
}
}
Set TNB_API_KEY=tnb_live_… and add --run to spend credits for real.
=== list tail ===
motion_mix_match-v1 video std 1 cr/s pro 1 cr/s ultra —
77 workflows — prices read live from the catalogue.
Recorded tool call
{
"type": "tool_call",
"seq": 85,
"ts": "2026-10-30T20:24:47.396Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /sandbox/repo/examples/thenewblack && timeout 60 node demo.mjs 2>&1; echo \"=== try-on ===\"; timeout 60 node demo.mjs --workflow virtual_try_on-v1 --product_images https://x/dress.jpg --field seg_camera=slightly_above 2>&1 | tail -20; echo \"=== list tail ===\"; timeout 60 node demo.mjs --list 2>&1 | tail -3"
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-865b2e2ccd26e5ef",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 86,
"ts": "2026-10-30T20:24:48.465Z",
"turn": 1,
"output": {
"content": [
{
"text": "freeform_image-v1 · Free Prompt Image (image)\n price : 1 cr (per generation)\n images : reference_images\n fields : none\n ratios : auto 9:16 1:1 4:5 3:4 2:3 16:9 4:3 3:2 5:4 21:9\n prompt : required\n\nDRY RUN (no TNB_API_KEY) — would POST https://thenewblack.ai/api/v1/generate:\n{\n \"workflow\": \"freeform_image-v1\",\n \"tier\": \"standard\",\n \"prompt\": \"a minimal linen overshirt, sand colour, studio light\",\n \"ratio\": \"4:5\"\n}\n\nSet TNB_API_KEY=tnb_live_… and add --run to spend credits for real.\n=== try-on ===\n images : product_images*, model_image*, scene_image\n fields : seg_framing, seg_camera, seg_look, seg_scene, seg_features\n ratios : auto 21:9 16:9 3:2 4:3 5:4 1:1 4:5 3:4 2:3 9:16\n prompt : not accepted\n MISSING : model_image\n\nDRY RUN (no TNB_API_KEY) — would POST https://thenewblack.ai/api/v1/generate:\n{\n \"workflow\": \"virtual_try_on-v1\",\n \"tier\": \"standard\",\n \"ratio\": \"4:5\",\n \"product_images\": [\n \"https://x/dress.jpg\"\n ],\n \"fields\": {\n \"seg_camera\": \"slightly_above\"\n }\n}\n\nSet TNB_API_KEY=tnb_live_… and add --run to spend credits for real.\n=== list tail ===\nmotion_mix_match-v1 video std 1 cr/s pro 1 cr/s ultra —\n\n77 workflows — prices read live from the catalogue.\n",
"type": "text"
}
]
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-865b2e2ccd26e5ef",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Works. Update README to match new flags (default workflow freeform_image-v1, --field, --duration). Also add a commit? Repo is a git repo; I'll leave committing optional — maybe commit is nice. I'll just leave files; not asked. Actually keeping it clean: no commit unless asked.
Update README run section.
File edits
1 file
Modifiedexamples/thenewblack/README.md+11−2View changes
/sandbox/repo/examples/thenewblack/README.md
Replacement excerpt
node demo.mjs --list # every workflow + live prices (no key)node demo.mjs # dry run of one generation (no key)-TNB_API_KEY=tnb_live_… node demo.mjs --run \- --workflow create_design-v1 --prompt "a minimal linen overshirt, sand colour" --tier standard+node demo.mjs --workflow virtual_try_on-v1 \+ --product_images https://x/dress.jpg --model_image https://x/model.jpg \+ --field seg_camera=slightly_above --ratio 4:5 # flags are validated against the catalogue++TNB_API_KEY=tnb_live_… node demo.mjs --run --tier standard \+ --prompt "a minimal linen overshirt, sand colour, studio light" # spends 1 credit```++Image parameters take public `https` URLs (or upload a local file first:+`POST /v1/media/upload`, multipart `file`, → `{ media_id, url }`). Panel fields go in+`fields` by name — `--field k=v` here. `MISSING:` in the output lists what the workflow+still needs before it would be accepted.
Source: edit · chatcmpl-tool-b76985088bf2b30f
Recorded tool call
{
"type": "tool_call",
"seq": 89,
"ts": "2026-10-30T20:24:55.829Z",
"name": "edit",
"turn": 1,
"input": {
"path": "/sandbox/repo/examples/thenewblack/README.md",
"edits": [
{
"newText": "node demo.mjs --list # every workflow + live prices (no key)\nnode demo.mjs # dry run of one generation (no key)\nnode demo.mjs --workflow virtual_try_on-v1 \\\n --product_images https://x/dress.jpg --model_image https://x/model.jpg \\\n --field seg_camera=slightly_above --ratio 4:5 # flags are validated against the catalogue\n\nTNB_API_KEY=tnb_live_… node demo.mjs --run --tier standard \\\n --prompt \"a minimal linen overshirt, sand colour, studio light\" # spends 1 credit\n```\n\nImage parameters take public `https` URLs (or upload a local file first:\n`POST /v1/media/upload`, multipart `file`, → `{ media_id, url }`). Panel fields go in\n`fields` by name — `--field k=v` here. `MISSING:` in the output lists what the workflow\nstill needs before it would be accepted.",
"oldText": "node demo.mjs --list # every workflow + live prices (no key)\nnode demo.mjs # dry run of one generation (no key)\nTNB_API_KEY=tnb_live_… node demo.mjs --run \\\n --workflow create_design-v1 --prompt \"a minimal linen overshirt, sand colour\" --tier standard\n```"
}
]
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-b76985088bf2b30f",
"tool_kind": "file_edit"
}Recorded tool result
{
"type": "tool_result",
"seq": 90,
"ts": "2026-10-30T20:24:55.829Z",
"turn": 1,
"output": {
"content": [
{
"text": "Successfully replaced 1 block(s) in /sandbox/repo/examples/thenewblack/README.md.",
"type": "text"
}
],
"details": {
"diff": " ...\n 12 \n 13 ```sh\n 14 node demo.mjs --list # every workflow + live prices (no key)\n 15 node demo.mjs # dry run of one generation (no key)\n-16 TNB_API_KEY=tnb_live_… node demo.mjs --run \\\n-17 --workflow create_design-v1 --prompt \"a minimal linen overshirt, sand colour\" --tier standard\n+16 node demo.mjs --workflow virtual_try_on-v1 \\\n+17 --product_images https://x/dress.jpg --model_image https://x/model.jpg \\\n+18 --field seg_camera=slightly_above --ratio 4:5 # flags are validated against the catalogue\n+19 \n+20 TNB_API_KEY=tnb_live_… node demo.mjs --run --tier standard \\\n+21 --prompt \"a minimal linen overshirt, sand colour, studio light\" # spends 1 credit\n 18 ```\n 19 \n+24 Image parameters take public `https` URLs (or upload a local file first:\n+25 `POST /v1/media/upload`, multipart `file`, → `{ media_id, url }`). Panel fields go in\n+26 `fields` by name — `--field k=v` here. `MISSING:` in the output lists what the workflow\n+27 still needs before it would be accepted.\n+28 \n 20 Keys are created in the account's **API / MCP tab** (up to 3, with scopes `read`,\n 21 `generate`, `publish`, `agents`). `TNB_API_KEY` in the environment wins over `tnb login`.\n 22 \n 23 ## Flow\n ...",
"patch": "--- /sandbox/repo/examples/thenewblack/README.md\n+++ /sandbox/repo/examples/thenewblack/README.md\n@@ -12,12 +12,21 @@\n \n ```sh\n node demo.mjs --list # every workflow + live prices (no key)\n node demo.mjs # dry run of one generation (no key)\n-TNB_API_KEY=tnb_live_… node demo.mjs --run \\\n- --workflow create_design-v1 --prompt \"a minimal linen overshirt, sand colour\" --tier standard\n+node demo.mjs --workflow virtual_try_on-v1 \\\n+ --product_images https://x/dress.jpg --model_image https://x/model.jpg \\\n+ --field seg_camera=slightly_above --ratio 4:5 # flags are validated against the catalogue\n+\n+TNB_API_KEY=tnb_live_… node demo.mjs --run --tier standard \\\n+ --prompt \"a minimal linen overshirt, sand colour, studio light\" # spends 1 credit\n ```\n \n+Image parameters take public `https` URLs (or upload a local file first:\n+`POST /v1/media/upload`, multipart `file`, → `{ media_id, url }`). Panel fields go in\n+`fields` by name — `--field k=v` here. `MISSING:` in the output lists what the workflow\n+still needs before it would be accepted.\n+\n Keys are created in the account's **API / MCP tab** (up to 3, with scopes `read`,\n `generate`, `publish`, `agents`). `TNB_API_KEY` in the environment wins over `tnb login`.\n \n ## Flow\n",
"firstChangedLine": 16
}
},
"run_id": "cmvvf5e50001a0im6q07g7of7",
"tool_id": "chatcmpl-tool-b76985088bf2b30f",
"is_error": false,
"tool_kind": "file_edit"
}›Thinking…
I need to wrap up by summarizing the pricing structure, how manageable this is to implement, any blockers we're facing—mainly the missing API key that would prevent running an actual generation—and what files need to be created. I should also verify that the quickstart doesn't require any local infrastructure, which it doesn't, so that's clear.
Yes, there's a real developer workflow — a hosted REST API (no local stack, no long-running services), plus an official CLI, MCP connector, and a public OpenAPI spec.
What I built
examples/thenewblack/demo.mjs — zero-dependency Node ≥18 script, plus examples/thenewblack/README.md.
It: reads the live catalogue (GET /api/v1/catalog, public and free) → prints the workflow's contract and price before spending → builds the request body from the catalogue's own param/field names (and flags MISSING: inputs) → with a key and --run, checks credits, submits, polls to succeeded/failed, and prints the result URL.
Verified against the live API just now:
node demo.mjs --list→ 77 workflows with live std/pro/ultra pricesnode demo.mjs→ dry run forfreeform_image-v1(1 cr), request body printednode demo.mjs --workflow virtual_try_on-v1 …→ correctly reportsMISSING: model_image- bad key → clean
401 invalid_keyhandling
Blocked on one thing only: no TNB_API_KEY in this environment, so I could not execute a paid generation end-to-end. Keys come from the account's API/MCP tab (up to 3, scopes read/generate/publish/agents). Set it and add --run.
How pricing works
Two layers: credits are the fuel, the plan is the licence.
- Per generation, per workflow and tier:
standard/pro/ultra(1K→2K→4K images, 720p→1080p video). Typical image = 1 / 3 / 7 credits;remove_background0.5 cr;create_3d_models10 cr. Video is billed per second of output (e.g. 2.2 / 4.4 / 23 cr/s). Their rule of thumb: 1 credit ≈ 1 image, 10 credits ≈ 1 video. - Plans (monthly, yearly = 2 months free): Starter $15 → 200 cr; Pro $35 → 500 cr; Business $65 → 1,000 cr; Enterprise $195 → 3,000 cr. One-off credit packs work on any account but only unlock the Standard studio; Ultra photos need Pro+. Credits roll over while a plan is active, with a hold cap per plan (700 / 2,000 / 4,000 / 12,000).
- Billing mechanics that matter for code: debited at submission, auto-refunded on failure or
502 generation_refused;402 insufficient_creditsif short;429 rate_limited+Retry-Aftercharges nothing. Rate = generations/min per plan (30 / 30 / 60 / 120 / 300) shared across API+CLI+MCP; reads are free and uncounted.
Will it be easy for me to manage?
Yes — unusually so. Machine-readable contract published key-free (/api/v1/openapi.json, /api/v1/catalog) and generated at call time, so flags/schemas/prices are read live instead of hardcoded; versioned workflow endpoints (create_design-v1) mean old integrations keep working; stable error codes; async submit + poll or single-shot webhook; official no-dependency CLI with JSON output built for agents.
Two things I'd watch: result URLs expire after 48 hours (must copy to your own storage), and webhooks are fire-once with a 5 s timeout, so the poll endpoint stays the source of truth.
AX Fundamentals
23 checks. Open an area for details.
This check is a quick preview. Test more tasks and models with Gauge Agents.
Test your product with Gauge Agents