GLOSSARY

What is an API Scope?

An API scope is a named permission attached to a credential that limits which endpoints it may call, so a leaked or misused key can only do the subset of things it was minted for.

Free forever plan · No credit card required · Cancel anytime

Quick definition

An API scope is a named permission attached to a credential that limits which endpoints it may call, so a leaked or misused key can only do the subset of things it was minted for.

In a single sentence: a scope is the answer to "if this key leaks tonight, what exactly can the finder do with it?"

What it means

An API scope is a permission label carried by a credential. The credential says who you are; the scope says what that identity is allowed to reach. A key with directory:read and nothing else can call the catalogue endpoints and is refused everywhere else, no matter how valid it is.

Scopes exist because authentication and authorisation are different problems and collapsing them produces master keys. A single credential that can do everything the account can do is fine right up until it appears in a log file, a repository, a screenshot, or a subcontractor's laptop. At that point the only question that matters is how much the finder can do, and the answer is decided entirely by the scopes you attached months earlier.

Where the idea comes from

The vocabulary is OAuth 2.0. RFC 6749 section 3.3 defines the scope request parameter as a space-delimited, case-sensitive list of strings, and then declines to define the strings themselves: their meaning is up to the authorization server. There is no scope registry and there never has been.

That is why every product's scope names look different and all of them are legal. GitHub uses repo and user:email. Google uses full URLs. The common convention, and the one most readable at a glance, is resource:action, which sorts sensibly and makes an audit of a key's permissions a five-second job.

RFC 6750 supplies the other half: when a valid token lacks the required permission, the error code is insufficient_scope and the status is 403 Forbidden, not 401. The distinction is behavioural rather than aesthetic. 401 tells a client "I do not know who you are", and every reasonable client responds by re-authenticating. If you answer 401 to a scope failure, the client re-authenticates successfully, retries, gets 401 again, and loops. 403 tells it the truth: the credential is fine, the permission is not.

Six scopes, and what "sensitive" means

The Pinlyx Data API publishes six scopes, three of which are flagged sensitive. It is worth being precise about what that flag means, because it is not "this data is secret".

  • scrape:live is sensitive because it costs. A live read goes to the platform right now and spends real upstream capacity shared with the rest of the product, which is why it has its own much smaller per-minute ceiling on every tier.
  • leads:read is sensitive because of what it touches: company and contact data, and follower-graph exports. That is the scope you do not attach to a key that lives in a widget backend.
  • tools:use is sensitive because it runs work rather than reading a row: valuation, follower audits, scoring.

The three unflagged scopes, directory:read, insights:read and research:read, read catalogued data at index-probe cost. Grouping by cost and reach rather than by secrecy is what makes the scope list actually useful for deciding what a given key should carry.

Least privilege, worked through

Least privilege is easy to agree with and easy to skip. The practical version is one key per job, with the scopes that job needs and nothing more:

  • A public "is this handle real" widget backend needs directory:read. Nothing else. If that key leaks, the finder can look up public catalogue rows, which is what the widget already shows the world.
  • A fraud review flow needs directory:read plus scrape:live, because "does this account exist right now" is the whole point. It should not carry leads:read.
  • A prospecting job needs leads:read and nothing else. If it leaks, nobody can burn your live-scrape budget with it.
  • An internal analytics notebook needs insights:read and research:read, and should be a separate key from anything customer-facing so that revoking it at 2am breaks nothing a customer can see.

The compounding benefit is revocation. With one key per job you can kill a compromised credential immediately, because you know exactly what stops working. With one key for everything, revoking it is an outage, so it does not get revoked, so the compromise stays live.

Scopes are one gate of several

A scope answers one question, and a request that passes it can still be refused for reasons that have nothing to do with permissions. On the Data API there are five independent gates, each with its own status code and its own remedy, and telling them apart is what turns a support ticket into a two-minute fix. The table below lists all five.

The design principle behind it is that a refusal should be actionable. Compare a bare "403 Forbidden" with the actual response body: "This key does not carry the leads:read scope required by this endpoint." The second one names the missing permission, so the integrator fixes it in the panel without opening a ticket. Naming the scope in the message costs the API author one string and saves everyone else an afternoon.

Compute the scope set before you mint the key

Because the catalogue publishes a required scope on every endpoint, the minimum viable scope set for an integration is a calculation, not a discovery process: list the endpoints you call, take the distinct scopes, and mint a key with exactly those. Doing it in that order means you never go through the phase where somebody ticks every box "just to get it working" and then never comes back.

Related concepts

  • Bearer token: the credential the scope is attached to.
  • Rate limit: a different gate, with a different status code and a different fix.
  • Cursor pagination: how the list endpoints a scope unlocks are actually walked.
  • Webhook: the push side, where authorisation runs in the other direction.

How Pinlyx handles it

Every Data API key carries the scopes its plan allows, and every one of the 127 endpoints declares the scope it requires, so the mapping is published rather than discovered. Sensitive scopes are flagged as such in the catalogue. A refusal names the missing scope in the message and carries the stable code forbidden_scope so client code can branch on it, and keys can be further constrained to an IP allowlist for the cases where scope alone is not enough.

Cheat sheet · the six published scopes

Sensitive means costly or far-reaching, not secret.

Every endpoint in the catalogue declares exactly one of these, so the minimum set for an integration is a calculation rather than a guess.

ScopeWhat it unlocksSensitive
directory:read
Directory
Read the account and channel catalog across all seven platforms.No
scrape:live
Live scrape
Read from the platform itself rather than the catalog: a profile or channel on any platform, and on X the whole content layer.Yes
insights:read
Insights
Engagement rates, top posts, viral patterns, cohort benchmarks.No
research:read
Research
Findings, runs and events from the autonomous research engine.No
leads:read
Leads
LinkedIn company and contact data, and X follower-graph exports.Yes
tools:use
Tools
Run the analysis tools: valuation, follower audit, scoring, and more.Yes
Cheat sheet · a refusal that fixes itself

Same key, two endpoints, two outcomes.

The key below carries directory:read only. The catalogue check succeeds; the leads endpoint refuses and says exactly which scope is missing.

GET /data-api/v2/accounts/instagram/nasa
Authorization: Bearer psk_live_...        # scopes: directory:read

HTTP/1.1 200 OK
X-Request-Id: req_9f2c41a8b3d5

{ "data": { "platform": "instagram", "handle": "nasa", "exists": true, ... },
  "meta": { "request_id": "req_9f2c41a8b3d5", "took_ms": 42 } }


GET /data-api/v2/leads/linkedin/companies?q=logistics
Authorization: Bearer psk_live_...        # same key, same scopes

HTTP/1.1 403 Forbidden
X-Request-Id: req_c71b09de4a22

{
  "error": {
    "code": "forbidden_scope",
    "message": "This key does not carry the leads:read scope required by this endpoint.",
    "request_id": "req_c71b09de4a22"
  }
}

Branch on error.code, which is stable and enumerated. The message is prose written for a human and may be reworded; it exists so the person reading the log knows what to click.

Five gates, five remedies

A scope failure is not a rate limit is not a billing problem.

GateStatusError codeRemedy
Is the credential real?401unauthorized, invalid_keyMint or repair the key. Retrying with the same value cannot help.
Does it carry the scope?403forbidden_scopeAdd the scope to the key, or call an endpoint the key is allowed to call.
Is the caller at an allowed address?403forbidden_ipAdd the address to the allowlist. Nothing about the key itself is wrong.
Can the plan pay for it?402payment_required, subscription_inactiveTop up, raise the overage cap, or renew. Waiting changes nothing.
Is the caller within the rate ceiling?429rate_limited, quota_exceededWait out the minute, or wait for 00:00 UTC. The code says which.
Watch out for

Six ways a scope model stops protecting anything.

  • One key with every scope "for now", which never gets narrowed because narrowing it risks an outage nobody has time to test.
  • The same key in CI, staging and production, so revoking a leaked credential takes all three down at once.
  • Answering 401 for a scope failure, which sends well-behaved clients into a re-authentication loop.
  • Returning partial data instead of 403, so downstream code cannot tell "not permitted" from "not measured".
  • A refusal that does not name the missing scope, turning a self-service fix into a support ticket.
  • Treating scopes as a UI concern. If the check is not enforced server side on every request, it is decoration.

API scopes: FAQ

Naming, status codes, granularity, and how to compute the set you actually need.

No. RFC 6749 section 3.3 defines the scope parameter as a space-delimited, case-sensitive list of strings and then explicitly leaves the strings themselves to the authorization server. There is no registry, which is why you meet read, user:email, https://www.googleapis.com/auth/drive.readonly and directory:read in different products and all of them are correct. The resource:action convention is the most common because it reads naturally and sorts usefully.
Because the two invite different reactions. 401 means the server does not know who you are, and the sensible client response is to re-authenticate. 403 means the server knows exactly who you are and the answer is still no, so re-authenticating is pointless. RFC 6750 section 3.1 makes this explicit: insufficient_scope is a 403. A server that answers 401 for a scope failure sends well-behaved clients into a loop where they refresh a perfectly valid credential and get refused again.
No. Silently stripping fields a scope does not cover produces a response that looks like data and is not, and downstream code cannot tell the difference between "this field is not permitted" and "this field is null because it was not measured". Refuse the call with 403 and name the missing scope. The one exception is a documented, explicitly flagged reduced view, where the response itself says what was withheld.
A scope should map to a job somebody actually does. Too coarse and every key is a master key, which defeats the purpose. Too fine and nobody can work out which of forty scopes an endpoint needs, so integrators tick every box and you are back to master keys with extra steps. Six to a dozen scopes covering recognisable jobs is a workable range for a data API; the Data API publishes six.
Yes, and you should. The Data API catalogue publishes the required scope on every one of its 127 endpoints, so the minimal set for an integration is the distinct scopes of the endpoints it calls: a mechanical calculation rather than a trial-and-error exercise against production. Do that before you mint the key, not after the first 403.
A key carries the scopes your plan allows, so scopes and plan are coupled and a downgrade can remove a capability a key previously had. The visible symptom is a 403 forbidden_scope on a call that worked last month, which is easy to misdiagnose as a code change. When an endpoint starts refusing after a billing event, check the plan before you check your deployment.
Ready to ship

Mint the key. Grant only the job.

Six published scopes, a declared scope on every endpoint, refusals that name what is missing, and an optional IP allowlist on top.

Free forever plan · GDPR-ready · No credit card required

We value your privacy

We use cookies to improve our site, analyze traffic, and personalize ads. You can accept all, reject non-essential, or customize your choices. Read our Cookie Policy.