Get started with the Management API
This guide walks through your first Management API call. You get a token, send a narrowly filtered read for one user, and read the result. It then explains how to set up safe access for automation.
Before you start
You need:
- An environment where the Personalization Service is enabled.
- A token for that environment that holds the Data: Read (
DATA_READ) permission. - The ID of a user whose data you want to inspect.
Choose the token type that fits your use case.
| Token type | Use it for |
|---|---|
| Service Account Token | Backend services, scheduled jobs, scripts, and other automation |
| User Account Token | A person using an administration tool with the permissions of their roles |
For automation, always use a Service Account Token.
Get a token
Service Account Token
- Create a Service Account for this integration in the Mosaic Admin Portal.
- Grant it only the permissions the integration needs. For this guide, grant Data: Read.
- Exchange the Service Account credentials for an access token.
The steps for creating a Service Account, granting permissions, and requesting a token, including generating a token in the Admin Portal for testing, are described in How to Authenticate a Service Account. Access tokens expire, so automation should request a new token when the current one expires.
User Account Token
A User Account Token is the access token that the Identity Service issues to a signed-in Mosaic user. The token carries the permissions of that user's roles. See Authentication and Authorization for how these tokens work.
Keep credentials on the server
A token with Management API permissions can reach the data of every user in the environment. Treat it like any other server credential.
- Store Service Account secrets and tokens in a secret store, not in source control.
- Never embed a Service Account secret or Service Account Token in a frontend application, a mobile app, or any end-user client.
- Use a User Account Token only in trusted administrative tools, where the signed-in person holds the needed permissions.
- Do not log tokens.
End-user applications use the End-User API with tokens issued to end users.
Send your first request
The following read lists the key-value entries that one user stored under one key. Narrow filters like this keep a first call small and make it clear which data you are reading.
The operation:
query InspectUserPreferences($input: ListKeyValuesInput!) {
listKeyValues(input: $input) {
nodes {
key
kind
value
owner {
userId
profileId
applicationId
scope
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
The variables, with a user ID of your choice:
{
"input": {
"filter": {
"userId": "11111111-1111-4111-8111-111111111111",
"key": "ui:preferences",
"scope": "USER"
},
"first": 10
}
}
Send both as one JSON request body.
Replace <token> with your access token.
curl https://personalization.service.eu.axinom.net/graphql-management \
--request POST \
--header "Authorization: Bearer <token>" \
--header "Content-Type: application/json" \
--data '{
"query": "query InspectUserPreferences($input: ListKeyValuesInput!) { listKeyValues(input: $input) { nodes { key kind value owner { userId profileId applicationId scope } } pageInfo { hasNextPage endCursor } } }",
"variables": {
"input": {
"filter": {
"userId": "11111111-1111-4111-8111-111111111111",
"key": "ui:preferences",
"scope": "USER"
},
"first": 10
}
}
}'
Read the response
A successful response contains the matching entries and paging information. The values below are only an illustration of the shape.
{
"data": {
"listKeyValues": {
"nodes": [
{
"key": "ui:preferences",
"kind": "JSON",
"value": { "theme": "dark", "language": "en" },
"owner": {
"userId": "11111111-1111-4111-8111-111111111111",
"profileId": null,
"applicationId": null,
"scope": "USER"
}
}
],
"pageInfo": {
"hasNextPage": false,
"endCursor": "<opaque cursor>"
}
}
}
}
nodescontains one entry per stored record that matches the filter. It is empty when the user has no data under the key.ownertells you exactly where each record is stored.pageInfo.hasNextPagetells you whether to request another page. See Paginate with cursors.
Set up least-privilege access for automation
Create a separate Service Account for each integration and grant only the permissions its operations require.
| Integration purpose | Permission to grant |
|---|---|
| Reporting, audits, and data inspection | Data: Read |
| Support tools that correct one user's data | Data: Read and Data: Write |
| Maintenance jobs that change data for many users | Bulk Data: Write |
A few rules of thumb:
- Start with Data: Read and add permissions only when an integration needs them.
- Keep Bulk Data: Write separate from Data: Write, because bulk jobs can change data for every user in the environment.
- Remove permissions that an integration no longer uses.
See Authentication and permissions for the operation-to-permission mapping.
Fix common problems
| Symptom | Likely cause |
|---|---|
UNAUTHENTICATED error | The token is missing, invalid, or expired, or it is not a User Account or Service Account Token |
FORBIDDEN error | The token does not hold the permission that the operation needs |
BAD_USER_INPUT with reason FILTER_CONSTRAINT | The filter contains ids that contradict the scope. See Filter by owner and scope |
Empty nodes with hasNextPage set to true | Keep following endCursor. See Paginate with cursors |
See Errors and limits for the full list.
Next steps
- Find and inspect data to discover keys and read entries and items.
- Write user data to change one user's data.
- Bulk updates and deletions to change data for many users.