Skip to main content
Version: 1

AdviceCloud Firm API

The Firm domain API, first release: the firm's investment configuration — its risk profiles and their asset-class and security-category allocation matrices, its security asset-category overrides, and its minimum trade sizes. This document describes the operations this release publishes and no others.

Base URL​

Send every request to the production base URL:

https://app.advicecloudft.com/api

Each path in this document carries the /v1 segment, and it goes after the base URL. The path /v1/firm/risk is called as https://app.advicecloudft.com/api/v1/firm/risk.

Versions​

The version is a segment of the path. Every operation of this release is served under /v1. The segment was part of the path from the first publication, so a caller can pin a version from its first request. The same path without the segment does not answer.

Each domain API has its own version and is deprecated on its own schedule. A caller that uses three domain APIs tracks three version numbers.

A change that would break a caller that conforms to the published description of a version is made only under a different version of that domain API. Five kinds of change are breaking:

  • removing a field
  • renaming a field
  • narrowing a type
  • changing a status code
  • changing the meaning of an existing parameter

Two kinds of change are not breaking, and can be made under the same version: adding an optional field, and adding an optional parameter.

Authentication​

A script calls the API on behalf of a person, with the OAuth 2.0 device authorization grant. The token belongs to the person, and each call carries the firm, the role and the scopes of that person.

  1. The script sends a device authorization request to the issuer host. The request names the client_id, the script audience and the scopes, for example offline_access read:firm. The response carries a device_code, a user_code and a verification_uri.
  2. The script shows the code and the address to the person. The person opens the address on any device that has a browser and signs in with their AdviceCloud login.
  3. The consent page names "AdviceCloud API" and lists the scopes. Approve only a code that you started yourself.
  4. The script polls the token endpoint on the issuer host with the grant type urn:ietf:params:oauth:grant-type:device_code. When the person approves, the script gets an access token, valid for 3600 seconds, and a refresh token. A request for any audience other than the script audience is refused.
  5. The script calls a /v1 path with the access token as a bearer token. The token reaches only operations that require a scope, and only when it carries that scope. The API refuses it with status 403 on every other route that requires a token.
  6. When the access token expires, the script uses the refresh token to get a new one. Each use of the refresh token returns a new refresh token. The person does nothing.

Rules for the script.

  • Save the new refresh token before you use the new access token.
  • Use one approval in each process. Two processes that share one token file end the approval.
  • Do not send a refresh token that was already used. The approval then ends. A retry after a network error can send a used refresh token.

When the person approves again. The refresh fails, and the person does step 2 again, in each of these cases:

  • after 30 days with no refresh
  • after 90 days in total
  • after the script sends a refresh token that was already used
  • after AdviceCloud revokes the approval

The values in the example. $ISSUER_HOST, $CLIENT_ID and $SCRIPT_AUDIENCE are the issuer host, the client_id of the "AdviceCloud API" client and the identifier of the script audience. The security scheme of this document states whether they are published yet. Use the issuer host exactly as published: a token from a different host gets status 401 from the API. $API_ROOT is the base URL above.

# 1. Start. Show verification_uri_complete, or verification_uri and user_code, to the person.
curl -s -X POST "https://$ISSUER_HOST/oauth/device/code" \
-d client_id="$CLIENT_ID" -d audience="$SCRIPT_AUDIENCE" \
-d scope="offline_access read:firm"

# 2. Poll every `interval` seconds until the person approves.
# Save refresh_token before you use access_token.
curl -s -X POST "https://$ISSUER_HOST/oauth/token" \
-d grant_type="urn:ietf:params:oauth:grant-type:device_code" \
-d device_code="$DEVICE_CODE" -d client_id="$CLIENT_ID"

# 3. Call the API.
curl -s "$API_ROOT/v1/firm/risk" -H "Authorization: Bearer $ACCESS_TOKEN"

# 4. Renew. Save the new refresh_token before you use the new access_token.
# Do not send the old refresh_token again. Auth0 then ends the approval.
curl -s -X POST "https://$ISSUER_HOST/oauth/token" \
-d grant_type=refresh_token -d client_id="$CLIENT_ID" -d refresh_token="$REFRESH_TOKEN"

Scopes​

The public API has 12 scopes: a read: and a write: scope for each of the six domain APIs. All of them are listed here, although this release publishes only the Firm domain API. In this release, read:firm authorizes the reads and write:firm authorizes the writes, and every operation requires one of the two on the bearer token.

Each scope authorizes the route prefixes listed after it:

  • read:household: /households, /accounts, /contacts, /households/:householdId/rmd, /rmd, /search
  • write:household: /households, /accounts, /contacts, /households/:householdId/rmd, /rmd, /search
  • read:firm: /firm, /users, /profile
  • write:firm: /firm, /users, /profile
  • read:model: /models
  • write:model: /models
  • read:billing: /billing, /cash-settings
  • write:billing: /billing, /cash-settings
  • read:report: /reports, /reports/13f, /insights, /dashboard, /activity-log
  • write:report: /reports, /reports/13f, /insights, /dashboard, /activity-log
  • read:rebalance: /rebalances, /transactions, /transfers, /securities
  • write:rebalance: /rebalances, /transactions, /transfers, /securities

read:report, write:report, read:rebalance and write:rebalance authorize more than their names say. The prefixes above are the whole of what each one covers.

The Client domain API's scopes are read:household and write:household. In an OAuth scope the word "client" already names the OAuth client, so a scope built on "client" would read two ways.

Pagination​

Each operation that returns a list whose length the request does not bound takes two query parameters:

  • limit: how many rows the response carries. The default is 50.
  • offset: how many rows to skip before the first row of the response. The default is 0.

No maximum page size applies. The server uses the limit you send; it does not lower it and does not refuse it for being large.

A malformed limit or offset is refused with status 400, not replaced with the default: a negative number, a decimal, exponent notation, a value that is not a number, or a limit below 1.

The response keeps the data key that every response carries, and puts a pagination key beside it. pagination holds the limit and offset that produced the page and totalCount, the size of the whole collection:

{
"data": [ ... ],
"pagination": { "limit": 50, "offset": 0, "totalCount": 137 }
}

Rows can be skipped or repeated when the collection changes between requests. A script that walks a collection page by page can then get a wrong answer, with no error and no way to detect it. The API has no cursor today.

Errors​

Every error response carries the same JSON body, whatever the operation:

{
"statusCode": 400,
"message": "One sentence that a person can read.",
"details": { ... }
}
  • statusCode: a number, always present. It equals the HTTP status of the response.
  • message: a string, always present. One sentence that a person can read.
  • details: an object, present only when the operation has facts of its own to report. Read only the keys in it that you understand.

A caller can read statusCode and message without knowing which operation it called.

What each status means:

  • 400: the request is malformed. A query parameter or the request body fails validation. When more than one check fails, message joins their sentences with ; .
  • 401: the request carries no bearer token, or the API does not accept the token, for example because it has expired or because a different issuer host issued it.
  • 403: the API accepts the token, but not for this operation. The role of the person does not permit the operation, or the token does not carry the scope that the operation requires.
  • 404: no operation matches the method and the path of the request. What an operation returns for an id that does not exist is stated on that operation.
  • 429: the request is over a rate limit. See Rate limit.
  • 500: the API failed. The body is { "statusCode": 500, "message": "Internal server error" }.

A status 500 on the first call after the approval. This status is not a temporary fault. Do not retry the call. The API returns 500 when the user record of the person has no firm, and a retry does not change the user record.

Rate limit​

The API has two rate limits, and it counts each request on one of them at most. A request over a limit gets status 429.

The limit for each person. A request whose token is for the script audience is counted on the limit of the person that the token belongs to: 30 requests per 10 seconds per person per API instance. The person has one count for all of their requests, whatever the operation. The API counts the request after it accepts the token and before it checks the scope, so a request that gets status 403 is counted, and a request that gets status 401 is not. A request over this limit gets the Retry-After-per-person header, which gives the number of seconds to wait before the next request of that person.

The limit for each client IP address. Every other request is counted by the client IP address: 30 requests per 10 seconds from one client IP address to one operation. Each operation keeps its own count. Requests sent from the same address share one count. The request is counted before the token is checked, so a request that gets status 401 is counted too. A request whose bearer token names the script audience is not counted on this limit. A request over this limit gets the Retry-After header, which gives the number of seconds to wait before the next request to that operation.

Each API instance counts on its own. Each API instance keeps its own counters in its own memory, and the counters are not shared. A caller's requests are spread across however many instances are running, so the limit a caller actually meets is up to the instance count times higher than the figures above, and the caller cannot control or see which instance answers a request. Treat each figure as the floor that is always enforced, not as a quota to spend.

Deprecation​

Removing or breaking a published operation is announced before the change ships. The minimum notice period is 90 days, and it runs from the first publication of the version that is deprecated, not from the announcement.

The announcement uses all four of these channels:

  • the Deprecation response header, sent on the deprecated operation
  • deprecated: true on the operation in this document
  • an entry in the changelog, written for the release that announces the deprecation
  • a direct email to each customer of the domain API that is deprecated

The Deprecation response header is not built yet. Nothing in version 1 is deprecated, so no operation sends it. A future deprecation will use it.

Changes and revisions​

The changelog lists the changes to this document. One changelog covers every domain API, and each entry names the domain API and the version it belongs to, because each domain API has its own version.

  • For a person: https://app.advicecloudft.com/api/openapi/changelog
  • For a script: https://app.advicecloudft.com/api/openapi/changelog.json

An additive change is made under the same version, so what this document says about a version can change while that version is served. Each revision of this document is identified by the date it was first published, in the form YYYY-MM-DD, with a -N suffix only when a second revision was published on the same day.

This document is revision 2026-09-24-2. It is at:

https://app.advicecloudft.com/api/openapi/revisions/2026-09-24-2.json

An earlier revision is at the same address with its own identifier in place of this one. A revision stays available while any domain API version it describes is served. The changelog lists the revisions that are kept.

Authentication​

OAuth 2.0 device authorization grant (RFC 8628). A script calls the API on behalf of a person. The script shows a short user code and a verification address. The person opens that address on any device that has a browser, signs in, and approves a code that they started themselves. The token belongs to the person, and each call carries the firm, the role and the scopes of that person.

Grant types: urn:ietf:params:oauth:grant-type:device_code and refresh_token, and no others. OpenAPI 3.0 and 3.1 have no flow type for the device authorization grant, so this scheme names no standard flow. The grant types are in x-grant-types, and the scopes are in the scopes map of the x-deviceCode flow.

An access token is valid for 3600 seconds. Each use of a refresh token returns a new refresh token. A refresh token expires after 2592000 seconds (30 days) with no use, and after 7776000 seconds (90 days) in total. A person cannot change these lifetimes. Offline access is allowed, which is what issues the refresh token.

These values are not yet published: the issuer host, the device authorization address, the token address, the client id of "AdviceCloud API" and the identifier of the script audience. This document gives no placeholder in their place.

x-audiences lists the audiences that this API accepts in the aud claim of a token. The API refuses a token whose aud is none of them. This scheme does not describe the audience of the MCP server, which uses a different audience.

Security Scheme Type:

oauth2

OAuth Flow (x-deviceCode):

Scopes:

  • read:firm: Read the Firm domain. At this release it reaches the 9 read operations of the Firm domain API's first release.

  • write:firm: Write the Firm domain. At this release it reaches the 13 write operations of the Firm domain API's first release.

Contact

AdviceCloud:

URL: https://help.advicecloudft.com