Authentication
Authenticate with an rsk_ key. Authorization has two axes, a ranked scope and a separate approval grant.
The API authenticates with an rsk_ API key. A key reaches the one workspace it
was minted in, which is one Meta ad account.
The Bearer header
Send the key in the Authorization header on every request.
curl https://winandscale.com/api/v1/overview?period=7d \
-H "Authorization: Bearer $WINANDSCALE_KEY"A missing, invalid, revoked or expired key returns 401 with code unauthorized. An
OAuth access token, such as the one an MCP client holds, is recognised and answered with
a specific 401: it only works at /api/mcp.
Creating keys
A workspace admin creates keys under Settings → API keys. Pick a name, a scope and whether the key holds the approval grant. The key is shown once, and only a hash is stored. Copy it immediately and keep it secret. Revoke a key at any time.
A key stops working when it is revoked, when it expires, or when the operator who minted it leaves the workspace.
The same key authenticates the MCP server for a headless agent, with the same scope and grant. Both surfaces verify it with the same code, so revoking a key stops REST and MCP together.
Never expose an rsk_ key in client-side code or commit it to source control. The
API sends no CORS headers, and browser use is not supported. A key with the approval
grant can put ads live and spend money.
Authorization has two axes
The scope is ranked
A key satisfies any requirement at or below its own tier.
Prop
Type
There is no approve scope. It was a rung once; it is not one now, and a key requested
with it is rejected.
The approval grant is a separate boolean
Changing spend on Meta needs write and the approval grant. That covers:
- activating a launch,
- pausing or resuming ads,
- retargeting an ad set,
- rebuilding a launch's live creative.
The grant is not a tier above write. A key can hold admin and still be refused
here. Keeping the two apart is what makes the review gate a control rather than a
convention: a key that may propose is not automatically a key that may approve its own
proposal. The dashboard does not offer the grant on a read key.
| Scope | Approval grant | Use it for |
|---|---|---|
read | no | Dashboards and reporting. |
write | no | An agent that researches, briefs, tags and launches paused drafts, but cannot spend. |
write or admin | yes | An agent or job that may also activate, pause and retarget. |
Give each integration the lowest combination that works. A leaked key with the grant can turn spend on.
When authorization fails
A key that authenticates but is not allowed gets 403 forbidden, not 401. The
body names which axis fell short so you can branch without parsing the prose.
Scope too low carries required_scope:
{
"error": {
"code": "forbidden",
"message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
"required_scope": "write",
"key_scope": "read",
"request_id": "req_8fK2mQ"
}
}No approval grant carries required_grant instead:
{
"error": {
"code": "forbidden",
"message": "This endpoint requires the approval grant (activate, pause or resume ads, retarget an ad set, or rebuild a launch's live creative — what changes spend on Meta) — this key does not have it.",
"required_grant": "approve",
"key_scope": "write",
"request_id": "req_8fK2mQ"
}
}Branch on which field is present. required_scope means mint a higher scope.
required_grant means this key may author but not approve. The scope is checked first,
then the grant, then the rate limit. Every operation in the API reference
states what it requires.
What keys can never do
- Set Meta credentials. The Meta System User token enters only through the app. No endpoint accepts it.
- Mint or revoke keys. Keys are created and revoked by an admin in the dashboard.
- Switch workspace. A key is pinned to the workspace it was minted in.