HTTP API
Enter jumps to the next match, shift-enter the previous.
One Markdown file covering the whole product. Last changed August 30, 2026.
Authentication
Every call below is authenticated with your account token, sent as a bearer token. Mint one on Account - it is shown once, in full, and after that only its last few characters are.
curl https://api.arcticauth.com/api/v1/services \
-H "Authorization: Bearer YOUR_ACCOUNT_TOKEN"Regenerating the token on the account screen revokes the old one the moment the new one is issued. There is no grace period and no second active token, so rotate when you have somewhere ready to put the new value.
Signing in with a browser still works exactly as before. These endpoints accept either, and the token is only consulted when an Authorization header is present.
Services
A service is one product: its own keys, its own vault, its own checkpoint chain. The id in a key page URL is the same id used here.
- GET /api/v1/services
- Every service on your account, with its name, identifier, slug and whether it is paused.
- POST /api/v1/services
- Creates one. Body: { "name": "My Hub", "identifier": "my-hub" }. The identifier has to be unique across the platform; a clash answers 409.
- GET /api/v1/services/{serviceId}
- One service in full: name, identifier, slug, plan, checkpoint count, whether it is active, and when it was last used.
- GET /api/v1/services/{serviceId}/stats
- Today's activity. Executions served, keys live and ever issued, validation calls answered, checkpoint runs started and finished, and hardware ids refused.
- GET /api/v1/services/{serviceId}/settings
- Everything on the settings screen, including the HWID cooldown that gates the self-serve reset page.
- PUT /api/v1/services/{serviceId}/settings
- Saves them. The whole object goes in - this is a replace, not a patch, so read it first and send it back changed.
- DELETE /api/v1/services/{serviceId}
- Deletes the service and everything under it. There is no undo and no confirmation step on the API.
curl -X POST https://api.arcticauth.com/api/v1/services \
-H "Authorization: Bearer YOUR_ACCOUNT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"My Hub","identifier":"my-hub"}'curl https://api.arcticauth.com/api/v1/services/SERVICE_ID/stats \
-H "Authorization: Bearer YOUR_ACCOUNT_TOKEN"Keys
Keys are minted in batches, edited one at a time, and deleted either way. A key binds to a machine the first time it is validated, not when it is created.
- GET /api/v1/services/{serviceId}/keys
- Paged. Takes page, pageSize, and a search term matched against the key value, note and Discord id.
- GET /api/v1/services/{serviceId}/keys/counts
- Totals only - live, expired, revoked, premium - without pulling a page of rows.
- POST /api/v1/services/{serviceId}/keys
- Mints a batch. Body: { prefix, count, expirationType, days, expiresAt, isPremium, hwidValidation }. Returns the minted values, once.
- POST /api/v1/services/{serviceId}/keys/import
- Adopts keys minted elsewhere, one per line, so a migration does not invalidate what customers already hold.
- PATCH /api/v1/services/{serviceId}/keys/{keyId}
- Partial: every field is optional and null means leave it. { note, expiresAt, isPremium, hwidLocked, clearHwid, revoked }.
- DELETE /api/v1/services/{serviceId}/keys/{keyId}
- Deletes one.
- POST /api/v1/services/{serviceId}/keys/delete
- Deletes many. Body: { "keyIds": ["...", "..."] }.
curl -X POST https://api.arcticauth.com/api/v1/services/SERVICE_ID/keys \
-H "Authorization: Bearer YOUR_ACCOUNT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"prefix": "HUB",
"count": 10,
"expirationType": 10,
"days": 30,
"isPremium": false,
"hwidValidation": true
}'curl -X PATCH https://api.arcticauth.com/api/v1/services/SERVICE_ID/keys/KEY_ID \
-H "Authorization: Bearer YOUR_ACCOUNT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"clearHwid": true}'Secure vault
Every script, its slug, and the loadstring your users paste. The slug is per script and rotatable on its own, which is what makes a leaked entry point survivable.
- GET /api/v1/services/{serviceId}/vault/scripts
- Every script: id, name, description, slug, whether it accepts a script_key, whether Lockmode is on, its obfuscation preset and its status.
- GET /api/v1/services/{serviceId}/vault/overview
- The same list plus the counters the vault screen shows.
- GET /api/v1/services/{serviceId}/vault/scripts/{scriptId}
- One script in full.
- PATCH /api/v1/services/{serviceId}/vault/scripts/{scriptId}/hardened
- Lockmode for this one script. Body: { "hardened": true }. This is the per-slug switch.
- PATCH /api/v1/services/{serviceId}/vault/scripts/{scriptId}/status
- Serves it or stops serving it. Body: { "enabled": false }. A disabled script answers nothing, which is the fastest kill switch you own.
- DELETE /api/v1/services/{serviceId}/vault/scripts/{scriptId}
- Deletes the script and its versions.
The loadstring is built from the slug rather than returned ready-made, because which of the two shapes a script uses is decided by its own mode:
-- loader-based
_G.SlugID = "SCRIPT_SLUG"
loadstring(game:HttpGet("https://api.arcticauth.com/api/v1/loader"))()
-- direct
loadstring(game:HttpGet("https://api.arcticauth.com/api/v1/s/SCRIPT_SLUG"))()Self-serve pages
Two anonymous pages your users can be sent to instead of you. The key is the credential, so there is nothing for them to sign into.
- POST /api/v1/public/keys/check
- Body: { service, key }. Answers what the key is bound to, when it expires, whether it works, and whether a reset would be allowed right now.
- POST /api/v1/public/keys/reset-hwid
- Body: { service, key }. Unbinds it. Refusals answer 200 with reset: false and a sentence, because "the cooldown has not run out" is an ordinary answer rather than an error.
The pages themselves are /key-checker and /reset-hwid. Both accept the service and the key in the URL, so a link handed to a user arrives filled in:
https://arcticauth.com/reset-hwid/SERVICE_ID
https://arcticauth.com/key-checker/SERVICE_IDValidation
What a script calls at runtime. No token: this one is anonymous by design, because it is called from an executor where any credential you shipped would already be public.
- POST /api/validation/v1/validate
- Body: { service, key, hwid }. Always 200 on a well-formed request, with the verdict in the body - a loader has to branch on the reason anyway, and a 4xx makes some executors throw where a value was expected.
- GET /api/validation/v1/ping
- Liveness, for a loader that wants to fail fast rather than hang.
Errors and limits
Failures answer application/problem+json with a title worth showing and, where it helps, a detail worth logging.
- 401
- No token, a token that is not valid, or one whose account is disabled. All three answer the same, so a leaked token learns nothing.
- 403
- The token's account exists but cannot do that.
- 404
- No such service, or one your account does not own. The two are not told apart, so this cannot be used to find out which ids are real.
- 409
- A conflict with something that already exists - most often a service identifier already taken.
- 429
- Rate limited. The self-serve pages allow 20 calls a minute per address; validation allows 120.

