Skip to main content
Salfio Docs

Search documentation

Type to search this documentation.

List a client's cards

GET/clients/{clientId}/cardsList a client's cards

Returns the AI-generated cards (briefing, wins/traction, risks/frictions, topics) for the client, in the display order configured in the organization's card settings. Filtered to configs where both is_active and is_displayed are true; the column-only configs that surface on the clients-overview list are intentionally excluded here.

Stale handling. When at least one card is stale, that card is returned with is_stale=true AND a regeneration is enqueued for the worker to pick up on its next tick. The read path is purely lazy — no synchronous LLM call is ever made on a partner request. Re-call the endpoint after a short delay to observe the refreshed value (is_stale=false, new last_update).

Cross-tenant lookups and missing clients both return 404 not_found so existence is never leaked.

Parameters

clientIdstring · uuidpathrequired

Client UUID.

Responses

200Ordered list of the client's cards.application/json

Headers

X-RateLimit-Limit

The request cap for the tighter of the per-organization / per-endpoint windows that applied to this request.

X-RateLimit-Remaining

Requests remaining in the current window.

X-RateLimit-Reset

Unix timestamp (seconds) when the current window resets.

value
allOf · 2 options
Option 1objectEnvelope
datavaluerequired

The response payload — shape depends on the endpoint.

metaobjectrequired

Pagination metadata — populated on list endpoints, empty on single-resource endpoints.

Show child attributes
cursornull | string

Opaque cursor to pass to the next request.

hasMoreboolean | null

True when further pages of results are available.

Option 2object
dataarray of object
Show child attributes
Show array items

One AI-generated card for a client. Each card is the result of running an organization-level prompt against the client's recent activities — the prompt and display position are configured by the organization's admins, the value is computed and refreshed by the Salfio worker. `value` is `null` until the worker has produced the first rendered output (the dashboard renders this as a "generating…" state). `is_stale=true` means the underlying activities have changed since the value was last computed — the value shown is the previous one and a refresh is in flight. Polling will pick up the new value once the worker finishes; reading this endpoint also nudges the worker to prioritise the refresh. `last_update` is the wall-clock time the value was last written by the worker; `null` when no value has been produced yet.

card_config_idstring · uuidrequired

ID of the parent card configuration this value was computed for. Shared across every client in the organization.

card_value_idstring · uuidrequired

ID of this client's instance of the card — the thing that holds `value`. Unlike `card_config_id`, which is shared by every client using the same card definition, this is unique per client and per card. Pass it to `POST /cards/{cardValueId}/feedback` to report an issue with what you read here.

display_orderintegerrequired

Position the card occupies in the ordered list (lower values first). The base value is implementation-defined; rely on the relative ordering, not the absolute number.

identifierstringrequired

Stable, machine-readable identifier of the card (e.g. `briefing`, `wins_traction`).

is_stalebooleanrequired

True when the underlying activities have changed since `value` was last written. A refresh is enqueued automatically on read.

last_updatenull | string · date-time

Time the worker last wrote `value`. `null` when no value has been produced yet.

titlestringrequired

Human-readable title configured for this card.

valuenull | string

Rendered Markdown value of the card. `null` until the worker has produced output.

Example response
{
  "data": [
    {
      "card_config_id": "00000000-0000-0000-0000-000000000000",
      "card_value_id": "00000000-0000-0000-0000-000000000000",
      "display_order": 1,
      "identifier": "briefing",
      "is_stale": true,
      "last_update": "2026-06-09T00:00:00Z",
      "title": "Briefing",
      "value": "string"
    }
  ],
  "meta": {
    "cursor": "string",
    "hasMore": true
  }
}
400Request body / query parameters failed validation.application/json
objectErrorEnvelope
errorobjectrequired
Show child attributes
codestringrequired

Machine-readable error category.

one of "unauthorized", "forbidden", "not_found", "invalid_argument", "conflict", "rate_limited", "internal_error", "not_implemented"

detailsobject

Optional per-code context (field names, retry windows, …).

messagestringrequired

Human-readable description — intended for operator logs, not end-user display.

Example response
{
  "error": {
    "code": "invalid_argument",
    "message": "limit must be an integer between 1 and 100"
  }
}
401Missing or invalid bearer token. The message is intentionally opaque — do not rely on it to distinguish "missing" from "invalid".application/json
objectErrorEnvelope
errorobjectrequired
Show child attributes
codestringrequired

Machine-readable error category.

one of "unauthorized", "forbidden", "not_found", "invalid_argument", "conflict", "rate_limited", "internal_error", "not_implemented"

detailsobject

Optional per-code context (field names, retry windows, …).

messagestringrequired

Human-readable description — intended for operator logs, not end-user display.

Example response
{
  "error": {
    "code": "unauthorized",
    "message": "Authentication required"
  }
}
404The referenced resource does not exist, or belongs to a different organization than the one owning the API key. The public API does not distinguish between these cases — both return 404 to avoid leaking cross-tenant existence. application/json
objectErrorEnvelope
errorobjectrequired
Show child attributes
codestringrequired

Machine-readable error category.

one of "unauthorized", "forbidden", "not_found", "invalid_argument", "conflict", "rate_limited", "internal_error", "not_implemented"

detailsobject

Optional per-code context (field names, retry windows, …).

messagestringrequired

Human-readable description — intended for operator logs, not end-user display.

Example response
{
  "error": {
    "code": "not_found",
    "message": "client not found"
  }
}
429Per-organization or per-endpoint rate limit exceeded.application/json

Headers

Retry-After

Seconds the client should wait before retrying.

objectErrorEnvelope
errorobjectrequired
Show child attributes
codestringrequired

Machine-readable error category.

one of "unauthorized", "forbidden", "not_found", "invalid_argument", "conflict", "rate_limited", "internal_error", "not_implemented"

detailsobject

Optional per-code context (field names, retry windows, …).

messagestringrequired

Human-readable description — intended for operator logs, not end-user display.

Example response
{
  "error": {
    "code": "rate_limited",
    "details": {
      "retry_after_seconds": 30
    },
    "message": "Rate limit exceeded"
  }
}

Documentation menu