Ingest tokens
The credential every log shipper uses: how to issue one, what it is scoped to, how long it lasts, rate limits, rotation, revocation, and what to do if one leaks.
An ingest token is the credential a log shipper presents when it sends events to Qorionix. It is a bearer token: whoever holds the string can use it, with no second factor, and — unless you restrict it to an address range when you issue it — from anywhere on the internet. Tokens issued today carry an expiry date; tokens issued before that change do not. That makes them simple to deploy and worth being careful with, and this article is mostly about the being careful.
Format
A token is a four-character prefix followed by 32 bytes of cryptographically random data encoded as URL-safe base64 — 256 bits of entropy, which is not brute-forceable by anybody. Newly minted tokens carry the prefix qxi_. Tokens minted before the rename carry zqi_ and keep working, permanently.
Token minted today: qxi_kQ7xR2mB9tYfL4nVdW8cJp1sHg3eZ0aUoI6bN5rTqXk
Token minted before the rename: zqi_7dLpW1qN… (still valid, no action needed)
Record id (not secret): sit-9f2c41ab77e0Nothing on the authentication path reads the prefix. A token is resolved by the SHA-256 hash of the entire presented string, there is no prefix column in the database and no lookup keyed on one, so an old zqi_… token hashes to exactly what it always did. There is no migration, no expiry attached to the old prefix and no cutover date. If you have zqi_ tokens in production, leave them alone — and note that because they predate the expiry rules below, they have no end date at all.
The prefix is otherwise there for your benefit as much as ours. It lets an operator grep a secret manager, a source repository or a log archive for Qorionix ingest tokens specifically, and it makes a monitoring rule that flags accidental token logging trivial to write.
Two neighbouring prefixes are worth keeping straight while you are editing scanner rules. Endpoint enrolment tokens still begin zqe_ and have deliberately not been renamed — a deployed sensor decides from that prefix alone whether it is holding a coupon to redeem or a finished credential, so minting a new prefix would make existing sensors silently never enrol. See Enrolment tokens. And inbound provisioning tokens begin zqscim_, also unchanged.
The record identifier beginning sit- is what you use in the API to revoke a token. It is not a secret and appears in listings.
Issuing a token
Three routes exist and all three require a permission. Issuing requires siem:sources.write; listing requires siem:sources.read; revoking requires siem:sources.write. See Roles and permissions for who has these by default.
| Method and path | Permission | Success |
|---|---|---|
POST /api/v1/organizations/{orgID}/siem/ingest-tokens | siem:sources.write | 201 Created, with the plaintext token. The only response anywhere that contains it. |
GET /api/v1/organizations/{orgID}/siem/ingest-tokens | siem:sources.read | 200 OK, an array of token records — without plaintext. |
DELETE /api/v1/organizations/{orgID}/siem/ingest-tokens/{id} | siem:sources.write | 204 No Content. |
POST /api/v1/organizations/{orgID}/siem/ingest-tokens
Content-Type: application/json
{"name": "branch-firewall-hq", "parser_kind": "cisco_asa"}
---
HTTP/1.1 201 Created
{
"id": "sit-9f2c41ab77e0",
"organization_id": "…",
"name": "branch-firewall-hq",
"parser_kind": "cisco_asa",
"created_by": "…",
"created_at": "2026-09-01T09:14:22Z",
"bytes_ingested": 0,
"events_ingested": 0,
"plaintext": "qxi_kQ7xR2mB9tYfL4nVdW8cJp1sHg3eZ0aUoI6bN5rTqXk"
}The created_by value is taken from the session of whoever called, not from the request body, so a token cannot be issued under someone else's name.
How long a token lasts
This changed, and the change was made deliberately backwards-compatible, so there are two populations of token in the world and it is worth knowing which yours is in.
- A token issued from now on has a lifetime. Ask for nothing and it is 400 days. Ask explicitly for longer and you may have up to 730 days — about two years — and no more.
- A token issued before this change has no expiry at all. Existing tokens were grandfathered rather than cut off, so nothing that was working stopped working on the day this shipped. A very old token may genuinely never expire.
The maximum exists because a credential nobody has looked at in three years is not a credential anybody is managing. Two years is long enough that expiry is not an operational nuisance and short enough that a departed employee's token does not outlive the notice period by a decade. When a token does expire, the collector using it simply stops being accepted — and because the ingest endpoints deliberately do not distinguish between reasons for refusing a credential, that will look like every other refusal rather than announcing itself as an expiry. Put the date in the same calendar as your certificate renewals.
Choosing the parser kind
parser_kind decides how everything sent with that token is interpreted. It defaults to json if you omit it.
auto json syslog otlp
windows_eventlog windows_evtx auditd
cloudtrail m365 okta
cloudflare cisco_asa fortinet palo_altoAnything else is refused with a 422. One accepted value is still worth a warning, because the list the API accepts is one longer than the list of parsers that exist. otlp is permitted vocabulary with no parser behind it. It does not fall back to the JSON parser, and it does not produce an error either.
Four values that used to be accepted and are not any more
cef and ecs are no longer accepted parser kinds. Asking for either when you issue a token now fails outright with a 422. Earlier versions of this article warned that those two stored your logs and stripped them; that is the problem this fixes, and it is fixed by removing them as choices rather than by giving them a real parser. If you were sending CEF or ECS-shaped events, send them as json or syslog according to what is actually on the wire, and read How your logs are normalised for what you get.
entra and workspace have been retired as separate choices too. Tokens that were already using them were automatically remapped to working equivalents, so no collector had to be touched and nothing stopped arriving. There is nothing for you to do about an existing one; there is simply no longer a reason to choose either name for a new token.
The practical consequence: issue one token per format, not one token per organisation. A single token used for a firewall and a Windows shipper will run the wrong parser on one of them, and the symptom is events that arrive with almost every field empty.
What a token is scoped to — and what it is not
This section exists because the reasonable assumption is wrong, and the assumption is a security-relevant one.
A token is scoped to your organisation and to a parser kind, and — if you asked for it when you issued it — to an address or address range. It is still not bound to a log source, not bound to a receiver record, and not bound to a protocol. The same token string works on the HTTP Event Collector and on the OTLP endpoint until it is revoked or expires — and that is true of a zqi_ token and a qxi_ token alike, because the prefix carries no authority of its own.
The consequences worth acting on:
- Do not reuse one token across machines you do not trust equally. A token on a branch appliance and a token on a domain controller should be two different tokens, because revoking one should not take the other offline.
- Do not treat the token name as a control. The name is a label for humans. It constrains nothing.
- An address allow-list exists, but only if you ask for one. A token issued without a restriction is accepted from anywhere. If your collector has a fixed address or sits in a known range, set the restriction when you issue the token — it is the cheapest control available on this credential, and it is the difference between a leaked token being usable by anybody and usable only from your own network.
- Issue a token per sender so revocation is surgical. The one thing you can control precisely is which token you revoke, and that is only useful if the tokens are separated in the first place.
The header
One header, two accepted prefixes, matched case-insensitively. Splunk exists so that Splunk-compatible shippers work unchanged.
Authorization: Splunk qxi_kQ7xR2mB9tYfL4nVdW8cJp1sHg3eZ0aUoI6bN5rTqXk
Authorization: Bearer qxi_kQ7xR2mB9tYfL4nVdW8cJp1sHg3eZ0aUoI6bN5rTqXkThere is no custom header. X-Qorionix-Ingest-Token and anything like it does not exist and never has. Leading and trailing whitespace on the token itself is tolerated, so a value with a stray newline from a shell variable still works.
The exact rejection responses
Both ingest endpoints answer identically. The bodies are plain text, not JSON.
HTTP/1.1 401 Unauthorized
missing bearer tokenHTTP/1.1 401 Unauthorized
invalid tokeninvalid token is returned for an unknown token, a revoked token and a token whose lookup failed, deliberately without distinguishing them, so the endpoint cannot be used to work out which tokens exist. Internally the condition is recorded as ingest token not found; you will not see that string in a response.
One more rejection is worth recognising on sight, because it means the token is fine and the format is wrong. If a batch arrives and not one event in it can be parsed by the token's parser, the whole batch is refused and nothing is stored:
HTTP/1.1 400 Bad Request
{"text":"Invalid data format","code":6,"accepted":0,
"invalid":500,"parser":"cisco_asa",
"error":"..."}Read parser in that response as what this token said your logs would be, and invalid as how many events did not look like it. Either the token's parser_kind is wrong for the sender, or the sender is pointed at the wrong token. Nothing was stored, so nothing is lost — fix one end and re-send. A batch where only some events fail is accepted, and the failures are stored as raw text.
The admin API, by contrast, uses a JSON envelope of the form {"error": "<message>"}:
400 Bad Request {"error":"invalid request body"}
422 Unprocessable Entity {"error":"organization_id and name are required"}
422 Unprocessable Entity {"error":"unsupported parser: elastic"}
422 Unprocessable Entity {"error":"unsupported parser: cef"}
404 Not Found {"error":"ingest token not found"}The 404 is what you get for revoking an identifier that does not exist or has already been revoked, which makes a repeated revoke safe to retry.
Rate limiting
Each token gets a token bucket allowing 1,000 events per second steady with a burst depth of 2,000, and the bucket starts full so a polite collector never trips it on its first request. The limit is per token and per API process. Unauthenticated traffic never reaches the limiter, so a flood of junk tokens cannot grow its state.
The second caveat is arithmetic. The limiter's state lives in one process's memory, so a deployment running several API replicas multiplies the effective ceiling by the replica count. A shared implementation that would make the limit exact across replicas exists in the codebase and is not wired up. The practical meaning: 1,000 events per second is a rate you can rely on being allowed, not a ceiling that will contain a leaked token.
Usage counters, and one gap in them
Every accepted request to the HTTP Event Collector updates the token's last_used_at, last_used_ip, events_ingested and bytes_ingested. Listing your tokens is therefore a quick way to confirm traffic arrived from the address you expected, and a quick way to spot a token still in use that you thought was retired.
Two honest caveats. The counters are best-effort — a counter update failure must never fail a request whose bytes have already been accepted — so they are an indicator rather than a billing record. And OTLP traffic is not counted at all: a token used only for OTLP will report zero events however much it has sent. Do not read a zero as evidence that a token is unused unless you know it is not an OTLP token.
Revoking a token
Revoking used to be an API call and nothing else. It is not any more: the Ingest tokens screen has a working row action to revoke a token. Earlier versions of this article told you to look for the DELETE call because there was no button; there is one now, and it does the same thing.
Find the row and choose to revoke it
SIEM → Ingest tokens in the sidebar. The State column reads active or revoked, and an active row now carries the action.
Type the token's own name to confirm
The confirmation asks you to type the name of the token you are revoking, not to press a second button. That is on purpose: revoking the wrong row silences a log source you were not thinking about, and typing the name is the cheapest way to make you look at which row you are on.
Read what the confirmation tells you, because it is accurate
Every collector using that token stops sending immediately — its very next request is rejected. Nothing warns you afterwards. That source simply disappears from the SIEM until you issue a new token and update the collector. Logs already ingested are kept.
The API route is unchanged and still available for scripted use: DELETE on the token's sit- identifier, answering 204 No Content, and 404 for an identifier that does not exist or has already been revoked — so a repeated revoke is safe to retry.
Rotation
There is no rotate endpoint, and there does not need to be one. Rotation is three steps, and the API is built so that you can do them without an outage.
Issue the replacement
POSTa new token with the sameparser_kindand a name that makes the cutover legible — appending the date is enough. Both tokens are now valid simultaneously, which is the point.Cut the collector over and confirm
Update the shipper's configuration and confirm the new token's
events_ingestedis climbing. Listing returns active tokens first and revoked ones after, ordered newest first within each group, so during a cutover you can see both without filtering.Revoke the old one
DELETEthe old identifier. Revocation is effective on the very next request — nothing caches a resolved token — so there is no propagation window to wait out.
Revocation is a soft delete: the record stays, with a revocation timestamp, and the usage counters are preserved. That is deliberate. The audit question what did that collector send us, and when did it stop is one you will eventually want answered, and hard-deleting the row would destroy the only record of it.
One thing has changed about step one. The replacement you issue now carries the default lifetime described above — 400 days unless you asked for longer, up to a 730-day maximum. So a rotation is no longer only a manual habit: the token you create today has an end date attached to it whether or not you write one down.
If a token leaks
- Revoke it first, then investigate. Use the row action on the Ingest tokens screen, or
DELETEthe identifier. It stops working on the next request and the collector using it will start receiving401 invalid token. Accept the few minutes of lost collection; it is cheaper than the alternative. - Issue a replacement and cut the legitimate sender over. Same parser kind, new name — and if the collector has a fixed address, restrict the replacement to it while you are there.
- Check what was sent with it. Read the revoked token's
last_used_ipandevents_ingested, and search your events for the source and the window in question. You are looking for events from an address that is not your collector's. - Assume injected events may be present until you have checked. The realistic abuse of a stolen ingest token is not theft, it is pollution — fabricated events to muddy a timeline, or a flood to bury a real one. If the token was used from an address you do not recognise, treat the affected window's events as untrusted when investigating.
- Find and fix the leak path. Almost always a token committed to a repository, pasted into a chat, or logged by the shipper itself at start-up. Make sure your secret scanning matches
zqi_orqxi_so the next one is caught automatically — a rule that names only the old prefix will not see the replacement you just issued.
What to read next
- Sending events with the HTTP Event Collector — the endpoint this credential is for, with a copyable request.
- Connecting your first log source — the concepts, and which sources work end to end today.
- Roles and permissions — who in your organisation can issue and revoke these.