Command-line interface for the Two merchant APIs. Generated from the public OpenAPI specs, so every endpoint is exposed as a subcommand.
brew install two-inc/tap/twoctlDownload from releases and place on $PATH.
go install github.com/two-inc/twoctl-cli/cmd/twoctl@latesttwoctl ships completions for bash, zsh, fish, and PowerShell. The binary
generates them on demand via twoctl completion <shell>.
Linux:
twoctl completion bash | sudo tee /etc/bash_completion.d/twoctl > /dev/nullmacOS (with bash-completion@2 from Homebrew):
twoctl completion bash > "$(brew --prefix)/etc/bash_completion.d/twoctl"If you don't have write access to a system path, source the completion in your
~/.bashrc:
echo 'source <(twoctl completion bash)' >> ~/.bashrc# one-shot (re-run on shell start):
echo 'source <(twoctl completion zsh)' >> ~/.zshrc
# or persist to fpath:
twoctl completion zsh > "${fpath[1]}/_twoctl"If compinit hasn't been initialised in your ~/.zshrc, add:
autoload -Uz compinit && compinitbefore the completion source line.
twoctl completion fish | source # current shell
twoctl completion fish > ~/.config/fish/completions/twoctl.fish # persistenttwoctl completion powershell | Out-String | Invoke-Expression # current session
twoctl completion powershell >> $PROFILE # persistentAfter installing, open a new shell. Tab-completion works on subcommands, flags, and any flag value that has a known enum in the OpenAPI spec (country codes, currencies, statuses).
twoctl uses named contexts (kubectl-style). Each context bundles a base URL
and an OS-keychain entry holding the API key, so you can switch between
sandbox, prod, staging, cyber, perf, release, or any custom environment
without copy-pasting keys.
twoctl ctx set sandbox --url https://api.sandbox.two.inc --key secret_test_...
twoctl ctx set prod --url https://api.two.inc --key secret_prod_...
twoctl ctx list # show all contexts, * marks current
twoctl ctx use prod # switch the default
twoctl ctx current # print the current name
twoctl ctx delete temp # remove + clear keychain entryPer-invocation overrides (no switching):
twoctl --env prod company company-search --country NO --q two
twoctl --context cyber checkout get-order --order-id abc # kubectl-style alias
twoctl --url http://localhost:8080 --api-key secret_test_x ...For built-in env names (prod, sandbox, staging, cyber, perf,
release) twoctl knows the URL. For any other name it falls back to
https://api.<name>.two.inc; override with --url.
API key resolution order (highest precedence first):
--api-keyflagTWO_API_KEYenv var- OS keychain entry for the active context
Keys are obtained from the Two merchant portal.
The command tree is resource-first: twoctl <resource> <action> [flags].
Every operation across every Two API is classified into a (resource, action) pair derived from the URL path + operationId, then registered
under the resource. Non-CRUD actions like cancel, refund, fulfill,
search, notify surface as first-class verbs alongside get/create/
edit/delete.
twoctl order get --order-id abc-123 # GET /v1/order/{order_id}
twoctl order create --file order.json # POST /v1/order
twoctl order cancel --order-id abc-123 # POST /v1/order/{id}/cancel
twoctl order fulfill --order-id abc-123 --file f.json
twoctl order refund --order-id abc-123 --file r.json
twoctl order edit --order-id abc-123 --file patch.json
twoctl company search --q "two" --country NO
twoctl billing-account get --billing-account-id ba_xxx
twoctl explain order create # JSON schema for the operation
twoctl api-resources --resource order # catalog filtered by resource
twoctl api-resources --action cancel # everything that's a "cancel"Run twoctl <resource> on its own to see every action available. Each leaf
command's --help lists flags derived from the OpenAPI operation;
request bodies go via --file path.json or --data '{...}'.
Top-level non-resource commands:
twoctl |
Purpose |
|---|---|
config set-context / use-context / get-contexts / current-context / delete-context |
Manage contexts (kubectl naming) |
auth login / logout / whoami |
Store the API key in the OS keychain |
explain <resource> <action> |
JSON schema for an operation, no network call |
api-resources |
JSON catalog of every operation, for agent discovery |
version |
Print version and build info |
upgrade |
Self-upgrade from the latest GitHub release |
--context / --env (alias) |
Per-invocation context override |
twoctl is designed to be driven by both humans and LLM agents.
twoctl catalog [-a <api>]— emits a JSON catalogue of every operation (command, method, path, flags with kind/type/required, body status). Pipe this to an agent's planner so it can pick the right command without parsing--helptext.twoctl <api> <op> --describe— JSON view of one operation's full spec (parameters, request body schema, response schemas) without a network call.twoctl <api> <op> --dry-run— render the HTTP request that would be sent (URL, redacted headers, body presence) and exit. No credentials needed.- Output defaults to pretty JSON on stdout,
-o yamlfor YAML. - Errors are emitted as JSON on stderr with shape
{error, message, status, response}. Stdout stays clean for piping.
| Code | Meaning |
|---|---|
| 0 | success |
| 1 | generic error |
| 2 | usage / missing required input |
| 3 | authentication or authorisation (401/403) |
| 4 | not found (404) |
| 5 | rate limited (429) |
| 6 | server error (5xx) |
| 7 | network / transport failure |
twoctl checks for new releases at most once every 24 hours and prompts when one is available. The prompt offers:
yinstall nownnot now (default)sskip this version (won't ask again until the next release)
Direct controls:
twoctl upgrade # check + install
twoctl upgrade --check # only report, don't install
twoctl upgrade --reset-skips # forget every skipped version
twoctl upgrade --disable-autocheck # silence the prompt entirely
twoctl upgrade --enable-autocheck # turn it back on--no-upgrade-check is a per-run override for scripts. State lives in ~/.config/twoctl/state.json.
Every operation across all six merchant-facing specs surfaces as a twoctl <verb> <resource> command. The verbs are auto-derived from operationId
prefixes (get_/retrieve_/list_/search_, create_/make_/fulfill_/refund_/cancel_/...
etc.), with HTTP-method fall-back when no prefix matches. Run
twoctl api-resources for the full machine-readable catalog.
| Spec | Source |
|---|---|
| Checkout (Order) | checkout-api.yaml |
| Billing Account | billing-account-api.yaml |
| Repay | repay-api.yaml |
| Recourse | recourse-api.yaml |
| Company | company-api.yaml |
| Limits | limits-api.yaml |
The openapi/ specs are vendored from two-inc/docs.
When that source changes, a repository_dispatch event fires the regenerate.yml workflow,
which pulls fresh specs, runs codegen, and opens a PR.
To regenerate locally:
./scripts/codegen.sh
go build ./...This repository is generated from the OpenAPI specs in two-inc/docs.
Bug reports and PRs for the CLI itself (flags, output formatting, ergonomics) are welcome here.
For API behaviour or schema changes, please open an issue against two-inc/docs.
MIT - see LICENSE.