Service Accounts

Service Accounts

API v0 only. Service account tokens work exclusively with the Credal API v0. They are not accepted by API v1, which uses OAuth 2.0 for authentication.

Service accounts are currently in beta. Contact your Credal representative or support@credal.ai to enable them for your organization.

A service account is a dedicated, non-human identity for machine-to-machine access to the Credal API. Instead of sharing a static organization-wide API key, create a service account for each integration—such as an ingestion pipeline or internal tool—grant only the permissions it needs, and mint scoped, expiring, and individually revocable tokens.

Service accounts always act as themselves. Unlike legacy API keys, a service account token never impersonates a human user. Every API call runs with the service account’s own permissions, and every action is attributed to the service account in your audit logs.

How it works

  1. An organization admin creates a service account with a name and an email address on your organization’s domain, such as ingestion-bot@yourcompany.com.
  2. The admin grants the service account access like any other user, including collection permissions, agent deployments, and IdP group membership. The service account can only access what it has explicitly been granted.
  3. The admin mints one or more tokens for the service account. Each token has a name, a set of scopes, and an expiration date.
  4. Your integration calls the v0 API with the token in the Authorization header.

Create a service account and token

Organization admins manage service accounts from Service Accounts in the Credal web app.

Create a service account

Provide a display name and an email address. The email domain must match your organization’s domain. If you want integration permissions to sync to the service account, use an address that corresponds to its identity in your IdP or source systems.

Create a token

Select the service account, then provide:

FieldDescription
NameA label for the token, such as prod-ingestion.
DescriptionOptional free-form notes.
ScopesThe parts of the API the token may call.
Expiration dateThe date the token stops working. Defaults to one year.

The token is displayed exactly once at creation time and is never shown again. Copy it immediately and store it in a secrets manager. Tokens look like:

cred_sa_<your_token>

If a token is compromised or no longer needed, revoke it from the same page. Revocation takes effect immediately. Deleting a service account revokes all of its tokens.

Scopes

Scopes control which API surfaces a token may call. They are layered on top of the service account’s own permissions: a token can never read data its service account has not been granted, regardless of scope. A token with no scopes cannot call any scoped endpoint.

ScopeGrants
agent:messageSend messages to deployed agents and read their responses.
catalog:writeUpload and update documents through the catalog API.
catalog:readRead documents and collections through the catalog API.

Grant only the scopes each integration needs.

Authentication

Store the token in an environment variable instead of hard-coding it:

$export CREDAL_SERVICE_ACCOUNT_TOKEN="cred_sa_<your_token>"

Pass the token as a Bearer token in the Authorization header of every request:

1Authorization: Bearer cred_sa_<your_token>

Service accounts always act as themselves. Do not send user impersonation fields such as userEmail or uploadAsUserEmail; requests containing them are rejected with a 400 response.

Send a message to an agent

This endpoint requires the agent:message scope. The agent must have API access enabled and be deployed to the service account, just as it would be for a human user. agentId is required, and userEmail must be omitted.

$curl -X POST https://app.credal.ai/api/v0/copilots/sendMessage \
> -H "Authorization: Bearer $CREDAL_SERVICE_ACCOUNT_TOKEN" \
> -H "Content-Type: application/json" \
> -d '{
> "agentId": "3a1b8c2d-0e4f-4a6b-9c8d-7e5f3a1b8c2d",
> "message": "Summarize open support tickets from this week."
> }'

A successful response looks like:

1{
2 "sendChatResult": {
3 "type": "ai_response_result",
4 "conversationId": "9f2e7d61-4c3b-4a5e-8f1d-2b6c9a0e7d61",
5 "response": {
6 "message": "Here is a summary of this week's open support tickets: ..."
7 }
8 }
9}

To continue a conversation, pass the conversationId from a previous response in your next request:

1{
2 "agentId": "3a1b8c2d-0e4f-4a6b-9c8d-7e5f3a1b8c2d",
3 "conversationId": "9f2e7d61-4c3b-4a5e-8f1d-2b6c9a0e7d61",
4 "message": "Which of those tickets are highest priority?"
5}

Upload a file to the catalog

This endpoint requires the catalog:write scope. Send the file as multipart/form-data. documentExternalId is required and identifies the document in your system; uploading again with the same ID updates the document. Omit uploadAsUserEmail because the document is uploaded as the service account.

$curl -X POST https://app.credal.ai/api/v0/catalog/uploadFile \
> -H "Authorization: Bearer $CREDAL_SERVICE_ACCOUNT_TOKEN" \
> -F "file=@quarterly-report.pdf" \
> -F "documentExternalId=quarterly-report-2026-q2" \
> -F "documentName=Quarterly Report Q2 2026" \
> -F "collectionId=5b2c9d3e-1f4a-4b6c-8d9e-0a7f5b2c9d3e"

A successful response returns the Credal document ID:

1{
2 "documentId": "7c4d1e8f-2a5b-4c7d-9e0f-3b8a7c4d1e8f"
3}

Errors

StatusMeaning
401The token is missing, invalid, expired, or revoked.
403Service accounts are not enabled for your organization, or the token lacks the scope required by the endpoint.
400The request is invalid—for example, it contains userEmail or uploadAsUserEmail, or omits agentId when messaging an agent.

Error responses have this shape:

1{
2 "error": {
3 "message": "This service account token is missing the required 'agent:message' scope."
4 }
5}

Best practices

  • Use one service account per integration. This keeps permissions minimal and audit trails clear.
  • Grant the fewest scopes that work. A token for an ingestion job needs catalog:write, not agent:message.
  • Set short expirations and rotate tokens. Mint a new token before the old one expires, deploy it, then revoke the old token.
  • Store tokens in a secrets manager. The plaintext token is shown only once and cannot be recovered; it can only be revoked and reissued.
  • Never send impersonation fields. Service accounts act as themselves, so userEmail and uploadAsUserEmail are rejected.