Getting a key
Keys are issued from your account page. API and MCP access is included on Concierge on any billing cycle, and on any paid plan billed yearly — see Products.
A key is shown once, when it is created. It isn't stored in a form we can read back, so if it's lost, revoke it and issue another. Keys can be read-only or read and write; a read-only key can't file, correct, or withdraw anything.
Authentication
Send the key as a bearer token. It has to be a header — a key in a query string ends up in server logs and browser history, which is three copies of a live credential nobody meant to make.
curl -s https://courierpr.com/api/v1/me \
-H "Authorization: Bearer cpr_your_key_here"REST endpoints
| Method | Path | What it does |
|---|---|---|
GET | /api/v1/me | Your account, plan, limits, and whether API access is on. Answers even when the rest is refusing you. |
GET | /api/v1/releases | Your own releases, newest first. Takes limit, offset, and status. |
POST | /api/v1/releases | File a press release. Send an Idempotency-Key. |
GET | /api/v1/releases/{id} | One of your releases with its running view total. |
PATCH | /api/v1/releases/{id} | Correct the headline or body. The URL does not change. |
DELETE | /api/v1/releases/{id} | Withdraw a release from the wire. |
GET | /api/v1/wire | Search everything published on CourierPR. Takes q, category, limit. |
GET | /api/v1/billing/history | When you joined, and every plan change and payment since. |
Filing a release
A release goes live immediately at a permanent URL. The same rules apply as on the web form: your plan's filing cap, the content filter, and a real category. There's no draft state — file it when it's ready.
curl -X POST https://courierpr.com/api/v1/releases \
-H "Authorization: Bearer cpr_your_key_here" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"title": "Acme opens a second plant in Leeds",
"body": "At least fifty words of press release...",
"company_name": "Acme Ltd",
"category": "industry-realestate-construction",
"contact_email": "[email protected]",
"submitter_name": "Your Name",
"submitter_email": "[email protected]",
"submitter_phone": "+44 20 7000 0000"
}'Always send an Idempotency-Key on a POST. Every release gets a unique URL, so a request that times out and is retried without one publishes a second copy rather than failing. With one, the retry returns the original result and carries an idempotent-replay: true header.
MCP setup
The MCP server is hosted — nothing to install. Point any MCP client at it with your key:
claude mcp add --transport http courierpr https://courierpr.com/mcp \
--header "Authorization: Bearer cpr_your_key_here"Or, for a client configured by file:
{
"mcpServers": {
"courierpr": {
"type": "http",
"url": "https://courierpr.com/mcp",
"headers": { "Authorization": "Bearer cpr_your_key_here" }
}
}
}Tools
| Tool | Needs | What it does |
|---|---|---|
whoami | read | Account, plan, caps, and remaining rate limit. |
billing_history | read | Joined date, plan changes, renewals, failed payments, cancellations. |
search_wire | read | Search the published wire. |
list_releases | read | Your own releases. |
get_release_stats | read | One release and its view total. |
submit_release | read and write | File a press release. |
correct_release | read and write | Correct one you filed. |
withdraw_release | read and write | Withdraw one from the wire. |
A read-only key is only offered the read tools — the write ones don't appear in its tool list at all.
ChatGPT app (public, no key)
A second, read-only MCP server at https://courierpr.com/api/mcp powers the CourierPR app in ChatGPT and needs no key. It exposes what a visitor can already read: list_desks, latest_releases, search_releases, get_release and how_to_file, plus connector-style search and fetch. Results are summaries with links to the release page; media contacts are never returned. To file, correct or withdraw releases from an agent, use the keyed server above.
The same server is available to Claude at https://courierpr.com/api/mcp/claude; see Courierpr.com for Claude.
Rate limits
60 requests a minute and 5,000 a day, per key. Every response carries x-ratelimit-remaining and x-ratelimit-reset. How much you may publish is a separate thing, set by your plan, not by these — /api/v1/me reports both.
Errors
Every failure returns the same envelope, with a request_id worth quoting if you get in touch.
{
"error": {
"code": "feature_not_available",
"message": "API and MCP access is included on Concierge ...",
"request_id": "0b6f...",
"docs": "https://courierpr.com/docs/api"
}
}| Code | Status | Meaning |
|---|---|---|
unauthorized | 401 | No Authorization header. |
invalid_key | 401 | Key unknown, revoked, expired, or wrong. |
insufficient_scope | 403 | A read-only key tried to write. |
feature_not_available | 403 | Your plan doesn't include API access. |
plan_inactive | 402 | The subscription ended. |
rate_limited | 429 | Too many requests, or your plan's filing cap is spent. |
invalid_request | 400 / 422 | Something in the request was wrong. The message says what. |
not_found | 404 | No such release on your account. |
request_in_flight | 409 | That Idempotency-Key is still being processed. |
What isn't here yet
View counts are a running total only — there's no per-day series. When that lands it will be an added field, not a change to what's above.
Something missing, or behaving oddly? Tell the desk — a person reads it.