Skip to main content

JSON Output

All Grove CLI commands support --json flag for machine-readable output. Perfect for scripts and agent integrations.

Why Use JSON Output?

  • Scriptable - Parse with jq, Python, JavaScript, etc.
  • Reliable - Consistent structure, no parsing HTML/text
  • Machine-friendly - Easy to integrate with automation tools
  • Error handling - Structured error messages with exit codes

Command Reference

grove balance --json

Get account balance in JSON format.

Command:

grove balance --json

Output:

{
"balance": "4.99",
"token": "USDC",
"network": "base",
"address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"
}

Error:

{
"error": "Unauthorized: Invalid API key"
}

grove tip --json

Send a tip and get transaction details.

Command:

grove tip olshansky.info 0.01 --json

Output:

{
"success": true,
"destination": "olshansky.info",
"amount": "0.01",
"token": "USDC",
"network": "base",
"receiver": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"tx_hash": "0xabc123...",
"tx_url": "https://basescan.org/tx/0xabc123...",
"fee": "0.001",
"new_balance": "4.98"
}

Error:

{
"error": "Insufficient balance: have 0.00 USDC, need 0.01 USDC"
}

grove check --json

Check if destination is tippable.

Command:

grove check olshansky.info --json

Output (success):

{
"tippable": true,
"destination": "olshansky.info",
"receiver": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"method": "llms.txt"
}

Output (not tippable):

{
"tippable": false,
"destination": "example.com",
"error": "No tipping address found"
}

grove history --json

Get transaction history.

Command:

grove history --json --limit 5

Output:

{
"transactions": [
{
"date": "2024-01-15T14:30:00Z",
"type": "TIP",
"destination": "olshansky.info",
"amount": "-0.01",
"token": "USDC",
"balance_after": "4.99",
"tx_hash": "0xabc123..."
},
{
"date": "2024-01-14T10:00:00Z",
"type": "FUND",
"source": "Credit Card",
"amount": "+5.00",
"token": "USDC",
"balance_after": "5.00"
}
],
"count": 2
}

grove fund --json

Fund account via x402 protocol.

Command:

grove fund 5.00 --json

Output:

{
"success": true,
"amount": "5.00",
"token": "USDC",
"network": "base",
"tx_hash": "0xdef456...",
"tx_url": "https://basescan.org/tx/0xdef456...",
"new_balance": "5.00"
}

grove contact --json

Submit support request.

Command:

echo '{
"email": "user@example.com",
"message": "How do I...?",
"category": "question"
}' | grove contact --json

Output:

{
"success": true,
"message": "Support request submitted"
}

Scripting Examples

Bash + jq

Check balance before tipping:

#!/bin/bash
set -e

BALANCE=$(grove balance --json | jq -r '.balance')
REQUIRED="0.01"

if (( $(echo "$BALANCE < $REQUIRED" | bc -l) )); then
echo "Insufficient balance: $BALANCE USDC"
exit 1
fi

RESULT=$(grove tip olshansky.info $REQUIRED --yes --json)
TX_HASH=$(echo "$RESULT" | jq -r '.tx_hash')
echo "Tip sent! Transaction: $TX_HASH"

Python

Tip multiple creators:

#!/usr/bin/env python3
import subprocess
import json

def tip(destination, amount):
result = subprocess.run(
["grove", "tip", destination, str(amount), "--yes", "--json"],
capture_output=True,
text=True
)
return json.loads(result.stdout)

creators = [
("olshansky.info", 0.01),
("@olshansky", 0.05),
("example.substack.com", 0.10)
]

for dest, amt in creators:
try:
result = tip(dest, amt)
if result.get("success"):
print(f"✓ Tipped {dest}: {amt} USDC")
else:
print(f"✗ Failed to tip {dest}: {result.get('error')}")
except Exception as e:
print(f"✗ Error tipping {dest}: {e}")

JavaScript (Node.js)

Check if destinations are tippable:

const { exec } = require('child_process');
const util = require('util');
const execPromise = util.promisify(exec);

async function checkTippable(destination) {
const { stdout } = await execPromise(
`grove check ${destination} --json`
);
return JSON.parse(stdout);
}

const destinations = [
'olshansky.info',
'@olshansky',
'example.com'
];

(async () => {
for (const dest of destinations) {
const result = await checkTippable(dest);
console.log(`${dest}: ${result.tippable ? '✓' : '✗'}`);
}
})();

Error Handling

Exit Codes

The CLI uses standard exit codes:

CodeMeaning
0Success
1General error (API error, invalid input, etc.)
2Usage error (invalid command, missing arguments)

Example:

#!/bin/bash
set -e # Exit on error

grove tip olshansky.info 0.01 --yes --json

if [ $? -eq 0 ]; then
echo "Tip succeeded"
else
echo "Tip failed"
exit 1
fi

Error Response Format

All errors return JSON with an error field:

{
"error": "Human-readable error message",
"code": "ERROR_CODE",
"details": {}
}

Common error codes:

  • UNAUTHORIZED - Invalid API key
  • INSUFFICIENT_BALANCE - Not enough funds
  • INVALID_DESTINATION - Destination not tippable
  • NETWORK_ERROR - Connection failed
  • RATE_LIMIT - Too many requests

Parsing Tips

Using jq

Extract specific fields:

Get just the balance:

grove balance --json | jq -r '.balance'

Get multiple fields:

grove tip olshansky.info 0.01 --json | jq '{tx_hash, new_balance}'

Check for errors:

grove check example.com --json | jq -e '.tippable' || echo "Not tippable"

Conditional logic:

BALANCE=$(grove balance --json | jq -r '.balance')
if (( $(echo "$BALANCE >= 1.0" | bc -l) )); then
grove tip olshansky.info 0.01 --yes --json
fi

Using Python

import subprocess
import json

def grove_cmd(args):
"""Run Grove CLI command and return parsed JSON."""
result = subprocess.run(
["grove"] + args + ["--json"],
capture_output=True,
text=True,
check=True
)
return json.loads(result.stdout)

# Usage
balance = grove_cmd(["balance"])
print(f"Balance: {balance['balance']} {balance['token']}")

tip_result = grove_cmd(["tip", "olshansky.info", "0.01", "--yes"])
if tip_result.get("success"):
print(f"Tip sent: {tip_result['tx_url']}")