The API for a listing’s team
If you hold an approved claim on a listing, you can make a personal token and hand it to an agent — Claude, a script, a workflow tool. It can do on your listings what you can do by hand in the admin, and nothing more.
Making a token
At /admin/account, under API tokens. Give it a name you will recognise, choose read only or read and write, and how long it lasts: 30, 90 or 365 days. There is no token that never expires. It is shown once, when it is made; we keep only a one-way hash of it. You can hold 5 at a time and revoke any of them there, which takes effect on the next request.
A token is you. It acts on the listings you hold, as your role on each — a builder’s token publishes, a contributor’s writes drafts — and it never carries anything an admin can do, whatever your account is. Losing a claim, or having your account switched off, stops it at once.
Sending it
Every request carries it in a header. Bodies are JSON, except image uploads.
curl https://nutsgrowth.com/api/me -H "Authorization: Bearer ngp_…"
What it can do
GET /api/me any token
Who the token is, the listings it can work on, and what it may do on each. Start here.
GET /api/listings/{slug} builder or contributor
The listing as it stands, in the shape PATCH takes back.
PATCH /api/listings/{slug} builder or contributor
Its overview, value proposition and audience. Send what you change; null puts back the directory’s own text, which only the builder may.
GET /api/listings/{slug}/history builder or contributor
What has changed on the listing, newest first.
POST /api/listings/{slug}/media builder or contributor
A screenshot for the gallery: the image file is the whole body. ?caption= adds a caption; ?replaces={id} swaps one (builder only).
PATCH /api/listings/{slug}/media/{id} builder or contributor
A picture’s caption.
DELETE /api/listings/{slug}/media/{id} builder only
Take a picture out of the gallery.
POST /api/listings/{slug}/mark builder or contributor
The logo shown on cards: the image file is the whole body.
DELETE /api/listings/{slug}/mark builder only
Take the logo down.
GET /api/listings/{slug}/posts builder or contributor
The listing’s posts, drafts included.
POST /api/listings/{slug}/posts builder or contributor
A post: an update, press material, or a related article elsewhere. A draft unless status is "published", which only the builder may.
GET /api/listings/{slug}/posts/{id} builder or contributor
One post.
PATCH /api/listings/{slug}/posts/{id} builder or contributor
Change a post. Changing its status is publishing, which only the builder may.
DELETE /api/listings/{slug}/posts/{id} builder only
Delete a post.
GET /api/listings/{slug}/coupons builder or contributor
The listing’s offers, drafts included.
POST /api/listings/{slug}/coupons builder or contributor
An offer. A draft unless status is "published", which only the builder may.
GET /api/listings/{slug}/coupons/{id} builder or contributor
One offer.
PATCH /api/listings/{slug}/coupons/{id} builder or contributor
Change an offer. Changing its status is publishing, which only the builder may.
DELETE /api/listings/{slug}/coupons/{id} builder only
Delete an offer.
GET /api/listings/{slug}/corrections builder or contributor
Corrections proposed for the listing’s facts, and what came of them.
POST /api/listings/{slug}/corrections builder or contributor
Propose a correction to a fact, with a link that shows it. A person checks the evidence and decides.
GET /api/blog/posts builder or contributor
Your blog posts, and the ones written as a company you are the builder of.
POST /api/blog/posts builder or contributor
A blog draft, written as a listing you hold. A person publishes it.
GET /api/blog/posts/{id} builder or contributor
One blog post.
PATCH /api/blog/posts/{id} builder or contributor
Change a draft. A published post is changed in the editor.
DELETE /api/blog/posts/{id} builder or contributor
Delete a draft.
Examples
Rewrite the value proposition
curl -X PATCH https://nutsgrowth.com/api/listings/{slug} -H "Authorization: Bearer ngp_…" \
-H "Content-Type: application/json" \
-d '{"value_prop": "Self-hosted analytics with no cookie banner."}'Post an update and publish it
curl -X POST https://nutsgrowth.com/api/listings/{slug}/posts -H "Authorization: Bearer ngp_…" \
-H "Content-Type: application/json" \
-d '{"category": "update", "title": "Version 4.2 is out", "body": "What changed, in markdown.", "status": "published"}'Add an offer
curl -X POST https://nutsgrowth.com/api/listings/{slug}/coupons -H "Authorization: Bearer ngp_…" \
-H "Content-Type: application/json" \
-d '{"headline": "20% off the first year", "code": "NUTS20", "url": "https://example.com/pricing", "expires_at": "2026-12-31"}'Upload a screenshot
curl -X POST "https://nutsgrowth.com/api/listings/{slug}/media?caption=Dashboard" -H "Authorization: Bearer ngp_…" \
--data-binary @dashboard.pngWrite a blog draft
curl -X POST https://nutsgrowth.com/api/blog/posts -H "Authorization: Bearer ngp_…" \
-H "Content-Type: application/json" \
-d '{"writing_as": "{slug}", "title": "How we moved off US clouds", "body": "…", "category": "general"}'The fields
Positioning
overview up to 3000 characters, in paragraphs; value_prop up to 400; audience up to 8 labels of 40 characters. On the page they are marked as your own words. The category, country and the rest of the fact grid are the directory’s record: propose a change to them with evidence, through corrections.
Posts
category is update, press or article (writing about you elsewhere, which needs external_url); title 3 to 200 characters; body in markdown, up to 20000; excerpt up to 400; source up to 120; slug to choose the address; status draft or published. Changing the title never moves a published post’s address; sending a new slug does.
Offers
headline up to 90 characters; detail up to 160; code up to 32; url, a full https:// address where the offer is claimed; expires_at as 2026-12-31; status.
Blog drafts
writing_as, the slug of a listing you hold (fixed once the draft exists); title up to 120 characters; body in markdown, up to 60000; excerpt up to 300; category, one of general, ai-develop-tools; tags, up to 8; declares_affiliate, true if it has affiliate links you added. The blog is the directory’s page, so a person publishes a draft from the editor; the API never does.
Retrying safely
Send an Idempotency-Key header on a create. If the answer is lost and you send the same request with the same key, you get the first answer back instead of a second post. A key belongs to your account: nobody else’s request can collide with it.
Limits
120 requests a minute per token, and 20 new posts, offers and blog drafts per listing a day — enough for real work, and a ceiling for an agent stuck in a loop.
When it says no
- 401 unauthorized — No token, an unknown one, or one that has expired or been revoked.
- 403 read_only_token — A read-only token tried to change something.
- 403 not_your_listing — The account holds no approved claim on that listing.
- 403 not_allowed — A contributor tried something that is the builder’s: publishing, removing, clearing.
- 403 not_for_personal_tokens — A route that only the directory itself uses.
- 404 no_such_listing / no_such_post / … — Not there, or not on the listing in the address.
- 409 published — A blog post that is already live: change it in the editor.
- 422 unsupported_fields, bad_post, bad_offer, … — The body. The message says which field and why; nothing is cut to fit.
- 422 publish_in_admin — A blog post cannot be published through the API.
- 429 throttled / daily_cap — More than 120 requests a minute, or 20 new items on one listing in a day.
What is kept
For each token: its name, a one-way hash of it, when it was made, when it expires, and when it was last used — not the address requests come from. What a token changes is recorded as your account’s change, naming the token. See /privacy.