Developers

Commands

Every API v3 operation is a cademi command, generated from the API contract and organized by domain. This page explains how an operation becomes a command, how to find commands, and how to pass parameters and bodies, read the output, paginate, and handle writes and asynchronous operations.

From operation to command

Commands are grouped in 11 resource domains: account, automations, content, files, gamification, integrations, reports, sales, settings, support, and users. cademi --help lists the operations and sandbox groups with the core commands, next to auth, api, listen, and the other built-in commands.

Each operation's operationId starts with a resource, such as products, modules, or credentials, and each resource belongs to one domain. The command starts with that domain path. The rest of the operationId follows: each dot-separated segment becomes a word, underscores become hyphens, and the last segment is the verb.

operationIdCommand
products.listcademi content products list
modules.listcademi content products modules list <product_id>
credentials.current_policiescademi integrations credentials current-policies
products.access_schedules.rules.updatecademi content products access-schedules rules update <product_id> <access_schedule_id> <release_rule_id>
users.createcademi users create

Two operations have their own name: products.publications.create is cademi content products publish-all <product_id>, and modules.publications.create is cademi content products modules publish-all <product_id> <module_id>. Both publish the content below them, including copies in replicated accounts.

The command name comes from the operationId, not from the path: modules.list is GET /products/{product_id}/modules. In the API reference, the last segment of each operation page's URL is its operationId.

The paths without a domain, such as cademi products list, still run with the same arguments and flags. They are hidden from --help and from cademi commands, which show only the domain paths.

cademi --help lists the core commands and the domains, and cademi <domain> --help lists the groups and commands below it. The help of an operation command starts with its usage, then shows its description, the API route, the required permission, the path parameters, the body fields, its flags, and related commands:

cademi content products get --help
USAGE
  cademi content products get <product_id> [flags]
  cademi content products get --help

Retrieves a product by its public ID.

The `offer` object is included only when the credentials have the `products.read_offer` permission.

The response includes an `ETag` representing the current revision. Send this value in the `If-Match` header when updating the product to avoid overwriting a newer version.

API: GET /api/v3/products/{product_id}
Permission: products.read
  <product_id>: Public ID of the product, prefixed with `prd_`.

FLAGS
  ...

RELATED COMMANDS
  cademi content showcases copies|create|delete|get|list|order|products|update ...
    Organize products in showcases and showcase groups
  ...

AUTOMATION GUIDE
  cademi guide --help
    Output, body merging, retries, exit codes and reorder recipes.

When any one of several permissions is enough, the Permission: line joins them with or, as in Permission: reports.read or rankings.read for cademi reports rankings list. A body field that the API deprecated is marked deprecated after its type.

The event stream connection (cademi integrations event-streams events get) is the only operation that does not run as a regular command: use cademi listen.

Finding commands

cademi commands lists every command in one table: the commands generated from the API, with their route, and the built-in commands, with - as the route. Built-in commands include auth, api, listen, config, skills, and mcp; cademi commands --builtin lists all of them. Pass a prefix to list the groups and commands below it:

cademi commands content products modules
GROUP                                          SUMMARY
cademi content products modules                Manage a product's modules and module groups
cademi content products modules content        Inspect and order a module's direct children
cademi content products modules content order  Reorder module contents
cademi content products modules copies         Duplicate a module

COMMAND                                               ROUTE                                                                SUMMARY
cademi content products modules content list          GET /api/v3/products/{product_id}/modules/{module_id}/content        List module contents
cademi content products modules content order update  PUT /api/v3/products/{product_id}/modules/{module_id}/content/order  Reorder module contents
cademi content products modules copies create         POST /api/v3/products/{product_id}/modules/{module_id}/copies        Duplicate a module
cademi content products modules create                POST /api/v3/products/{product_id}/modules                           Create a module
cademi content products modules delete                DELETE /api/v3/products/{product_id}/modules/{module_id}             Delete a module
cademi content products modules get                   GET /api/v3/products/{product_id}/modules/{module_id}                Retrieve a module
cademi content products modules list                  GET /api/v3/products/{product_id}/modules                            List modules
cademi content products modules publish-all           POST /api/v3/products/{product_id}/modules/{module_id}/publications  Publish a module
cademi content products modules update                PATCH /api/v3/products/{product_id}/modules/{module_id}              Update a module
9 commands. Use --json for arguments, flags and permissions.

A prefix can also be a path without a domain: cademi commands products lists the cademi content products commands. A prefix that matches no command fails with exit code 2.

--generated lists only the commands generated from the API, and --builtin only the built-in commands. --builtin cannot be combined with --generated or --groups.

Browsing by group

--groups lists only the groups directly below the prefix, each with a summary, instead of commands. Without a prefix, it lists the domains and the core groups. Start with the top level and narrow the prefix one level at a time:

cademi commands --groups --brief --json
cademi commands content products --groups --brief --json
cademi commands content products access-schedules --json

The JSON catalog

With --json, -o yaml, or --jq, the command describes the CLI in one document, so a script or an agent does not need to run --help on each command:

FieldContent
cli_version, api_releaseThe CLI version and the API release it was built for.
global_flagsThe flags every command accepts.
flag_setsFlags shared by many commands, grouped in named sets: output, output-basic, body, idempotency, async, and confirm. Each set is described once here, and commands refer to it by name.
commands[]One entry per command: command, summary, args (positional arguments, in order), arguments (each argument with required, variadic, description, and schema), flag_constraints (output formats a flag requires), operation_id, method, path, permissions (one entry per permission), permissions_any_of (groups of permissions of which any one is enough), legacy_paths (the paths without a domain that still run), description, body_fields (each field with deprecated: true when the API deprecated it), body_required, related_settings (settings that affect the command, with the command that inspects them), manual_checks (conditional permissions), deprecated, flag_sets (the sets the command accepts), and flags (its other flags, with name, type, default, description, allowed values, whether it is required, and the flags each one conflicts with).
groups[]One entry per group: command, summary, description, related, related_settings, and examples.

Built-in commands have no operation_id, method, path, or permissions, and fields without a value are left out. The entry for cademi content products delete, with the long description shortened:

cademi commands content products delete --json --jq '.commands[0]'
{
  "command": "cademi content products delete",
  "summary": "Delete a product",
  "args": [
    "product_id"
  ],
  "arguments": [
    {
      "name": "product_id",
      "required": true,
      "variadic": false,
      "description": "Public ID of the product, prefixed with `prd_`.",
      "schema": {
        "example": "prd_42",
        "type": "string"
      }
    }
  ],
  "flag_constraints": [
    {
      "flag": "json",
      "allowed_values": {
        "output": [
          "json"
        ]
      }
    }
  ],
  "operation_id": "products.delete",
  "method": "DELETE",
  "path": "/api/v3/products/{product_id}",
  "permissions": [
    "products.delete"
  ],
  "legacy_paths": [
    "cademi products delete"
  ],
  "description": "Moves the product to the trash, together with its modules, its lessons, and its copies in replicated accounts. ...",
  "flag_sets": [
    "output",
    "idempotency",
    "confirm"
  ]
}

--brief keeps only command, summary, args, method, and path for each command, without flags or permissions. Combined with --groups, it gives a compact index of the domains.

--jq filters the document. For example, to list every delete command of the access schedules group:

cademi commands content products access-schedules --json --jq '.commands[] | select(.method == "DELETE") | .command'
cademi content products access-schedules delete
cademi content products access-schedules rules delete

Request body schemas

--schema adds the full request body of each command, as declared in the API contract, and the schemas it references under components: field descriptions, types, enums, limits, nullability, and nested properties. The CLI reads the contract built into it and makes no API request. Output is JSON unless you pass -o yaml. --schema cannot be combined with --brief or --groups.

cademi commands users update --schema --json
cademi commands content products update --schema --json --jq '.commands[0].request_body'

Automation guides

cademi guide prints short reference guides about the CLI's behavior, for scripts and agents. They are built into the CLI and do not contact the API. Read a topic with cademi guide <topic> --help:

TopicContent
errorsExit codes, error envelopes, and the results of asynchronous operations.
inputJSON bodies, field types, and the order in which --data, -f, and -F are merged.
outputPagination, JSON, --jq, and what goes to standard output and standard error.
reorderingHow to collect complete ID lists, check revisions, and submit a new order.
retriesIdempotency keys across automatic retries and separate runs.

Skills and MCP for agents

cademi skills install installs the cademi-cli skill: instructions and a command reference that teach coding agents such as Claude Code, Codex, and Cursor to use the CLI. The skill is built into the CLI and matches its version, so the install downloads nothing. cademi skills status shows where the skill is installed and whether it is current, and cademi skills uninstall removes it.

cademi mcp install <client> adds the Cademí MCP server to an assistant instead, so the assistant works with the API through MCP tools. See AI coding assistants.

Path and query parameters

Path parameters are positional arguments, in the order they appear in the path. Query parameters are flags named after the parameter, with underscores replaced by hyphens:

cademi content products get prd_12
cademi content products list --status published --showcase-id shw_01J8Z1... --limit 50
cademi users list --tag-id tag_01,tag_02

Array parameters (tag_id[]) accept a comma-separated list or a repeated flag. Enum parameters list their allowed values in --help and complete them in the shell.

A query parameter that the operation requires is marked (required) in --help and has required: true in cademi commands --json. Without it, the command exits with code 2 and nothing is sent to the API:

cademi reports activity list --from 2026-09-01 --to 2026-09-30
cademi account usage --period 30d

See Pagination and filtering for the filters and sort orders of each collection.

Request bodies

Commands for operations that take a body accept three flags, which you can combine:

FlagValue
-d, --dataA JSON body: a literal, @file.json, or @- to read standard input.
-f, --field key=valueA string field.
-F, --typed-field key=valueA typed field: true, false, null, a number, a JSON value starting with {, [, or ", or @file to read a file's content as a string.

-f and -F are applied on top of the object given with --data, and repeat for each field. Nested fields use dots (a.b=v) or brackets (a[b]=v). key[]=value appends to an array. Arrays of objects need --data.

cademi users create -f name="Ana Souza" -f [email protected] -F send_credentials=false

cademi integrations webhooks create -f url=https://example.com/hooks/cademi \
  -f 'event_types[]=user.created' -f 'event_types[]=enrollment.created'

cademi content products certificate template update prd_12 -F enabled=true \
  -f criteria.kind=progress_percent -F criteria.percent=80

cademi content products create -d @product.json

Quote fields that contain [] so your shell does not expand them. When an operation requires a body and you pass no body flag, the command fails with exit code 2 and asks you to use -f, -F, or --data.

Validation before sending

Each command checks the request against the API contract built into the CLI, for the API release that cademi version shows. A body field that the operation does not accept stops the command with exit code 2, and nothing is sent to the API. The check covers fields given with -f, -F, and --data, including the keys of nested objects when the contract lists them. The message names each unknown field with its JSON path ($ is the top level of the body) and lists the fields the operation accepts:

cademi users create -f name="Ana Souza" -f [email protected] -f nickname=ana
Error: unknown body field "nickname" at $ for POST /users; accepted: custom_fields, document, email, external_id, name, phone, send_credentials, tags

For a nested field, the path points to the object that contains it:

Error: unknown body field "min_score" at $.criteria for PUT /products/{product_id}/certificate-template; accepted: criteria, enabled, fields, layout, single_issue, texts (see the resource command's --help for nested fields)

The items of arrays, objects whose keys the contract does not list, and a --data body that is not a JSON object are not checked locally: the API validates them. With --json, -o json, or --jq, the message prints as a cli_error (Exit codes). To see every field an operation accepts, use --schema. To send a field that is newer than the CLI's API release, use cademi api --skip-validation or update the CLI.

Output

Commands print the data of the response. Status messages, warnings, and progress go to standard error, so standard output carries only data.

FlagEffect
(none)Lists of objects print as a table in a terminal. Everything else, and any output sent to a pipe or a file, prints as JSON.
--jsonJSON. Same as -o json.
-o, --outputjson, table, or yaml.
--jq <expression>Filters the JSON output with a jq expression. The filter is built in, so jq does not need to be installed. Strings print without quotes.
--rawThe full response envelope (data, page, and so on) instead of data.
-i, --includeThe HTTP status and the response headers, such as ETag, X-Request-Id, and X-Cademi-Release, printed to standard output before the body.
cademi users list --jq '.[].email'
cademi content products get prd_12 -o yaml
cademi content products list --raw --jq '.page.next_cursor'

Error messages from the API show the error code, the message, each item of details, a hint for common codes, and the request_id. Each item of details shows its field and message, followed in parentheses by its code and its reason, each one only when the API returns it, such as (reason: has_memberships). The message language follows CADEMI_LANG or your system locale (Environment and diagnostics). With --json, -o json, or --jq, errors print to standard error as JSON, including errors in flags and arguments (Exit codes).

Pagination

A list command returns one page. --limit sets the page size, and --cursor requests the page after the one that returned page.next_cursor. Pass the cursor with the same filters and sort order, and stop when next_cursor is empty or null. Cursors are opaque: do not build or change them.

Commands for collections paginated with a cursor also accept --all. It follows next_cursor until the last page and prints every item as a single array. --limit still sets the size of each request:

cademi content products list --status published --all
cademi content products list --all --limit 200 --jq '.[].id'
cademi content products content list prd_12 --all
  • With --cursor, --all starts from that page.
  • --all cannot be combined with --raw or --include: the command exits with code 2 before any request.
  • The items are collected in memory. If any page fails, nothing is printed to standard output.
  • --jq runs once, on the complete array.
  • --all returns only the items the current credentials can access.

Writes, retries, and idempotency

Every POST, PATCH, PUT, and DELETE carries an Idempotency-Key header, a new UUIDv7 per command. The CLI retries a request, with the same key and body, after a network error, a 500, 502, 503, or 504, a 409 idempotency_in_progress or 409 result_uncertain, or a 429. Other 5xx statuses are not retried. It makes up to 3 retries, waiting as long as the API indicates in Retry-After, or with exponential backoff when the API gives no wait time. Because the key stays the same, a retry never duplicates an effect.

Some of these responses stop the command at the first attempt:

  • A 429 that asks for a wait longer than 60 seconds, or a 429 too_many_streams, exits with code 7.
  • A 503 that returns an API error, such as storage_unavailable, without a Retry-After header exits with code 8. A 503 whose body is not an API error, such as one from a proxy, is retried.

A 500, 502, 503, or 504 that asks for a wait longer than 60 seconds is retried after 60 seconds.

To change these limits, set CADEMI_MAX_RETRIES to the number of retries (0 turns retries off) and CADEMI_MAX_RETRY_WAIT to the longest wait, such as 10s (Environment variables).

The key changes with every run of a command. When a write fails after the CLI sent it, including a network error without a response or a cancellation, the error shows the request and the key it used:

  request: POST /api/v3/users
  idempotency_key: "0192f3a1-7c2e-7b4d-9e8f-3a5b6c7d8e9f"
  To repeat this same request, pass this key with --idempotency-key and keep the same body.

With --json, -o json, or --jq, the same information is in the request object of the JSON error (Exit codes). To repeat the write, run the same command with the same body and pass the key with --idempotency-key. A failed attempt does not prove that the API did not apply the write, and the key makes the repeat safe. Use a new key when the body changes. An error raised before the request is sent, such as a validation error, has no key.

You can also choose the key yourself before the first run, so you can repeat the write even when the error output is lost. A key has 1 to 128 characters: letters, digits, ., _, :, and -.

cademi users create --idempotency-key import-ana-2026-09-25 -f name="Ana Souza" -f [email protected]

If the API already processed that key with the same body on the same route, it returns the stored result and the CLI warns Idempotent replay. Keys are scoped to the credential and remembered for 48 hours. See Asynchronous operations, batches, and idempotency.

Conditional updates

Operations that accept If-Match have an --if-match flag. Read the resource with -i to get its ETag, then send it with the update:

cademi content products get prd_12 -i
cademi content products update prd_12 -f name="New name" --if-match 'W/"product:prd_12:..."'

If the resource changed after you read it, the API returns 412 revision_mismatch and the command exits with code 6: read the resource again and retry with the new ETag.

Asynchronous operations

Operations that answer 202 return an operation. By default the command prints it and tells you how to follow it:

cademi content products publish-all prd_12
cademi operations wait op_01J8Z3ZQ4H8K2M0T1S9P7YQF5C

With --wait, the command waits for the operation to finish, prints its progress to standard error whenever the status or the item counts change, and then prints the final operation. --wait-timeout 10m limits the wait.

cademi content products publish-all prd_12 --wait

Some operations answer 202 with a resource instead, such as an export or a processing attempt, and its operation_id points to the operation that does the work: cademi files exports create, cademi users imports processing-attempts create, cademi sales events processing-attempts create, and cademi automations diamonds memberships processing-attempts create. On these commands, --wait waits for that operation. Standard error shows the resource ID and the operation, and standard output carries the final operation, not the resource. When operation_id is null, --wait prints the resource without waiting.

The first import of an account is released by the Cademí team. Until then, cademi users imports processing-attempts create with mode set to initial (the default) exits with code 6: the API answers 409 feature_disabled with the reason first_import_requires_release. Retrying does not help. Contact support to release the first import; later imports are processed normally.

cademi operations wait polls every 2 seconds for the first 30 seconds and every 10 seconds after that. --timeout limits the wait.

Final statusExit code
succeeded0
partially_succeeded0, with a warning that points to cademi operations items <operation_id>
failed, canceled1

When a failed or canceled operation returns an error, the message on standard error shows its field, message, code, and reason, each one only when the API returns it. The same message appears with --wait.

operation op_1 failed: file: ... (import_column_missing, reason: email)

A wait that reaches its time limit also exits with 1, and the operation keeps running. cademi operations items, cademi operations attempts create, and cademi operations update inspect, resume, and cancel operations as described in Asynchronous operations, batches, and idempotency.

Deleting

Delete commands ask for confirmation. When the profile is a production profile, the question starts with [production]. Answer y or yes to proceed (s and sim are also accepted). Any other answer cancels the command with exit code 130.

cademi content products delete prd_12
cademi content products delete prd_12 --yes

--yes (-y) skips the question. Without a terminal, a delete command fails with exit code 2 unless you pass --yes.

Global flags

FlagEffect
-p, --profile <name>Use this profile for the command.
--base-url <url>Use this API URL instead of the profile's.
--debugLog each HTTP request to standard error: method, URL, status, duration, and request_id. Secrets are never logged.
-h, --helpShow the help of the command.

On this page