API keys
The API keys resource lets you mint, list, and revoke HMAC credentials programmatically — the same keys you'd otherwise create from Dashboard → Settings → API keys.
This page is about managing keys. For the signing recipe, see Authentication.
The secret is shown exactly once, on creation. Ripllo stores only a one-way hash. If you lose the secret, the only recovery is to revoke the key and mint a new one — there is no fetch-secret endpoint and there never will be.
Endpoints
| Method | Path | Operation |
|---|---|---|
POST |
/api/v1/api-keys |
Create a key |
GET |
/api/v1/api-keys |
List keys |
POST |
/api/v1/api-keys/:id/revoke |
Revoke a key |
All endpoints require the calling key to have the admin scope.
Create a key
POST /api/v1/api-keys
Mints a new key under the caller's workspace and returns the plaintext secret. The secret is not retrievable later.
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
name |
string (1–120) | yes | Human label. Use something specific (Production server, CI — GitHub Actions). |
scopes |
enum[] | no | Subset of ["read", "write", "admin"]. Defaults to ["read", "write"]. See Scopes. |
Response — 201 Created
{
"data": {
"apiKey": {
"id": "akey_01HX...",
"name": "Production server",
"keyId": "AKIARPLO0123456789ABCDEF",
"scopes": ["read", "write"],
"createdAt": "2026-05-13T10:42:00.123Z"
},
"secret": "fulksk_AbCdEf12...verylongbase64url..."
},
"error": null,
"meta": { "requestId": "...", "timestamp": "..." }
}
secret is the HMAC secret. It is present only on this 201 response; subsequent GET calls never include it. Capture it synchronously — pipe to your secrets manager, don't log it, don't keep it in shell history.
The minted key's creation is audited under the operating user.
Errors
| Status | error.code |
When |
|---|---|---|
400 |
VALIDATION |
Shape wrong, name too long, scope not in the allowed set. |
403 |
NO_ACCOUNT |
Caller's token has no accountId. |
Examples
const created = await ripllo.apiKeys.create({
name: 'Production server',
scopes: ['read', 'write'],
});
console.log(created.apiKey.keyId); // AKIARPLO...
console.log(created.secret); // fulksk_… (only here, only now)
created = ripllo.api_keys.create(name='Production server', scopes=['read', 'write'])
print(created['apiKey']['keyId'], created['secret'])
created, err := client.ApiKeys.Create(ctx, &ripllo.ApiKeyCreateParams{
Name: "Production server",
Scopes: []string{"read", "write"},
})
ripllo_curl POST '/api/v1/api-keys' \
'{"name":"Production server","scopes":["read","write"]}'
List keys
GET /api/v1/api-keys
Returns every key in the workspace, newest first. The secret is never included; instead a secretPreview shows the first 8 and last 4 chars for visual confirmation.
Response
{
"data": {
"apiKeys": [
{
"id": "akey_01HX...",
"name": "Production server",
"keyId": "AKIARPLO0123456789ABCDEF",
"secretPreview": "fulksk_A…ef12",
"scopes": ["read", "write"],
"createdAt": "2026-05-13T10:42:00.000Z",
"lastUsedAt": "2026-05-13T11:03:14.000Z",
"revokedAt": null,
"createdBy": "usr_huudis_01HX..."
}
]
},
"error": null,
"meta": { "requestId": "...", "timestamp": "..." }
}
Revoked keys are still returned (with revokedAt populated) so you can audit history. They no longer authenticate.
Revoke a key
POST /api/v1/api-keys/:id/revoke
Revokes a key immediately. Any request signed with it starts returning 401 REVOKED_KEY within seconds — no grace period.
Errors
| Status | error.code |
When |
|---|---|---|
404 |
NOT_FOUND |
No such key in this workspace. |
409 |
ALREADY_REVOKED |
The key was already revoked. |
Revocation is irreversible and propagates within seconds. Always rotate before revoking — never the other way round.
await ripllo.apiKeys.revoke('akey_01HX...');
The API key object
| Field | Type | Notes |
|---|---|---|
id |
string | Internal ID with prefix akey_. Use this in URLs. |
name |
string | What you passed on create. |
keyId |
string | Public access key ID, format AKIARPLO<random>. Goes in the Authorization header. Safe to log. |
secretPreview |
string | First-8/last-4 of the secret. Visual confirmation only; cannot be used to authenticate. |
scopes |
enum[] | Subset of ["read", "write", "admin"]. |
createdAt |
ISO 8601 | |
lastUsedAt |
ISO 8601 | null | Most recent signed request. Updates within seconds of first use. |
revokedAt |
ISO 8601 | null | Revocation time, or null for live keys. |
createdBy |
string | null | Huudis user ID of the operator. |
Scopes
Pick the narrowest scope set that works. Scopes can't be widened — mint a new key.
| Scope | What it allows |
|---|---|
read |
GET endpoints. |
write |
POST / PATCH / DELETE of merchant resources. |
admin |
API key + webhook endpoint management, plus the ripllo:platform:admin capability for partners. |
The ripllo:platform:admin capability that gates X-Ripllo-On-Behalf-Of is bundled into the admin scope on platform-owned workspaces. Regular merchant admin keys do not get to act on behalf of other workspaces — the partner-tier flag is provisioned out-of-band.
Programmatic rotation
Always: mint → verify → cut over → revoke. Never the reverse.
// 1. Mint a replacement.
const next = await ripllo.apiKeys.create({
name: `Production server (rotated ${new Date().toISOString().slice(0, 10)})`,
scopes: ['read', 'write'],
});
// 2. Push next.secret into your secrets manager. Wait for consumers
// to reload and confirm at least one request signs successfully.
await secrets.set('RIPLLO_KEY_ID', next.apiKey.keyId);
await secrets.set('RIPLLO_KEY_SECRET', next.secret);
await waitForConsumersToReload();
// 3. Once lastUsedAt advances on the new key, revoke the old one.
await ripllo.apiKeys.revoke(process.env.OLD_RIPLLO_AKEY_ID);
lastUsedAt is the simplest verification signal — if it advances on the new key within 60 seconds of cutover, you're safe to revoke. Schedule this as a quarterly cron.
Events
The API keys resource is intentionally not broadcast on the event stream — we don't want webhook subscribers enumerating or correlating credential lifecycle. Key creation and revocation do show up in the audit log. Capture a signal in your own systems at the point you call apiKeys.create / apiKeys.revoke.
Next
- Authentication — using the secret you just minted.
- Webhook endpoints — the other half of integration plumbing.