Skip to main content

User Profile

The authenticated user's profile — who the token belongs to — and the workspace their data lives in.

Base URL: https://api-v2.kryptos.io

EndpointReturnsRequired Permission
GET/v1/users/meThe profile behind the tokenusers:read
GET/v1/workspacesEvery workspace you are a member of—
GET/v1/workspaces/{wid}One workspace, with its ingestion limitsworkspace:read

Unlike most of the API, /v1/users/me also accepts an API key — pass x-api-key instead of a bearer token.

Request​

curl -X GET "https://api-v2.kryptos.io/v1/users/me" \
-H "Authorization: Bearer ACCESS_TOKEN"

Response​

{
"success": true,
"data": {
"uid": "user_9f2c8a",
"email": "[email protected]",
"firstName": "Alex",
"lastName": "Rivera",
"active": true,
"clientType": ["retail"],
"preferredLanguage": "en",
"createdAt": "2026-01-04T11:02:00.000Z",
"updatedAt": "2026-08-01T09:30:00.000Z"
}
}
FieldTypeDescription
uidstringStable user identifier — matches the sub claim in an OIDC token
emailstringEmail address; unique across Kryptos
firstName, lastNamestring | nullName, when provided
activebooleanAccount is active
clientTypearrayOne or more of retail, enterprise, accountant, developer
preferredLanguagestringLanguage code, default en
createdAt, updatedAtstringISO 8601

clientType is an array, not a single value — a user can be both retail and accountant. Branch on membership, not equality.

404 is expected for a Guest​

{ "success": false, "error": "User not found" }

A 404 here means the token authenticated but no profile exists. That is the normal response for a Kryptos Connect Guest — a workspace-scoped identity with no user account behind it. Don't treat it as an error state; check is_anonymous at login instead. See Guest and Linked users.

Your workspaces​

GET /v1/workspaces

The profile itself does not list workspaces — all portfolio data is workspace-scoped, and for a token-bound credential the workspace is resolved from the credential rather than from the profile. See Workspaces for how that resolution works. This endpoint enumerates every workspace the authenticated user is a member of.

curl -X GET "https://api-v2.kryptos.io/v1/workspaces?type=retail&status=active" \
-H "Authorization: Bearer ACCESS_TOKEN"

Query Parameters​

ParameterTypeDefaultDescription
pageinteger1Page number
limitinteger10Page size. Note the default is 10, not the 50 most list endpoints use
typestring—retail, enterprise or connect-anonymous
statusstring—active, suspended or pending — your membership status, not the workspace's
roleIdstring—Only workspaces where you hold this role

Response​

{
"success": true,
"data": {
"workspaces": [
{
"wid": "ws_12ab",
"workspaceName": "My Workspace",
"type": "retail",
"countryCode": "AU",
"costBasisMethod": "FIFO",
"timezone": "Australia/Sydney",
"baseCurrencyCode": "AUD",
"organizationId": null,
"roleId": "owner",
"status": "active",
"joinedAt": "2026-01-04T11:02:00.000Z",
"createdAt": "2026-01-04T11:02:00.000Z",
"updatedAt": "2026-08-01T09:30:00.000Z"
}
],
"pagination": { "page": 1, "limit": 10, "total": 1 }
}
}

Each entry is a workspace joined with your membership in it. Alongside the workspace fields described under One workspace, it carries:

FieldTypeDescription
roleIdstringYour role in this workspace — owner, admin and so on
statusstringYour membership status: active, pending (an unaccepted invite) or suspended
joinedAtstring | nullWhen you accepted the invite; null if never accepted
organizationIdstring | nullParent organization, for enterprise workspaces
status is about you, not the workspace

Both the filter and the returned field describe your membership. A pending entry is an invite you have not accepted — the workspace itself is fine. Don't read it as a workspace health signal.

pagination here carries only page, limit and total — no totalPages or hasMore, unlike the paginated collections elsewhere in the API. Derive the page count from total and limit.

limits is not included in list entries. It is computed per workspace and returned only by the single-workspace read below.

A Guest gets an empty list, not an error

The list is built by joining workspaces to membership rows, and a Kryptos Connect Guest has none — Guest login creates a workspace and nothing else, with no user record and no membership. So a Guest token authenticates normally and returns 200 with workspaces: [].

That is not a failure, and there is nothing to look up: a Guest belongs to exactly one workspace and its id is already bound into the token. Use it directly with One workspace.

One workspace​

GET /v1/workspaces/{wid} · Required Permission: workspace:read

Reads one workspace you already have the id for — including the ingestion limits the list omits.

curl -X GET "https://api-v2.kryptos.io/v1/workspaces/ws_12ab" \
-H "Authorization: Bearer ACCESS_TOKEN"

Response​

{
"success": true,
"data": {
"wid": "ws_12ab",
"workspaceName": "My Workspace",
"type": "retail",
"countryCode": "AU",
"costBasisMethod": "FIFO",
"timezone": "Australia/Sydney",
"baseCurrencyCode": "AUD",
"customAssetPricesEnabled": false,
"organizationId": null,
"lastSyncTime": "2026-08-13T09:16:02.000Z",
"lastAccountingCalculation": "2026-08-13T09:18:40.000Z",
"createdAt": "2026-01-04T11:02:00.000Z",
"updatedAt": "2026-08-01T09:30:00.000Z",
"limits": {
"transactionLimit": 5000,
"enableLimiter": true,
"effectiveTransactionLimit": 5000,
"currentTransactionCount": 4871,
"remainingTransactions": 129
}
}
}
FieldTypeDescription
widstringWorkspace identifier
workspaceNamestringDisplay name
typestringretail, enterprise or connect-anonymous (a Kryptos Connect Guest workspace)
countryCodestringTax jurisdiction
costBasisMethodstringe.g. FIFO
timezonestringIANA timezone
baseCurrencyCodestringCurrency all values are reported in
customAssetPricesEnabledbooleanManually-set asset prices are in effect for this workspace
organizationIdstring | nullParent organization, for enterprise workspaces
lastSyncTimestring | nullEvery integration last settled at this time; null if never
lastAccountingCalculationstring | nullCost-basis calculation last completed; null if never
createdAt, updatedAtstringISO 8601
limitsobjectTransaction-ingestion cap — see below

Compare transaction counts against limits.effectiveTransactionLimit rather than the raw override it resolves. Manually-set asset prices have their own endpoint, GET /v1/workspaces/{wid}/custom-asset-prices.

Ingestion limits​

limits is returned on this single-workspace read only.

FieldTypeDescription
transactionLimitnumber | nullThe raw per-workspace override. null when unset — the workspace inherits the default
enableLimiterboolean | nullThe raw override flag. null when unset
effectiveTransactionLimitnumber | nullThe cap actually enforced. null when the workspace is uncapped
currentTransactionCountnumberSaved rows plus the rows a running sync has in flight
remainingTransactionsnumber | nullHeadroom before ingestion stops. null when uncapped

Compare counts against effectiveTransactionLimit, not transactionLimit — an unset override still inherits a cap, so a null transactionLimit does not mean unlimited.

Once remainingTransactions reaches 0, syncs stop mid-run and report limitReached. For Connect partners, raising a Guest user's cap is PATCH /developer/grants/{grantId}/transaction-limit.