Zoho Books
name: zoho-books
by byungkyu · published 2026-03-22
$ claw add gh:byungkyu/byungkyu-zoho-books---
name: zoho-books
description: |
Zoho Books API integration with managed OAuth. Manage invoices, contacts, bills, expenses, and other accounting data.
Use this skill when users want to read, create, update, or delete invoices, contacts, bills, expenses, or other financial records in Zoho Books.
For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway).
Requires network access and valid Maton API key.
metadata:
author: maton
version: "1.0"
clawdbot:
emoji: 🧠
requires:
env:
- MATON_API_KEY
---
# Zoho Books
Access the Zoho Books API with managed OAuth authentication. Manage invoices, contacts, bills, expenses, sales orders, purchase orders, and other accounting data with full CRUD operations.
Quick Start
# List contacts
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/zoho-books/books/v3/contacts')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOFBase URL
https://gateway.maton.ai/zoho-books/books/v3/{endpoint}The gateway proxies requests to `www.zohoapis.com/books/v3` and automatically injects your OAuth token.
Authentication
All requests require the Maton API key in the Authorization header:
Authorization: Bearer $MATON_API_KEY**Environment Variable:** Set your API key as `MATON_API_KEY`:
export MATON_API_KEY="YOUR_API_KEY"Getting Your API Key
1. Sign in or create an account at [maton.ai](https://maton.ai)
2. Go to [maton.ai/settings](https://maton.ai/settings)
3. Copy your API key
Connection Management
Manage your Zoho Books OAuth connections at `https://ctrl.maton.ai`.
List Connections
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections?app=zoho-books&status=ACTIVE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOFCreate Connection
python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'zoho-books'}).encode()
req = urllib.request.Request('https://ctrl.maton.ai/connections', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOFGet Connection
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF**Response:**
{
"connection": {
"connection_id": "21fd90f9-5935-43cd-b6c8-bde9d915ca80",
"status": "ACTIVE",
"creation_time": "2025-12-08T07:20:53.488460Z",
"last_updated_time": "2026-01-31T20:03:32.593153Z",
"url": "https://connect.maton.ai/?session_token=...",
"app": "zoho-books",
"metadata": {}
}
}Open the returned `url` in a browser to complete OAuth authorization.
Delete Connection
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}', method='DELETE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOFSpecifying Connection
If you have multiple Zoho Books connections, specify which one to use with the `Maton-Connection` header:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/zoho-books/books/v3/contacts')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '21fd90f9-5935-43cd-b6c8-bde9d915ca80')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOFIf omitted, the gateway uses the default (oldest) active connection.
API Reference
Available Modules
Zoho Books organizes data into modules. Key modules include:
| Module | Endpoint | Description |
|--------|----------|-------------|
| Contacts | `/contacts` | Customers and vendors |
| Invoices | `/invoices` | Sales invoices |
| Bills | `/bills` | Vendor bills |
| Expenses | `/expenses` | Business expenses |
| Sales Orders | `/salesorders` | Sales orders |
| Purchase Orders | `/purchaseorders` | Purchase orders |
| Credit Notes | `/creditnotes` | Customer credit notes |
| Recurring Invoices | `/recurringinvoices` | Automated recurring invoices |
| Recurring Bills | `/recurringbills` | Automated recurring bills |
Contacts
#### List Contacts
GET /zoho-books/books/v3/contacts**Example:**
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/zoho-books/books/v3/contacts')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF**Response:**
{
"code": 0,
"message": "success",
"contacts": [...],
"page_context": {
"page": 1,
"per_page": 200,
"has_more_page": false,
"sort_column": "contact_name",
"sort_order": "A"
}
}#### Get Contact
GET /zoho-books/books/v3/contacts/{contact_id}**Example:**
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/zoho-books/books/v3/contacts/8527119000000099001')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF#### Create Contact
POST /zoho-books/books/v3/contacts
Content-Type: application/json
{
"contact_name": "Customer Name",
"contact_type": "customer"
}**Required Fields:**
**Optional Fields:**
**Example:**
python <<'EOF'
import urllib.request, os, json
data = json.dumps({
"contact_name": "Acme Corporation",
"contact_type": "customer",
"company_name": "Acme Corp",
"email": "billing@acme.com",
"phone": "+1-555-1234"
}).encode()
req = urllib.request.Request('https://gateway.maton.ai/zoho-books/books/v3/contacts', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF**Response:**
{
"code": 0,
"message": "The contact has been added.",
"contact": {
"contact_id": "8527119000000099001",
"contact_name": "Acme Corporation",
"company_name": "Acme Corp",
"contact_type": "customer",
...
}
}#### Update Contact
PUT /zoho-books/books/v3/contacts/{contact_id}
Content-Type: application/json
{
"contact_name": "Updated Name",
"phone": "+1-555-9999"
}**Example:**
python <<'EOF'
import urllib.request, os, json
data = json.dumps({
"contact_name": "Acme Corporation Updated",
"phone": "+1-555-9999"
}).encode()
req = urllib.request.Request('https://gateway.maton.ai/zoho-books/books/v3/contacts/8527119000000099001', data=data, method='PUT')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF#### Delete Contact
DELETE /zoho-books/books/v3/contacts/{contact_id}**Example:**
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/zoho-books/books/v3/contacts/8527119000000099001', method='DELETE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF**Response:**
{
"code": 0,
"message": "The customer has been deleted."
}Invoices
#### List Invoices
GET /zoho-books/books/v3/invoices**Example:**
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/zoho-books/books/v3/invoices')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF#### Get Invoice
GET /zoho-books/books/v3/invoices/{invoice_id}#### Create Invoice
POST /zoho-books/books/v3/invoices
Content-Type: application/json
{
"customer_id": "8527119000000099001",
"line_items": [
{
"item_id": "8527119000000100001",
"quantity": 1,
"rate": 100.00
}
]
}**Required Fields:**
**Optional Fields:**
#### Update Invoice
PUT /zoho-books/books/v3/invoices/{invoice_id}#### Delete Invoice
DELETE /zoho-books/books/v3/invoices/{invoice_id}#### Invoice Actions
# Mark as sent
POST /zoho-books/books/v3/invoices/{invoice_id}/status/sent
# Void invoice
POST /zoho-books/books/v3/invoices/{invoice_id}/status/void
# Email invoice
POST /zoho-books/books/v3/invoices/{invoice_id}/emailBills
#### List Bills
GET /zoho-books/books/v3/bills**Example:**
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/zoho-books/books/v3/bills')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF#### Create Bill
POST /zoho-books/books/v3/bills
Content-Type: application/json
{
"vendor_id": "8527119000000099002",
"bill_number": "BILL-001",
"date": "2026-02-06",
"line_items": [
{
"account_id": "8527119000000100002",
"description": "Office Supplies",
"amount": 150.00
}
]
}**Required Fields:**
#### Update Bill
PUT /zoho-books/books/v3/bills/{bill_id}#### Delete Bill
DELETE /zoho-books/books/v3/bills/{bill_id}Expenses
#### List Expenses
GET /zoho-books/books/v3/expenses**Example:**
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/zoho-books/books/v3/expenses')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF#### Create Expense
POST /zoho-books/books/v3/expenses
Content-Type: application/json
{
"account_id": "8527119000000100003",
"date": "2026-02-06",
"amount": 75.50,
"paid_through_account_id": "8527119000000100004",
"description": "Business lunch"
}**Required Fields:**
**Optional Fields:**
#### Update Expense
PUT /zoho-books/books/v3/expenses/{expense_id}#### Delete Expense
DELETE /zoho-books/books/v3/expenses/{expense_id}Sales Orders
#### List Sales Orders
GET /zoho-books/books/v3/salesorders#### Create Sales Order
POST /zoho-books/books/v3/salesordersPurchase Orders
#### List Purchase Orders
GET /zoho-books/books/v3/purchaseorders#### Create Purchase Order
POST /zoho-books/books/v3/purchaseordersCredit Notes
#### List Credit Notes
GET /zoho-books/books/v3/creditnotesRecurring Invoices
#### List Recurring Invoices
GET /zoho-books/books/v3/recurringinvoicesRecurring Bills
#### List Recurring Bills
GET /zoho-books/books/v3/recurringbillsPagination
Zoho Books uses page-based pagination:
GET /zoho-books/books/v3/contacts?page=1&per_page=50Response includes pagination info in `page_context`:
{
"code": 0,
"message": "success",
"contacts": [...],
"page_context": {
"page": 1,
"per_page": 50,
"has_more_page": true,
"sort_column": "contact_name",
"sort_order": "A"
}
}Continue fetching while `has_more_page` is `true`, incrementing `page` each time.
Code Examples
JavaScript
const response = await fetch(
'https://gateway.maton.ai/zoho-books/books/v3/contacts',
{
headers: {
'Authorization': `Bearer ${process.env.MATON_API_KEY}`
}
}
);
const data = await response.json();Python
import os
import requests
response = requests.get(
'https://gateway.maton.ai/zoho-books/books/v3/contacts',
headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'}
)
data = response.json()Notes
Error Handling
| Status | Meaning |
|--------|---------|
| 400 | Missing Zoho Books connection or invalid request |
| 401 | Invalid or missing Maton API key, or OAuth scope mismatch |
| 404 | Resource not found |
| 429 | Rate limited |
| 4xx/5xx | Passthrough error from Zoho Books API |
Common Error Codes
| Code | Description |
|------|-------------|
| 0 | Success |
| 57 | Not authorized (OAuth scope mismatch) |
| 1 | Invalid value |
| 2 | Mandatory field missing |
| 3 | Resource does not exist |
| 5 | Invalid URL |
Troubleshooting: API Key Issues
1. Check that the `MATON_API_KEY` environment variable is set:
echo $MATON_API_KEY2. Verify the API key is valid by listing connections:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOFTroubleshooting: Invalid App Name
1. Ensure your URL path starts with `zoho-books`. For example:
Resources
More tools from the same signal band
Order food/drinks (点餐) on an Android device paired as an OpenClaw node. Uses in-app menu and cart; add goods, view cart, submit order (demo, no real payment).
Sign plugins, rotate agent credentials without losing identity, and publicly attest to plugin behavior with verifiable claims and authenticated transfers.
The philosophical layer for AI agents. Maps behavior to Spinoza's 48 affects, calculates persistence scores, and generates geometric self-reports. Give your...