Skip to content

Applications API

/api/v1/applications/* lets you manage the applications registered in your tenant — the OAuth clients your code authenticates as. The tenant admin console drives these endpoints; you call them directly when automating provisioning (e.g., a Terraform provider, a CI step that creates a fresh client for an integration test).

Scoped to applications:read and applications:write.

GET /api/v1/applications
Authorization: Bearer <access-token>
Required scope: applications:read
Query parameters:
cursor — pagination
limit — 1–250, default 50
type — 'spa' | 'm2m' | 'native' | 'server' | 'saml'
state — 'enabled' | 'disabled'
q — free-text search across name, description, client_id
{
"data": [
{
"id": "app_01HZX...",
"client_id": "app_01HZX...",
"name": "Cymmetri Banking Web",
"type": "spa",
"state": "enabled",
"created_at": "2026-01-15T10:00:00Z"
}
],
"meta": { "next_cursor": "...", "limit": 50 }
}
POST /api/v1/applications
Authorization: Bearer <access-token>
Content-Type: application/json
Required scope: applications:write
{
"name": "Cymmetri Banking Web",
"type": "spa",
"redirect_uris": [
"https://banking.cymmetri.com/callback",
"http://localhost:5173/callback"
],
"allowed_origins": ["https://banking.cymmetri.com"],
"allowed_scopes": ["openid", "profile", "email", "offline_access"],
"audience": "https://api.cymmetri.com",
"access_token_ttl_s": 3600,
"refresh_token_ttl_s": 1209600,
"tags": ["customer-facing", "production"]
}

Returns the created application with its client_id. For m2m and server types, also returns the client secret — exactly once. Copy it to your secret manager immediately; the API does not return it on subsequent fetches.

{
"data": {
"id": "app_01HZX...",
"client_id": "app_01HZX...",
"client_secret": "ias_abc123...",
...
}
}
GET /api/v1/applications/{application_id}
Authorization: Bearer <access-token>
Required scope: applications:read

The detailed DTO covers the full configuration plus action hints (can_* booleans tell you which operations the current caller is allowed to perform — handy for the admin UI).

{
"data": {
"id": "app_01HZX...",
"client_id": "app_01HZX...",
"name": "...",
"type": "spa",
"state": "enabled",
"redirect_uris": [...],
"allowed_origins": [...],
"allowed_scopes": [...],
"tags": [...],
"can_rotate_secret": false, // SPA — no secret to rotate
"can_disable": true,
"can_delete": true,
"audit_summary": { ... }
}
}
PATCH /api/v1/applications/{application_id}
Authorization: Bearer <access-token>
Content-Type: application/json
Required scope: applications:write
{
"redirect_uris": ["https://banking.cymmetri.com/callback", "https://staging.cymmetri.com/callback"],
"tags": ["customer-facing", "production", "v2-migration"]
}

Fields not in the body are unchanged. Some fields are immutable post-creation (type, client_id).

POST /api/v1/applications/{application_id}/rotate-secret
Authorization: Bearer <access-token>
Required scope: applications:write
{
"data": {
"client_secret": "ias_xyz789...",
"previous_expires_at": "2026-05-20T10:00:00Z"
}
}

The new secret is returned once. The previous secret stays valid until previous_expires_at (configurable per tenant, default 72 hours) so you can roll out the new secret to your deployments without downtime.

Only meaningful for m2m and server application types. SPA / native applications have no client secret and this endpoint returns 400 not_applicable.

POST /api/v1/applications/{application_id}/disable
POST /api/v1/applications/{application_id}/enable
Required scope: applications:write

A disabled application cannot acquire new tokens. Existing tokens it has already issued remain valid until expiry; revoke them separately if needed.

DELETE /api/v1/applications/{application_id}
Authorization: Bearer <access-token>
Required scope: applications:write

Hard delete. The application's client_id is never reused; even after delete, that id is gone for good (rules out replay attacks against the deletion).

SAML applications (type: "saml") carry additional fields — entity id, ACS URL, certificate, attribute statements. The shape is documented in the SAML topics; the API endpoints are the same GET, POST, PATCH, DELETE listed here, with a richer body schema.

For "disable all customer-facing apps temporarily" workflows:

POST /api/v1/applications/bulk/disable
Authorization: Bearer <access-token>
Content-Type: application/json
Required scope: applications:write
{
"ids": ["app_01HZX...", "app_01HZY...", "app_01HZZ..."]
}

Same shape for /bulk/enable and /bulk/delete. The platform applies operations atomically per-id (one app failing does not stop the others), and returns a per-id result list.

ErrorWhen
app_not_foundThe id doesn't exist or you can't see it
redirect_uri_invalidA redirect URI is malformed or violates RFC 8252
wildcard_uri_forbiddenA redirect URI contains *
scope_unknownAn allowed scope isn't registered in the tenant
app_in_use_cannot_deleteApplication has active sessions; disable first, wait for sessions to expire, then delete