Agent API v1 · for resellers
You have the brands. We have the creators.
If you already reach founders, marketers or brands — a newsletter, an agency, a community, a client list — you hold the side of the market that's hard to get. We hold the other one: a network of real people who publish. Sell them a monthly presence in the conversations that matter, or a boost on a post they're proud of. One API key. The brand approves the wording before anyone posts.
Other way round — you have creators, not clients? That's the earning side →
Before you build
Four things worth knowing before you write a line. If you've already decided, skip to Set up once — nothing below is required to integrate.
The promise2 minWhat each side of the market brings, and why neither works alone.
What each side of the market brings, and why neither works alone.
Attention is the expensive half of launching anything. Brands can build a product in a weekend and still can't get anyone to talk about it. Creators can publish to a real audience and have nothing worth publishing. ProductClank sits between them: a brief goes in, creators pick it up, and what they publish comes back as a link.
A storefront is a front door onto that. You already have the brands' trust — that's the part we can't buy. We already have the creators — that's the part you'd spend years building. The API connects the two so you never have to.
Why sell itwholesaleMargin, a product for an audience you already have, and nothing to fulfil.
Margin, a product for an audience you already have, and nothing to fulfil.
- You keep the spread. You buy credits at wholesale and sell at whatever your market bears. No revenue share, no platform fee on your sales, nothing to reconcile.
- Nothing to fulfil. Finding the conversations, drafting, creator recruitment, fraud review, proof-of-post, payouts — all on our side of the API. Your job is selling, approving, and showing results.
- It sells as a subscription. A brand's presence in its conversations is a monthly thing, and the cost per month is bounded. See Numbers.
- Your brand end to end. Clients never see ProductClank or need an account here.
What to expecthonestWhat a discovery subscription actually produces, how fast, and what it doesn't.
What a discovery subscription actually produces, how fast, and what it doesn't.
| What we find | Live conversations on X (or LinkedIn, Reddit, YouTube) where the brand's topic is being discussed — 5 per run, scored for relevance. |
| What we draft | One reply per conversation, in the brand's voice from the guidelines you set. The brand can edit any draft before it goes anywhere. |
| What creators do | Claim an approved draft and post it from their own account — a real person, a real reply, in the thread. |
| When it starts | Drafts are ready minutes after a run. Once published, creators pick them up on their own schedule — usually within hours. |
| What a result is | A live link to the reply a named creator posted, plus the engagement it drew. Auto-delivered: it counts the moment it's posted — no review step in your way. |
| How many | Up to the drafts you publish. Creators choose what to pick up. Sell a presence, not a reply count. |
| What happens after | Our fraud review runs in the background. A reply it flags shows review_status: rejected on your results; one the platform removes shows survival_status. Both rare, both visible to you. |
| Disclosure | Every reply is marked as a paid partnership. Required, not optional. |
See what the network is publishing right now on the live feed — every entry links to a real post.
What we commit to24hThe one number, and what we don't promise.
The one number, and what we don't promise.
- A run of discovery returns its drafts within minutes.
- Results are readable the moment a creator posts. No approval step on our side.
- Pilot support: a reply within the day on the thread we open with you.
- Not promised: a number of posted replies. Discovery and drafting are charged when they run; a draft nobody picks up costs you nothing further, but it isn't refunded either. Price a presence, not a count, and your clients will never be surprised.
Set up once
Three calls, or the web app (sign up → /credits → Profile → Developer) if you'd rather click. Same key either way.
caller_user_id and trusted — they're for first-party bots, and a normal key sending them gets 403.1. Get a keyfreeUnauthenticated. Shown exactly once.
Unauthenticated. Shown exactly once.
curl -X POST https://api.productclank.com/api/v1/agents/register \
-H "Content-Type: application/json" \
-d '{ "name": "Acme Creator Studio", "description": "Storefront for Acme's clients" }'pck_live_ and cannot be read back. Server-side secret only — never a browser bundle, client config or public repo. Leaked? POST /agents/rotate-key.2. Fund itcard or cryptoThe API hands you a Stripe Checkout link; a human pays it.
The API hands you a Stripe Checkout link; a human pays it.
curl -X POST https://api.productclank.com/api/v1/agents/credits/topup \
-H "Authorization: Bearer $PC_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "bundle": "large", "payment_method": "card" }'
# → { "status": "awaiting_payment", "checkout_url": "https://checkout.stripe.com/…", "credits": 2600 }Pay the link; credits land within seconds. The response is not a purchase — confirm with step 3. A monthly plan is usually the better buy for a subscription product; see Numbers. Keep a month of every live brand's ceiling on the balance — a run that lands on an empty account is a paying client waiting.
3. VerifyfreeKey works, balance is right, and your daily cap.
Key works, balance is right, and your daily cap.
curl https://api.productclank.com/api/v1/agents/me -H "Authorization: Bearer $PC_API_KEY"
# → { "agent": { "rate_limit_daily": 10, … }, "credits": { "balance": 2600, … } }rate_limit_daily is 10 campaigns per key per day. One campaign per brand means it only bites when you onboard more than ten brands in a day — but send us your agent id and we raise it to 1,000 for the pilot anyway.
Discovery: a brand's presence in its conversations
One campaign per brand, created once. Every day you run discovery, the brand approves the drafts it likes, you publish them, and real people post. The brand sees every reply as it goes up. Five steps — three of them one call each.
1. Create the brand's campaign — once, held10 crPublic campaign, private posts. Drafts arrive held until you publish them.
Public campaign, private posts. Drafts arrive held until you publish them.
curl -X POST https://api.productclank.com/api/v1/agents/campaigns \
-H "Authorization: Bearer $PC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"product_id": "PRODUCT_ID",
"title": "Acme — issue-tracker conversations",
"keywords": ["issue tracker", "project management for small teams"],
"search_context": "Founders and small teams comparing lightweight project tools",
"platform": "twitter",
"reply_guidelines": "Helpful, first-person, no hard sell. Mark every reply as a paid partnership.",
"visibility": "public",
"post_visibility": "private"
}'
# → { "campaign": { "id": "CAMPAIGN_ID", … } }visibility: "public" opens the campaign; post_visibility: "private" keeps every discovered post held until you publish it. Omit the second and drafts go to the community the moment they're written — before the brand has seen them.product_id comes from POST /agents/products {"url"} (free, idempotent). Put the disclosure requirement in reply_guidelines — it's a rule, not a suggestion. Store campaign.id against the brand.
2. Run discovery — daily, from your cron60 cr / runFinds 5 conversations and drafts a reply for each. Two runs a day for a '10 a day' plan.
Finds 5 conversations and drafts a reply for each. Two runs a day for a '10 a day' plan.
curl -X POST https://api.productclank.com/api/v1/agents/campaigns/CAMPAIGN_ID/generate-posts \
-H "Authorization: Bearer $PC_API_KEY"
# → drafts land in GET …/posts with is_public: false (held)A run is 5 posts at 12 credits each — sometimes fewer if the topic is quiet, and you pay only for what was found. Drafts are ready in minutes. Nothing is claimable yet.
3. The brand reviews — your UI, two callsfreeShow the drafts, let the brand rewrite any, and take note of which they approved.
Show the drafts, let the brand rewrite any, and take note of which they approved.
curl "https://api.productclank.com/api/v1/agents/campaigns/CAMPAIGN_ID/posts" \
-H "Authorization: Bearer $PC_API_KEY"
# → posts[]: { id, tweet_text, tweet_url, author_username, is_public: false,
# CommuniplyReply: [{ id, reply_text, is_claimed: false }] }curl -X PATCH https://api.productclank.com/api/v1/agents/campaigns/CAMPAIGN_ID/replies/REPLY_ID \
-H "Authorization: Bearer $PC_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "reply_text": "We run a 3-person team on Acme — the keyboard-first flow is what stuck. Paid partnership." }'The edit lands on the exact reply a creator will claim, so it is what gets posted. It refuses a reply that's already been claimed — which can only happen after step 4, so edit first, publish second.
4. Publish what they approvedfreeReleases only the posts you name. The rest stay held.
Releases only the posts you name. The rest stay held.
curl -X POST https://api.productclank.com/api/v1/agents/campaigns/CAMPAIGN_ID/publish \
-H "Authorization: Bearer $PC_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "post_ids": ["POST_ID_1", "POST_ID_2", "POST_ID_3"] }'
# → { "published": 3, "held_remaining": 2, "campaign": { "is_public": true, "is_active": true } }From here creators can claim those three drafts. Each reply a creator actually posts bills you 20 credits, settled daily. Unpublished drafts cost nothing further. Don't use PATCH {visibility} for this — that flip releases every post in the campaign at once.
5. Show results — free, auto-deliveredfreeLive links as creators post. Poll it when the brand opens their page.
Live links as creators post. Poll it when the brand opens their page.
curl "https://api.productclank.com/api/v1/agents/campaigns/CAMPAIGN_ID/activity" \
-H "Authorization: Bearer $PC_API_KEY"
# → { "claimed_replies": [ { "posted_url": "https://x.com/creator/status/…", "reply_text": "…",
# "claimed_at": "…", "review_status": null, "survival_status": "alive",
# "engagement": { "likes": 4, "replies": 1 } } ] }Each posted_url is a result the moment it appears. posted_url: null means claimed, not yet posted. Free and read-only, so call it when a brand opens their page rather than on a schedule. To pause a brand, PATCH { is_active: false }; to cancel, leave it paused.
Boost: amplify a post the brand already published
A brand pastes a post, picks replies or quote posts, pays you once, and creators respond in their own words. Auto-delivered, 200 credits, its own campaign per boost.
The whole flow200 crConfirm → pay → launch → results. Two of the four steps are yours.
Confirm → pay → launch → results. Two of the four steps are yours.
curl -X POST https://api.productclank.com/api/v1/agents/campaigns/boost \
-H "Authorization: Bearer $PC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"post_url": "https://x.com/client/status/1234567890",
"action_type": "quote",
"reply_guidelines": "Genuine reactions only. Mark every post as a paid partnership."
}'
# → { "campaign": { "id": "CAMPAIGN_ID", "action_type": "quote", … }, "items_expected": 10 }- Confirm first, no call: show the post, the action (
repliesorquote) and your price, get a yes. Boost has no preview endpoint yet. - Then take payment with your own processor. Only then launch.
- Write
campaign.idto the order immediately — it's returned exactly once.402holds the order; never fail it. - Results are the same
/activitycall as discovery. Slots drip out over ~24h and the campaign closes itself once they're gone — plan on 24–48 hours from launch. - Not
/postsfor results — it returns drafts without the published URL.
Getting money right
Each exists because the alternative is a client who paid and got nothing, or paid once and you spent twice.
In your app
The steps above, placed in your system: which call runs on which event, what you persist, what state a brand is in, and what each error means. This is the section to hand to whoever wires it up.
Events → calls (discovery subscription)
| Event in your app | Runs on | ProductClank call | You persist |
|---|---|---|---|
| Brand subscribes (payment confirmed) | webhook | POST /agents/products, then POST /agents/campaigns (held) | brand: campaign_id, plan, status active |
| Daily, per active brand | your cron | POST …/{id}/generate-posts (×2 for '10 a day') | run: campaign_id, ran_at, credits |
| Brand opens 'review drafts' | your server, on request | GET …/{id}/posts (is_public:false = awaiting) | nothing — render it |
| Brand edits a draft | your server | PATCH …/{id}/replies/{replyId} | nothing — the API holds the text |
| Brand approves a set | your server | POST …/{id}/publish { post_ids } | approval log (optional) |
| Brand opens results | your server, on request | GET …/{id}/activity | nothing — render it |
| Brand pauses / cancels | webhook or admin | PATCH …/{id} { is_active: false } | status paused |
| Run returned 402 | your cron | retry the same call after top-up | run: held |
| Daily / on demand | cron or dashboard | GET /agents/credits/balance | nothing — alert if low |
Every call is server-side. The key never reaches a browser, and neither should the raw responses — map them to your own shapes. For a boost, the events are the four steps in the Boost section: confirm → pay (webhook) → launch → results.
The brand record
id, client_email, product_url, pc_product_id,
pc_campaign_id, -- from create; write it in the SAME transaction as the subscription
plan, -- e.g. "10/day" → runs_per_day = 2
status, -- active | paused | held (credits) | cancelled
payment_ref, -- your provider's subscription/event id — UNIQUE, this is your idempotency
created_at, last_run_atWhat a draft is in, and what the brand sees
| State | How you know | Brand-facing |
|---|---|---|
| held | /posts: is_public false | “Awaiting your approval” — with edit |
| published | /posts: is_public true; /activity: no claim yet | “Waiting for a creator” |
| claimed | /activity: claimed_at set, posted_url null | “A creator is on it” |
| posted | /activity: posted_url set | The link, with engagement |
| flagged / removed | /activity: review_status rejected · survival_status removed | Hidden, or shown as such — your call; both are rare |
Errors you will actually seehandle theseSix codes. Three are yours to fix, three mean wait or ask.
Six codes. Three are yours to fix, three mean wait or ask.
| Code | Means | Do |
|---|---|---|
| 402 insufficient_credits | Balance too low for this call | Hold it. Top up. Retry the same call. |
| 429 rate_limit_exceeded | Your daily campaign-creation cap | Onboard the brand tomorrow — or send us your id for the raise. |
| 400 confirmation_required | Publishing a campaign that's still private | You created it private by mistake. Publish with confirm:true — or recreate it held. |
| 409 already_claimed | Editing a reply a creator already took | Too late for that one. Edit before publish next time. |
| 503 post_fetch_failed | Boost only — we couldn't read the post | Retry in a minute, or pass post_text and post_author. |
| 400 validation_error | Bad or unsupported URL / field | Show the client; don't retry. |
Anything else from a create or launch call: mark it failed, alert yourself, and don't retry blindly — a 500 after a successful create would double-spend. Check GET /agents/campaigns for a campaign you don't have an id for before creating again.
Your first test~$1There is no sandbox. Here is the cheapest real run.
There is no sandbox. Here is the cheapest real run.
Create a held campaign for a product you own, run discovery once (60 credits — about a dollar at plan rates), read the drafts, edit one, publish one, and watch /activity. You've now exercised every call a subscription uses. Do it before you wire payments, so the first thing you debug is the API and not your webhook.
Your numbers
Credits are your cost of goods. A monthly plan is roughly half the per-credit price of a bundle, and a subscription product should sit on one.
What a brand costs you per month
| Plan you sell | Runs / day | Discovery (certain) | Posted replies (≤) | Ceiling / month |
|---|---|---|---|---|
| 5 replies a day | 1 | 1,800 cr | 3,000 cr | 4,800 cr |
| 10 replies a day | 2 | 3,600 cr | 6,000 cr | 9,600 cr |
Plus 10 credits once per brand. The discovery column is charged when runs happen; the posted column accrues only as creators post — so a month lands between the two.
What credits cost you
| Buy | Credits | Price | Per credit | A 10/day brand at ceiling |
|---|---|---|---|---|
| Pro plan, monthly | 30,000 | $499 | $0.0166 | $160 |
| Growth plan, monthly | 12,000 | $199 | $0.0166 | $160 |
| enterprise bundle | 14,000 | $500 | $0.0357 | $343 |
| large bundle | 2,600 | $100 | $0.0385 | $369 |
Reseller pricing on plans is available for the pilot — ask. Price your subscription against what the brand's alternative costs (an agency, a freelancer, ads), not against your credit cost — and never against a reply count you can't guarantee. A boost is 200 credits flat: $3–8 depending on how you buy.
Rules
The network is shared. One reseller's shortcut costs every creator on it.
- Disclosure is mandatory. Require “paid partnership” in
reply_guidelineson every campaign and boost. We audit. - Never sell
likesorrepost. The API accepts them; a reseller may not offer them. Bought engagement gets the creators' accounts penalised — the people doing the work, not your client. - Approved wording only. Held mode exists so a brand signs off before a real person puts their name to a reply. Don't publish drafts nobody has read.
- No misrepresenting the network. Creators aren't your employees; don't invent follower counts; don't promise reply counts.
- One key, one deployment. Violations end the account and forfeit remaining credits.
Coming next: content campaigns
Creators make original posts, threads or videos about a brand's product against a brief. Live in the API today, with one thing missing for a reseller — read the fold before you sell it.
Content campaigns via the API1000 crFree dry-run preview, launch, results — and why it's not in the first pass.
Free dry-run preview, launch, results — and why it's not in the first pass.
pending and count as delivered only once approved — today in ProductClank's web app, by you, per brand. Fine for a handful; not a storefront. A review endpoint comes after the discovery and boost passes are stable.curl -X POST https://api.productclank.com/api/v1/agents/campaigns/content \
-H "Authorization: Bearer $PC_API_KEY" -H "Content-Type: application/json" \
-d '{ "product_id": "PRODUCT_ID", "campaign_message": "Show how you use it daily", "dry_run": true }'
# → { "proposal": { "title", "description", "action_message", … }, "credits_required": 1000 }
# Never forward this response to a browser: credits_available / can_afford are YOUR balance.curl -X POST https://api.productclank.com/api/v1/agents/campaigns/content … -d '{ …, "dry_run": false }' # 1000 cr, runs 3 days
curl "https://api.productclank.com/api/v1/agents/campaigns/content/CAMPAIGN_ID?status=approved" # free
# Use campaign.state (processing|active|ended…), never raw_status. Only "approved" is delivered work.Piloting with us
A small number of partners before we open it up. You build against this page; we raise your daily cap, price your credits for reselling, and answer within the day; you tell us every place the page or the API let you down.
Send your agent id (GET /agents/me) and we raise rate_limit_daily.
Reference implementation. A complete, deployable storefront built on this flow — one config file, the order machine, dashboard, optional Stripe. Ask and we'll share the repo.
What to send back. Anything you had to guess, any shape you special-cased, any job that needed two endpoints, any number here that was wrong — and, above all, how many of your published drafts actually got posted. That number is the pilot. On the thread we opened, or hello@productclank.com.