Connect a tool to your store
Your ERP, your warehouse software, a dashboard, a back office of your own, a nightly script: anything that has to read or change the store without a person…
Your ERP, your warehouse software, a dashboard, a back office of your own, a nightly script: anything that has to read or change the store without a person sitting in front of it goes in through a service token.
A panel session is not the right tool for this. It belongs to a person, it expires, and it dies the day that person leaves or changes their password. A service token belongs to the store, not to anyone, and it only does what you wrote on it.
Create one
Panel → Connections → Create token. Only an administrator sees this screen.
You choose three things:
- A name. What it is for and where you are going to keep it. It is the only thing you will see next to it later, on the day you have to decide whether to revoke it.
- What it can do. One line per area, and for each one: none, read or write. Everything starts at none. Write includes read, so you never need to give both.
- When it expires. 30 days, 90 days, a year, or never. Pick a date if you can: a token that never expires has to be revoked by hand the day it stops being needed, and that day nobody remembers.
Copy it right then
The token is shown once, on the screen where you created it. After that it is gone: the store keeps only a SHA-256 fingerprint of it, so neither the panel nor the API can show it to you again — not because we would rather not, but because we do not have it.
If you lose it, revoke it and create another one. That is the whole recovery procedure, and it is on purpose.
It looks like this:
pcc_svc_<55 characters>The pcc_svc_ prefix is there so that secret scanners (GitHub's, your CI's,
your own) can recognise it if somebody pastes it where they should not. The last
characters are a checksum, so a scanner can tell a real token from a random
string without asking anyone.
Use it
Exactly like a session token: an Authorization header with Bearer.
curl https://mystore.com/gestion/pedidos \
-H "Authorization: Bearer pcc_svc_..."const r = await fetch("https://mystore.com/gestion/productos", {
headers: { Authorization: `Bearer ${process.env.PCC_TOKEN}` },
})To check the token is still alive and what it is allowed to do:
curl https://mystore.com/gestion/quien-soy -H "Authorization: Bearer pcc_svc_..."{
"actor_type": "servicio",
"servicio": {
"id": "svct_...",
"nombre": "warehouse sync",
"permisos": { "catalogo": "escribir" }
}
}The id is the token's public identifier. It is not a secret: it is what
identifies the row in the panel and in the audit log.
When it says no
If the token is missing a permission, the store answers 403 and tells you which one:
{ "message": "This service token needs “Orders and invoices” with write access to do that." }That is the message to read before you start guessing. Add the area, or the level, and try again.
If the answer is 401, the token is not valid at all: revoked, expired, mistyped, or never existed. The store answers the same thing to all four on purpose — there is no person on the other end to explain it to, and telling apart "expired" from "does not exist" only helps whoever is trying tokens to see which one gets in.
What a token will never reach
Some parts of the panel are closed to service tokens and stay closed, whatever you tick:
- the team (
/gestion/usuarios,/gestion/create-staff) - payment gateway and AI provider keys
- extensions, which run code
- moving a shop in from somewhere else
- erasing someone's personal data
- the AI agent endpoint (
/mcp) - this very screen: a token cannot mint more tokens
They all have one thing in common: they hand out capability. A long-lived credential that can create an administrator turns a thirty-second leak into permanent access, and revoking the token afterwards does not take it back — the account it created is still there. So that door does not open, not even with a tick box.
There is one exception, and you have to confirm it explicitly when you create the token: paying authors. It moves money out of the store, so it is marked as such and asks you to say yes on purpose; but it is a bounded, audited operation rather than a permission that multiplies permissions, and settling up with authors from a back office is one of the things this feature exists for.
How much it may call
A token has a budget of points per minute, and it is its own: one tool running hot never eats another's.
Not every request costs the same. A read costs 1 and a write costs 5, one counter for both, the way GitHub prices its REST API. Reading a catalogue twenty times a second is normal traffic; writing twenty orders a second is not, and the damage a leaked token does is almost all on the writing side.
Out of the box that is 1200 points a minute: 1200 reads (20 a second) or 240
writes (4 a second). Paying authors has its own, much shorter budget —
moving money is never a burst, and a leak should not turn into a run of payouts
before anyone looks. Both are set with environment variables
(PCC_LIMITE_SERVICIO_PUNTOS, PCC_LIMITE_SERVICIO_PUNTOS_SENSIBLE; see
Environment variables).
Every answer tells you where you stand, not just the ones that say no:
RateLimit-Limit: 1200
RateLimit-Remaining: 1143
RateLimit-Reset: 41
RateLimit-Policy: "servicio";q=1200;w=60
RateLimit: "servicio";r=1143;t=41The first three are the ones client libraries understand today; the last two are the same thing in the format the IETF draft has moved to. Read whichever you like and slow down before you hit the wall.
When the budget runs out the answer is 429 with Retry-After in
seconds. Wait that long. Retrying straight away, or in a tight loop, makes the
thing you are complaining about worse. If you need to spread the load, spend
your points on reads and batch your writes.
There is a switch to turn it off entirely (
PCC_LIMITE_SERVICIO_ACTIVO=0). It exists for the one day it is needed — importing a whole shop, which writes for hours — and not as somewhere to hide a badly written loop.
Seeing what it does
The list shows, for each token, when it was last used and from which address, and how many requests it has made. That is all that is kept: the last use, not a log of every call. It is enough to answer the two questions that get asked — is this still alive? and who is calling? — without building a trail nobody asked for.
It also shows, in red, the day a token ran into its limit and how many times it has. Take that seriously. A token that suddenly calls ten times more than it ever has is either a tool with a runaway loop or a token somebody else has a copy of, and those are the only two explanations. It shows up on the panel's home screen as well, among the things to look at today. If you cannot explain it, revoke it: it costs you one integration for an afternoon and it is the only move that takes the access back.
Revoking
Revoke, on the token's row. It stops working on its next request; there is no cache and no grace period.
The row stays, marked as revoked. After a scare, the question is never "what was it called" but "what could it reach and when did it last call", and deleting the row is deleting the answer.
Revoke a token when the tool that used it is gone, when someone who had a copy leaves, or the moment you suspect it has been where it should not.
Rules of thumb
- One token per tool. Not one for everything. When you have to revoke one, you want to take down one integration, not all of them.
- Give it the least it needs. If it only reads reports, read on Reports and nothing else.
- Keep it out of the code. In an environment variable or your secret manager, never in the repository and never inside a theme — the theme packager refuses to build a package with one inside, and a package that has already been downloaded cannot be taken back.
- Put an expiry on it and renew it. Renewing is creating a new one, pointing the tool at it and revoking the old one; nothing breaks in between, because both work until you revoke.
See also
- Your team — for people, not machines
- Let ChatGPT and Claude sell your products — the public, read-only door for AI agents, which is a different thing