# How the JSON Output from wacli Commands Is Structured

> Understand the wacli JSON output structure. Learn how success status data and errors are presented in a standardized envelope for clear command results.

- Repository: [Peter Steinberger/wacli](https://github.com/steipete/wacli)
- Tags: api-reference
- Published: 2026-04-17

---

**Every wacli command that runs with the `--json` flag returns a standardized envelope containing a `success` boolean, a `data` payload, and an optional `error` string.**

The `steipete/wacli` repository is a command-line interface for interacting with WhatsApp. When you need to parse command results programmatically, the tool provides a predictable JSON output structure that unifies success and error responses under a common schema.

## The Standard JSON Envelope

All JSON serialization logic resides in [`internal/out/out.go`](https://github.com/steipete/wacli/blob/main/internal/out/out.go). The helper defines a rigid `envelope` struct that wraps every command response:

```go
type envelope struct {
    Success bool        `json:"success"`          // true for a successful command, false otherwise
    Data    interface{} `json:"data"`             // the command‑specific result (any JSON‑serialisable value)
    Error   *string     `json:"error,omitempty"`  // populated only when Success is false
}

```

The `WriteJSON` function marshals this struct using `json.Marshal` and writes the result to the supplied `io.Writer` (typically `os.Stdout`). This ensures that every command, regardless of its internal return type, emits a consistent JSON output format.

### Success Response Format

When a command completes without error, the envelope contains `success: true` and places the command-specific result inside the `data` field:

```json
{
  "success": true,
  "data": { ...command-specific fields... }
}

```

The `data` payload varies by command and can be an object, array, or primitive value.

### Error Response Format

If a command fails, the helper invokes `WriteError` (defined in [`internal/out/out.go`](https://github.com/steipete/wacli/blob/main/internal/out/out.go) at line 24) to produce:

```json
{
  "success": false,
  "data": null,
  "error": "human-readable error message"
}

```

The `error` string provides a direct explanation suitable for logging or displaying to users.

## Command-Specific Data Payloads

Each subcommand constructs its own Go value and passes it to `out.WriteJSON`. The shape of the `data` field depends entirely on the command being executed.

### Message Sending Commands

**`wacli send`** and **`wacli send-file`** return confirmation objects containing the target JID and message ID.

In [`cmd/wacli/send.go`](https://github.com/steipete/wacli/blob/main/cmd/wacli/send.go) (lines 75–82), the output looks like:

```json
{
  "jid": "12345@s.whatsapp.net",
  "msgId": "ABCD1234"
}

```

For file transfers in [`cmd/wacli/send_file.go`](https://github.com/steipete/wacli/blob/main/cmd/wacli/send_file.go) (lines 55–62), the payload includes the filename:

```json
{
  "jid": "12345@s.whatsapp.net",
  "msgId": "EFGH5678",
  "file": "photo.jpg"
}

```

### Data Retrieval Commands

**`wacli messages`** outputs an array of message objects. The implementation in [`cmd/wacli/messages.go`](https://github.com/steipete/wacli/blob/main/cmd/wacli/messages.go) (lines 75–78) returns a slice where each element contains metadata such as `id`, `timestamp`, and `fromMe`.

**`wacli sync`** provides a summary object. In [`cmd/wacli/sync.go`](https://github.com/steipete/wacli/blob/main/cmd/wacli/sync.go) (lines 62–66), the JSON contains counts of processed items:

```json
{
  "messagesStored": 1234,
  "contactsStored": 56
}

```

### Diagnostic Commands

**`wacli doctor`** emits a configuration report. The code in [`cmd/wacli/doctor.go`](https://github.com/steipete/wacli/blob/main/cmd/wacli/doctor.go) (lines 80–87) produces an object detailing the runtime environment:

```json
{
  "store_dir": "/home/user/.wacli",
  "lock_held": false
}

```

## Enabling JSON Output with the --json Flag

The CLI root command defines the global flag in [`cmd/wacli/root.go`](https://github.com/steipete/wacli/blob/main/cmd/wacli/root.go) (lines 35–40). The persistent boolean flag `--json` (aliased as `-json`) propagates to all subcommands. When this flag is detected, commands skip human-readable formatting and invoke the `out.WriteJSON` helper instead of printing plain text.

## Practical Examples

The following terminal commands demonstrate the wacli JSON output structure in action.

Sending a text message with JSON formatting:

```bash
$ wacli --json send 12345@s.whatsapp.net "Hello"
{
  "success": true,
  "data": {
    "jid": "12345@s.whatsapp.net",
    "msgId": "XyZ123"
  }
}

```

Retrieving the last two messages from a chat:

```bash
$ wacli --json messages 12345@s.whatsapp.net --limit 2
{
  "success": true,
  "data": [
    { "id": "AB12", "timestamp": 1681234567, "fromMe": true, "text": "Hi!" },
    { "id": "CD34", "timestamp": 1681234599, "fromMe": false, "text": "How are you?" }
  ]
}

```

Handling an invalid JID error:

```bash
$ wacli --json send unknown_jid "test"
{
  "success": false,
  "data": null,
  "error": "failed to resolve JID: unknown_jid"
}

```

## Summary

- The `wacli` CLI provides a **standard JSON envelope** defined in [`internal/out/out.go`](https://github.com/steipete/wacli/blob/main/internal/out/out.go) that wraps every response with `success`, `data`, and `error` fields.
- The **`--json` flag** (defined in [`cmd/wacli/root.go`](https://github.com/steipete/wacli/blob/main/cmd/wacli/root.go)) triggers machine-readable output instead of human-readable text.
- The **`data` payload** varies by command, ranging from single objects (send confirmations) to arrays (message lists) and summary statistics (sync results).
- Error responses always set `success: false`, null the `data` field, and populate the `error` string with a descriptive message.

## Frequently Asked Questions

### What is the root structure of every wacli JSON response?

Every response is wrapped in a standard envelope containing three fields: `success` (boolean), `data` (any JSON value or null), and `error` (string or omitted). This structure is enforced by the `envelope` struct in [`internal/out/out.go`](https://github.com/steipete/wacli/blob/main/internal/out/out.go) and ensures consistent parsing across all commands.

### How do I enable JSON output instead of plain text?

Pass the global `--json` or `-json` flag to any wacli command. This flag is defined as a persistent boolean in [`cmd/wacli/root.go`](https://github.com/steipete/wacli/blob/main/cmd/wacli/root.go) and propagates to all subcommands. When enabled, commands skip human-readable formatting and emit the standard JSON envelope instead.

### Why does the data field change shape between commands?

The `data` field contains command-specific results because each subcommand constructs its own Go value and passes it to `out.WriteJSON`. For example, `wacli send` returns an object with `jid` and `msgId`, while `wacli messages` returns an array of message objects. The envelope structure remains constant, but the payload inside `data` reflects the operation performed.

### Where is the error message located when a command fails?

When a command fails, the error message appears in the `error` field of the JSON envelope, while `success` is set to `false` and `data` is `null`. This is generated by the `WriteError` helper in [`internal/out/out.go`](https://github.com/steipete/wacli/blob/main/internal/out/out.go) (line 24), ensuring that error responses follow the same envelope structure as successful ones.