---
title: "Read one service credential"
method: GET
path: "/credentials/{credentialId}"
tags: ["Credentials"]
---

# Read one service credential

`GET /credentials/{credentialId}`

## Request

- Base URL: `https://inkseal.net/api/v1`
- URL: `https://inkseal.net/api/v1/credentials/{credentialId}`
- Auth: HTTP bearer

One credential and the secrets issued for it. Raw key material is never included.

A credential id belonging to another workspace answers 404, not 403: a 403 would confirm that the identifier exists.

## Response `200`

The credential.

- object
  - `data` Credential, required: A service credential: an identity, a grant, and the keys issued for it. Raw key material never appears here.
    - `id` string, required: The credential's public identifier, stable across rotations.
    - `name` string, required: A human label, 1 to 255 characters.
    - `agentIdentity` string, nullable, required: Who or what acts under this credential. Recorded on every audit row the credential writes, so an action can be traced back to the agent rather than to the human who issued the key.
    - `scopes` CredentialScope[], required: The grant, deduplicated and ordered by the scope vocabulary. Never empty.
    - `isLegacy` boolean, required: True for a credential grandfathered by the scoping migration, which holds the full scope set. Writing an explicit grant clears it.
    - `isActive` boolean, required: False once revoked. A revoked credential still appears in listings so the audit trail stays legible.
    - `createdAt` string, date-time, required
    - `expiresAt` string, date-time, nullable, required: When the credential itself stops authenticating, if an expiry was set.
    - `revokedAt` string, date-time, nullable, required: When the credential was revoked.
    - `lastUsedAt` string, date-time, nullable, required: When any of this credential's keys last authenticated a request.
    - `secrets` CredentialSecretSummary[], required: The keys issued for this credential, newest first. Ordinarily one; two while a rotation grace window is open.
      - `prefix` string, required: The first 8 characters of the key: `isk_` plus the first four characters of its body.
      - `lastFour` string, required: The last four characters of the key.
      - `createdAt` string, date-time, required
      - `expiresAt` string, date-time, nullable, required: Set only while a rotated-out secret serves its 24-hour grace window. Null for the current secret.
      - `revokedAt` string, date-time, nullable, required: When this key stopped working, either because the credential was revoked or because a second rotation cut its grace window short.
      - `lastUsedAt` string, date-time, nullable, required: When this key last authenticated a request. Null if it never has.
    - `limits` CredentialLimits, required: The spend ceilings on a credential. Null on either means no ceiling. They are enforced in the transaction that claims an envelope for send, so concurrent sends cannot cross one, and a refusal answers 429 `credential_limit_exceeded` having sent nothing.
      - `maxCreditsPerDay` integer, nullable, required: Credits this credential may spend in one UTC day. Counted in credits rather than sends, so a bigger envelope draws more of it down, and counted only on a metered workspace.
      - `maxSendsPerHour` integer, nullable, required: Envelopes this credential may send in one UTC hour, whether or not the workspace is metered.
    - `pausedAt` string, date-time, nullable, required: Set while the credential is paused. A pause is reversible and leaves the issued keys intact, unlike a revocation: a paused key answers 401 `unauthorized` and starts working again the moment the pause is lifted.

## Other responses

- `401`: The credential is missing, malformed, unknown, expired, revoked, or past its rotation grace window. Code: `unauthorized`. Every authentication failure is deliberately indistinguishable.
- `403`: The credential is valid but may not do this. Codes: `insufficient_scope` (the route's scopes are not all held; `details` names `requiredScopes` and `missingScopes`), `forbidden` (the capability check on the resolved resource failed), `scope_escalation` (a grant wider than the caller's own was requested).
- `404`: The resource does not exist, was deleted, or belongs to another workspace. Code: `not_found`. The three cases are answered identically on purpose, so a 404 never confirms that an identifier exists elsewhere.
- `429`: A limit was reached. Codes: `rate_limited` (the credential's per-bucket HTTP limit, or the per-workspace detection throttle), `workspace_limit_exceeded` (a workspace content or send limit; `details.limit` names it), `daily_budget_exceeded` (the workspace's daily detection budget). The four rate-limit headers are sent on this response and on no successful one, so a client cannot read its remaining budget without being refused. Retrying after `Retry-After` is always safe: a rate-limit refusal happens before the handler runs.
- `503`: A dependency the request needs is unreachable and nothing was changed. Codes: `queue_unavailable` (a background job could not be enqueued; retry the call), `billing_unavailable` (Stripe would not open a checkout session; nothing was charged, retry the call), `service_unavailable` (the rate-limit store is down, so the request was refused before running).

---

[API](https://skmtc.dev/inkseal/apis/inkseal-api.md) · [All operations](https://skmtc.dev/inkseal/apis/inkseal-api/llms.txt) · [OpenAPI document](https://skmtc.dev/inkseal/apis/inkseal-api/revisions/c440c981d578?raw)
