Developer documentation

Every marketplace, measured, behind one key.

613,446 placements from 10 suppliers, deduplicated by domain and checked against a third-party search index. An agent searches, plans at a price we hold, buys inside caps you set, and keeps watching after delivery. One prepaid balance, one invoice.

REST / v1
Base URLhttps://api.placementapi.com
215,280
domains measured independently
31
endpoints, all listed below
4 hours
a quoted price is held
1¢
= 1 credit, exactly

Two requests to a live link.

  1. Quote a plan

    A brief in, a costed basket out. Cheapest verified seller for each domain, spread across domains, with a reason on every line, held at that price for 4 hours.

  2. Order the lines

    Redeem the quote and pay what you were quoted. Spend caps and the idempotency key are checked in the same statement as the charge. Cancel free until the morning batch.

export PLACEMENT_KEY="pk_live_…"

# 1. ten finance links, DR50+, cheapest verified seller for each,
#    one per domain. Price held 4 hours.
curl -X POST https://api.placementapi.com/v1/quote \
  -H "Authorization: Bearer $PLACEMENT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"links":10,"topic": "finance","dr_min":50,
       "strategy": "cheapest","budget_credits":500000}'

# 2. buy a line at the price you were quoted
curl -X POST https://api.placementapi.com/v1/orders \
  -H "Authorization: Bearer $PLACEMENT_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"quote_id": "qt_9f2c…",
       "offer_id": "s1a2b3c4:example-publisher.com:guest_post",
       "target_url": "https://acme.com/pricing"}'

Permission to read. Permission to spend.

Authenticate with a bearer token. Use a read-scoped key for searching and planning; ordering requires the order scope. A read key searches and plans; only an order key can spend, and auto placement is switched on from the dashboard, never from a key.

Keep API keys server-side. Configure spending limits for integrations that place orders.

what a row carries

Our measurements sit next to the seller’s claims.

Verification, five tests

Traffic against rating, the queries it ranks for, who links to it, whether it is a subdomain trading on its parent, and the shape of its outbound links. A domain that fails is marked suspect and left out of plans unless asked for. How the tests work.

Placement score and market reference

A 0 to 100 composite with its components exposed, and for every listing the median price the same placement sells for elsewhere, so a cheap line and an expensive line are both explained.

Content profile and price confidence

A sample of the publisher's recent pages: posting velocity, links per page, sponsored share. And every price says when it was observed and whether it is fresh or aged, so nothing is priced without saying how old that price is.

Reference

The whole surface, by what an agent is trying to do.

Search and verify

Every supplier's inventory in one schema, deduplicated by domain, with our own measurements beside the seller's claims.

GET
/v1/offers

Search placements by DR, price, topic, geo, language, turnaround, traffic and verification. Fakes excluded unless asked for.

GET
/v1/sites/{domain}

One publisher, assembled: every way to buy it cheapest first, verification, placement score, link history, cross-buyer outcomes.

GET
/v1/market

The price distribution for a slice of the catalogue: what a DR 50 finance guest post costs across sellers.

GET
/v1/market/taste

What buyers, ranking winners and the web graph say a niche's links look like.

GET
/v1/keywords/winners

Who ranks for a keyword, who links to them, and which of those referrers we sell.

Plan

A brief goes in; a costed, held basket comes out, with a reason for every line.

POST
/v1/quote

A brief in, a costed basket out: cheapest seller per domain, spread across domains, held for 4 hours.

GET
/v1/quotes/{quote_id}

Read a held quote back by token, so a plan can be approved by someone other than the agent that made it.

GET
/v1/targets/profile

The backlink profile of the page you are buying for, and how much of it we sell.

POST
/v1/targets/gap

Domains your competitors have that you do not, priced and held.

POST
/v1/targets/scenario

What closing a keyword's gap could be worth, with measured, published and assumed figures kept apart.

GET
/v1/campaigns

What this account already bought for a page: domains, spend, anchor mix. Nothing gets bought twice.

Buy

Pay-first, like every link marketplace, with the guardrails enforced in the same statement as the charge.

POST
/v1/orders

Place an order at the held price. Spend caps and idempotency are checked atomically with the debit.

GET
/v1/orders

Every order with its delivery state: in progress, awaiting content, overdue, or past due and past the grace period.

POST
/v1/orders/{id}/cancel

Full refund until the order reaches a supplier in the morning batch.

POST
/v1/orders/{id}/content

Send the article. It is checked against the publisher's spec before anyone sees it.

POST
/v1/orders/{id}/content/papi

Have the article drafted for you and stored on the order for approval.

POST
/v1/checkout/basket

Buy a whole basket by card, with or without an account. Paying creates the account.

GET
/v1/checkout/basket/{id}

How that checkout went, line by line.

Measure what happened

A link is bought to move something. We keep watching after delivery, and say observed, never caused.

GET
/v1/orders/{id}/outcome

Everything observed since one placement: the link still standing, rank movement on the page's keywords, confidence.

POST
/v1/observations/purchases

Report placements bought anywhere else, so outcomes cover your whole footprint, not only ours.

POST
/v1/connections/google/start

Connect Google Search Console, read-only. Your rows stay yours: never pooled, never published, deleted on disconnect.

GET
/v1/gsc/opportunities

Your own pages at positions 5 to 20 with the queries behind them and their momentum: where a link has something to move.

Automate

For accounts that want links to keep arriving without a human in the loop, behind a dashboard-only switch.

POST
/v1/standing_orders

So many links a month for this page, within this budget. Quoted, approved or auto-placed, on a cadence.

PATCH
/v1/standing_orders/{id}

Pause, resume or edit a standing order; DELETE removes it.

PATCH
/v1/customers/me/brief

A weekly email per target: what landed, what is due, what moved, and a held quote for the next tranche.

POST
/v1/customers/me/auto

Enable auto placement. Dashboard session only: a key cannot switch on spending it did not ask for.

Account

One prepaid balance in US cents, keys with scopes, and a schema an agent configures itself from.

GET
/v1/credits

Balance, spend limits, cleared cash, allowance and the ledger behind them.

POST
/v1/credits/checkout

Start a card top-up. Auto-reload lives in /v1/credits/settings.

GET
/v1/keys

Issue, list and revoke keys. A read scope searches and plans; an order scope can spend.

GET
/v1/schema

Field semantics for agents: what every value means and how to reason about it.

GET
/v1/health

Catalogue coverage and freshness, machine-readable.

Full request and response schemas: GET /v1/schema for field semantics and /openapi.json for the contract. Reads are metered: 1,000 requests and 20,000 rows per hour, plus a monthly allowance that grows with credits purchased.

the handbrake

Guardrails an agent cannot argue past.

Caps in the same statement as the charge

Per-order and per-day limits are checked atomically with the debit. They are not in a prompt, so no amount of reasoning gets around them.

A retry never charges twice

Every order carries an idempotency key. A replayed request returns the original order instead of a second one.

billing

Credits, pegged to something real.

1 credit = 1 US cent. No invented unit, no conversion table, no rate card to decode at reconciliation time.

Credits leave the account when an order is placed, because link buying is pay-first everywhere. What we add is the accounting on the other side:

  • Past its promised turnaround: flagged, and logged against that supplier's on-time rate
  • Undelivered past the grace period: flagged in your dashboard, and never refunded on the calendar alone
  • A supplier recovery you ask us to pursue: email hello@placementapi.com; credits return once we have recovered from that supplier and their refund window plus your account grace period have run
  • Delivered late: counted, so you can stop buying from whoever keeps doing it

A refund for an order that has already reached a supplier is not automatic: your credits return once we have recovered from that supplier and their refund window plus your account grace period have run, unless we refund earlier as a goodwill decision. The date alone returns nothing, and we cannot promise that a supplier will reimburse us. Unspent credits are refundable for 90 days, and never expire. Terms.

{
  "balance_credits": 76600,
  "balance_usd": "766.00",
  "funding": {
    "cash_on_hand_credits": 51200,
    "pending_credits": 25400
  },
  "limits": {
    "per_order_max_credits": 50000,
    "daily_max_credits": 100000,
    "remaining_today_credits": 76600
  },
  "refund_grace_days": 21
}

pooled buying

Volume credits.

Suppliers discount on volume

No single agency places enough with any one supplier to reach the tiers that matter. Pooled across every buyer here, we do.

Most of it comes back

Returned as ordinary credits, weighted by what you bought. Not a loyalty scheme: it is your share of a rate you helped earn.

After delivery, not before

A discount on an order that never ran is not a discount, so credits follow delivery and are issued against what a supplier actually invoiced.

Or skip the REST surface entirely.

The same product is a hosted MCP server. Paste one URL into Claude, ChatGPT or Cursor and your agent can search, plan, compare, buy and track: 20 tools, nothing to install. The 5 that spend money only appear on a key with the order scope, so a key left in a chat window can look but cannot buy.