Metadata-Version: 2.4
Name: daknode-cli
Version: 0.3.2
Summary: DakNode's email API from a terminal. JSON to stdout by default.
Project-URL: Homepage, https://daknode.com
Project-URL: Documentation, https://daknode.com/developers
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Requires-Dist: daknode<0.4,>=0.3.7

# DakNode CLI

The API from a terminal. JSON to stdout by default, because the caller is as
likely to be a script as a person.

## Install

```bash
pipx install daknode-cli      # or: pip install daknode-cli
```

Get an API key with the two-request signup at <https://daknode.com/developers>.

```bash
export DAKNODE_API_KEY=…

daknode inboxes create --alias support [--display-name Support] [--domain-id …]
daknode inboxes list --limit 10 [--cursor …]
daknode inboxes get <inbox_id>
daknode inboxes rename <inbox_id> --display-name Support
daknode inboxes delete <inbox_id> --dry-run
daknode inboxes delete <inbox_id> --yes
daknode threads list --inbox-id … --limit 10
daknode threads get <thread_id>
daknode messages list --inbox-id …
daknode messages get <message_id>
daknode search --query "invoice from stripe"
daknode send --inbox-id … --to … --subject … --body … --request-id … [--thread-id …]
```

From a repository checkout, `python -m cli.main` runs the same commands.

`--format table` for reading. `--dry-run` on `send` prints the request and
exits without sending it — a command that emails a real person deserves a way
to be inspected first.

Inbox deletion **deactivates, not erases**. It requires `--yes`; its `--dry-run`
does not contact the API. Use `--request-id` for real sends: choose a stable,
non-secret identifier and reuse it only when retrying the identical send.
The CLI never retries sends automatically. API errors, including parsed validation
errors, exit nonzero. Use identifiers appropriate for your own retention policy.

## Exit codes

| | |
| --- | --- |
| `0` | success |
| `2` | the API refused the request |
| `3` | the API could not be reached |
| `4` | `DAKNODE_API_KEY` is not set |

`2` and `3` are separate on purpose: a script retrying a network failure must
not retry a `422` forever.

## Two deliberate constraints

**No credential flag.** The key comes from the environment only. argv is visible
to every process through `ps`, and shells record it in history. A test walks the
parser and fails if any flag name contains `key` or `token`.

**No third-party dependency.** `argparse` from the standard library, plus the
first-party generated SDK. Click and Typer are nicer to write against — and one
day before this was written, installing `mcp` silently upgraded a pinned
`pydantic` and changed the API's published OpenAPI output. Every dependency here
is another chance to move a pin production depends on. A test enumerates the
imports and fails on anything new.

**`send --thread-id` replies into a conversation**; without it the message opens
a new one in the recipient's client.
