Use the custdctl Client
custdctl is the command line client for Custd. It is a single binary: no Go
toolchain, no repository, no runtime to install. It signs in as your tenant
administrator and operates your own tenant — the same public contract the
released SDK uses.
Before you start
You need:
- a Custd tenant you administer, and
- the client credentials your tenant administrator created for the CLI.
If you do not have a CLI client yet, ask your tenant administrator to create
one in Admin → Credentials. Choose the CLI login client purpose: it is
a public client with no secret, and the page prints the exact config init
command to run. Copy it as it is.
Install the client
Download the release asset for your platform from the Custd downloads repository, then verify the checksum before you run it.
| Platform | Asset |
|---|---|
| Windows 64-bit | custdctl_<version>_windows_amd64.exe |
| macOS Apple Silicon | custdctl_<version>_darwin_arm64 |
| Linux 64-bit ARM | custdctl_<version>_linux_arm64 |
| Linux 64-bit x86 | custdctl_<version>_linux_amd64 |
Windows
- Download
custdctl_<version>_windows_amd64.exe. - Verify it against
SHA256SUMS— on Windows:certutil -hashfile custdctl_<version>_windows_amd64.exe SHA256. - Move the binary to a folder on your
PATH, for exampleC:\Program Files\Custd\. Rename it tocustdctl.exeif you like; the.exesuffix is the only difference. - Open a new terminal so the new
PATHentry is visible.
macOS
- Download
custdctl_<version>_darwin_arm64. macOS requires Apple Silicon; Intel Macs are not supported. - Verify it against the published checksum for that one asset:
shasum -a 256 custdctl_<version>_darwin_arm64and compare the value with the matching line inSHA256SUMS. - Move the binary into
/usr/local/binand make it executable:sudo mv custdctl_<version>_darwin_arm64 /usr/local/bin/custdctl && sudo chmod +x /usr/local/bin/custdctl. - If macOS blocks the first run because the binary is not notarised, approve it
once in System Settings → Privacy & Security, or clear the quarantine
attribute with
xattr -d com.apple.quarantine /usr/local/bin/custdctl.
Linux
- Download
custdctl_<version>_linux_amd64(orlinux_arm64). - Verify it against the published checksum for that one asset:
sha256sum custdctl_<version>_linux_amd64and compare the value with the matching line inSHA256SUMS. - Move the binary into
/usr/local/binand make it executable:sudo mv custdctl_<version>_linux_amd64 /usr/local/bin/custdctl && sudo chmod +x /usr/local/bin/custdctl.
Check the install at any time:
custdctl version
It prints the build facts of the binary: the version, the commit it was built
from, the build time and the Go version. The commit is what identifies a
build — quote it in a support message. The same facts appear in
custdctl system about --json.
Point the client at your tenant
Run the config init line your administrator gave you. It carries your API
URL, your identity provider issuer, your client id, your audience and your
scopes, and the profile name the client will use — which is your client id:
custdctl config init --profile "acme-cli" --api-url "https://custd.com" --issuer-url "https://auth.custd.com/" --client-id "acme-cli" --audience "custd" --scope "openid profile offline_access admin producers.provision"
The issuer must exactly match the server's discovery metadata, including the
trailing slash. The public Custd issuer is https://auth.custd.com/.
The public API base is https://custd.com, as configured by the production chart.
Copy it as it is. If you would rather set it up yourself, custdctl config init --help lists every flag.
The client stores this profile and the token it obtains on your machine, readable only by your own account:
| Platform | Location |
|---|---|
| Windows | %AppData%\custd\config.yaml and %AppData%\custd\tokens.json |
| macOS and Linux | $XDG_CONFIG_HOME/custd/, or ~/.config/custd/, holding config.yaml and tokens.json |
custdctl config path prints the path the client is using.
Sign in
custdctl login --profile acme-cli
The client opens your browser, you sign in as your tenant administrator, and the browser hands the token back to the client. If no browser opens, the client prints a URL to paste into any browser yourself.
If your machine has no browser — a server, a container, a locked-down desktop — use the device-code flow instead:
custdctl login --profile acme-cli --method device
It prints a code and a URL. Open the URL on any device, enter the code, and the client receives the token.
Check who you are signed in as:
custdctl account
Sign out again with custdctl logout --profile acme-cli.
Find the command you need
custdctl --help lists every command, grouped into Your tenant and
Platform operator. The grouping is the authority the command needs: a
command under Platform operator is refused for a tenant administrator.
custdctl commands
prints the same inventory for your tenant, with a description beside every command, so you can search for the verb you want:
custdctl commands | grep -i rotate
Every command explains itself:
custdctl sites rotate-write-key --help
custdctl help sites rotate-write-key
Both print the same block: what the command does, which flags it requires, every
flag with a description, and one working example. A wrong flag is reported with
the flag that was not understood and the exit code 2.
Get output you can pipe
Every command that produces data emits exactly one JSON document, so it pipes
straight into jq:
custdctl account --json | jq -r '.email'
custdctl usage me --json | jq '.data.rows[] | {meter: .meterSlug, quantity}'
The request identifier travels inside the document, so you can quote it in a support message.
When something goes wrong
These answer the first questions of any support conversation:
custdctl diagnose
custdctl system about --json
custdctl system diagnostics capture --tenant-scope --output ./custd-evidence
custdctl diagnose is the one that reports reachability: it separates a
network problem from an authorization one (api_reachable=true but
api_authorized=false means the credential is the problem, not the network).
system about --json reports the build the binary was made from.
system diagnostics capture --tenant-scope writes a bounded, redacted evidence
bundle for your tenant.
The system-wide capture needs platform authority and is refused for a tenant administrator. That refusal is intentional: a tenant cannot read another tenant's state.
Send the two outputs to your Custd contact. The evidence bundle contains no event payloads, no credentials and no other tenant's data.
What the client cannot do
The client is a thin shell over the same contract your SDK uses. It does not grant authority: a command is refused when your account lacks the role, and the CLI has no way around that. Anything that needs platform authority — operating the platform, running maintenance commands, reading another tenant — is out of scope for a tenant administrator by design.