---
title: "Issue an API key to a service account."
method: POST
path: "/organizations/{organizationId}/service-accounts/{serviceAccountId}/keys"
tags: ["service-accounts"]
---

# Issue an API key to a service account.

`POST /organizations/{organizationId}/service-accounts/{serviceAccountId}/keys`

## Request

- Base URL: `https://api.shorebird.dev/api/v1`
- URL: `https://api.shorebird.dev/api/v1/organizations/{organizationId}/service-accounts/{serviceAccountId}/keys`
- Auth: one of:
  - HTTP bearer
  - HTTP bearer

Mints a new `sb_api_*` key for the service account and returns its
secret in `api_key`. The secret is shown only in this response;
store it now, since no later call returns it.

A key does what the service account's role allows and takes no
scope of its own; a body that names `scope` is refused. It lasts 365
days unless `expires_in_days` says otherwise, and never expires only
when `expires_in_days` is explicitly `null`.

Requires the `serviceAccountKeys.create` permission, which only the
`admin` and `owner` roles hold. Personal access tokens and federated
tokens are refused whatever their role.

## Request body

- CreateServiceAccountKeyRequest: The request body for POST /organizations/{organizationId}/service-accounts/{serviceAccountId}/keys. A body that includes `scope` is refused: a service account's key takes no scope of its own.
  - `name` string, required: The key's name. Surrounding whitespace is trimmed; what remains must be 1 to 64 characters.
  - `expires_in_days` integer, nullable: How many days the key lasts, from 1 to 365. Omitted means 365. An explicit `null` issues a key that never expires.

## Response `201`

The new key, including its secret.

- CreateServiceAccountKeyResponse: The response body for POST /organizations/{organizationId}/service-accounts/{serviceAccountId}/keys: the new key, plus its secret.
  - `api_key` string, required: The key's secret, an `sb_api_*` token to send as a bearer token. Returned only here: store it now, since no later call returns it.
  - `id` integer, required: The key's ID.
  - `name` string, required: The key's name.
  - `created_at` string, date-time, required: When the key was issued.
  - `last_used_at` string, date-time, nullable, required: When the key was last used; null for a new key.
  - `expires_at` string, date-time, nullable, required: When the key expires, or null if it never does.
  - `scopes` string[], required: The key's scopes by wire name, `["api"]`.

## Other responses

- `400`: The organization id is not an integer (`organization_id_malformed`), or the service account id is not an integer, the body is not a JSON object, `name` is missing or invalid, `expires_in_days` is out of range, or the body names a `scope` (`service_account_bad_request`, with the reason in `details`).
- `403`: The caller lacks the `serviceAccountKeys.create` permission, or authenticated with a credential that may never manage service accounts.
- `404`: No such organization or the caller is not a member of it (`organization_membership_guard_error`), or the organization has no service account with that id (`service_account_not_found`).
- `424`: A database step failed (`service_account_database_error`).
- `default`: Standard error response. Emitted for any non-2xx status where a body can be decoded into an [ErrorResponse].

---

[API](https://skmtc.dev/shorebird/apis/shorebird-codepush-api.md) - [All operations](https://skmtc.dev/shorebird/apis/shorebird-codepush-api/llms.txt) - [OpenAPI document](https://skmtc.dev/shorebird/apis/shorebird-codepush-api/revisions/941da8871d10?raw)
