API keys
An API key authenticates a program. Each key belongs to your organization, acts on one catalog, and holds an explicit list of scopes. The secret is shown once, when the key is minted; //SCHEMA stores only a hash of it.
A credential can never mint a key more powerful than itself: every scope you request must be one the caller already holds. Ask grantableScopes for the list.
See Manage API keys.
- queryapiKeys
- querygrantableScopes
- mutationmintApiKey
- mutationrevokeApiKey
The ApiKey object#
An API key, without its secret.
Attributes
apiKeyPkInt!Unique identifier.catalogPkInt!The catalog the key acts on.nameString!What the key is for.tokenPrefixString!The first characters of the token, enough to recognize it.scopes[String!]!The key's scopes, in wire spelling.createdAtDateTime!When it was minted.- When it stops working, or
nullfor never. - Approximately when it was last used. Updated lazily — good for spotting dormant keys, not for auditing individual requests.
- When it was revoked, or
null.
List API keys#
Every API key your organization holds, newest first, including revoked ones. Never includes the secret.
Arguments
None.
Returns
A list of ApiKey objects.
query {
apiKeys {
apiKeyPk
name
tokenPrefix
scopes
lastUsedAt
revokedAt
}
}curl https://api.schema.fm/graphql \
-H "Authorization: Bearer $SCHEMA_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @- <<'EOF'
{
"query": "query {\n apiKeys {\n apiKeyPk\n name\n tokenPrefix\n scopes\n lastUsedAt\n revokedAt\n }\n}"
}
EOFconst res = await fetch("https://api.schema.fm/graphql", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SCHEMA_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
query: `
query {
apiKeys {
apiKeyPk
name
tokenPrefix
scopes
lastUsedAt
revokedAt
}
}
`,
}),
});
const { data, errors } = await res.json();{
"data": {
"apiKeys": [
{
"apiKeyPk": 305,
"name": "Player backend",
"tokenPrefix": "sk_8Hq2xJ0vZ",
"scopes": ["catalog_read", "media_read"],
"lastUsedAt": "2026-09-18T07:40:12.004103+00:00",
"revokedAt": null
}
]
}
}List grantable scopes#
The scopes this caller may put on a new key — exactly the scopes it holds itself.
Arguments
None.
Returns
A list of scope names in wire spelling, e.g. catalog_read.
query {
grantableScopes
}curl https://api.schema.fm/graphql \
-H "Authorization: Bearer $SCHEMA_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @- <<'EOF'
{
"query": "query {\n grantableScopes\n}"
}
EOFconst res = await fetch("https://api.schema.fm/graphql", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SCHEMA_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
query: `
query {
grantableScopes
}
`,
}),
});
const { data, errors } = await res.json();{
"data": {
"grantableScopes": [
"catalog_read",
"catalog_write",
"config_read",
"config_write",
"media_read",
"media_write"
]
}
}Mint an API key#
Create a key. Copy token from the response immediately — it is
never shown again and cannot be recovered.
Each requested scope must be one the caller holds; an unknown or ungrantable scope is an error, never silently dropped.
Arguments
- What the key is for, e.g.
Player backend. Required, so a list of keys can be audited. - Scopes in wire spelling:
catalog_read,catalog_write,config_read,config_write,media_read,media_write. At least one. catalogPkIntThe catalog the key acts on. Must belong to your organization. Defaults to the caller's catalog.expiresAtDateTimeWhen the key stops working. Omit for a key that does not expire on its own.
Returns
A MintedApiKey, including the secret.
mutation {
mintApiKey(name: "Player backend", scopes: ["catalog_read", "media_read"]) {
apiKeyPk
token
tokenPrefix
}
}curl https://api.schema.fm/graphql \
-H "Authorization: Bearer $SCHEMA_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @- <<'EOF'
{
"query": "mutation {\n mintApiKey(name: \"Player backend\", scopes: [\"catalog_read\", \"media_read\"]) {\n apiKeyPk\n token\n tokenPrefix\n }\n}"
}
EOFconst res = await fetch("https://api.schema.fm/graphql", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SCHEMA_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
query: `
mutation {
mintApiKey(name: "Player backend", scopes: ["catalog_read", "media_read"]) {
apiKeyPk
token
tokenPrefix
}
}
`,
}),
});
const { data, errors } = await res.json();{
"data": {
"mintApiKey": {
"apiKeyPk": 305,
"token": "sk_8Hq2xJ0vZQm1r3TbW7cN5yLs4KpA9eUdGfHj6VxOiBt",
"tokenPrefix": "sk_8Hq2xJ0vZ"
}
}
}Revoke an API key#
Stop a key working, immediately and permanently. The key stays in
apiKeys with revokedAt set. Revoking twice
keeps the first timestamp.
Arguments
- The key to revoke.
Returns
true if a key of your organization was revoked.
mutation {
revokeApiKey(apiKeyPk: 305)
}curl https://api.schema.fm/graphql \
-H "Authorization: Bearer $SCHEMA_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @- <<'EOF'
{
"query": "mutation {\n revokeApiKey(apiKeyPk: 305)\n}"
}
EOFconst res = await fetch("https://api.schema.fm/graphql", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SCHEMA_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
query: `
mutation {
revokeApiKey(apiKeyPk: 305)
}
`,
}),
});
const { data, errors } = await res.json();{
"data": {
"revokeApiKey": true
}
}