Access the Zoho Inventory API with managed OAuth authentication. Manage items, sales orders, invoices, purchase orders, bills, contacts, shipment orders, and item groups with full CRUD operations.
# List items
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/zoho-inventory/inventory/v1/items')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
https://api.maton.ai/zoho-inventory/inventory/v1/{endpoint}
Maton proxies requests to www.zohoapis.com/inventory/v1 and automatically injects your OAuth token.
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"
Manage your Zoho Inventory OAuth connections at https://api.maton.ai.
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections?app=zoho-inventory&status=ACTIVE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'zoho-inventory'}).encode()
req = urllib.request.Request('https://api.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))
EOF
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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": "{connection_id}",
"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-inventory",
"metadata": {}
}
}
Open the returned url in a browser to complete OAuth authorization.
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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))
EOF
If you have multiple Zoho Inventory connections, specify which one to use with the Maton-Connection header:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/zoho-inventory/inventory/v1/items')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '{connection_id}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
If you have multiple connections, always include this header to ensure requests go to the intended account.
| Module | Endpoint | Description |
|---|---|---|
| -------- | ---------- | ------------- |
| Items | /items | Products and services |
| Item Groups | /itemgroups | Grouped product variants |
| Contacts | /contacts | Customers and vendors |
| Sales Orders | /salesorders | Sales orders |
| Invoices | /invoices | Sales invoices |
| Purchase Orders | /purchaseorders | Purchase orders |
| Bills | /bills | Vendor bills |
| Shipment Orders | /shipmentorders | Shipment tracking |
GET /zoho-inventory/inventory/v1/items
Example:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/zoho-inventory/inventory/v1/items')
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",
"items": [
{
"item_id": "1234567890000",
"name": "Widget",
"status": "active",
"sku": "WDG-001",
"rate": 25.00,
"purchase_rate": 10.00,
"is_taxable": true
}
],
"page_context": {
"page": 1,
"per_page": 200,
"has_more_page": false
}
}
GET /zoho-inventory/inventory/v1/items/{item_id}
POST /zoho-inventory/inventory/v1/items
Content-Type: application/json
{
"name": "Widget",
"rate": 25.00,
"purchase_rate": 10.00,
"sku": "WDG-001",
"item_type": "inventory",
"product_type": "goods",
"unit": "pcs",
"is_taxable": true
}
Required Fields:
name - Item nameOptional Fields:
rate - Sales pricepurchase_rate - Purchase costsku - Stock keeping unit (unique)item_type - inventory, sales, purchases, or sales_and_purchasesproduct_type - goods or serviceunit - Unit of measurementis_taxable - Tax applicabilitytax_id - Tax identifierdescription - Item descriptionreorder_level - Reorder pointvendor_id - Preferred vendorExample:
python <<'EOF'
import urllib.request, os, json
data = json.dumps({
"name": "Widget",
"rate": 25.00,
"purchase_rate": 10.00,
"sku": "WDG-001",
"item_type": "inventory",
"product_type": "goods",
"unit": "pcs"
}).encode()
req = urllib.request.Request('https://api.maton.ai/zoho-inventory/inventory/v1/items', 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 item has been added.",
"item": {
"item_id": "1234567890000",
"name": "Widget",
"status": "active",
"rate": 25.00,
"purchase_rate": 10.00,
"sku": "WDG-001"
}
}
PUT /zoho-inventory/inventory/v1/items/{item_id}
Content-Type: application/json
{
"name": "Updated Widget",
"rate": 30.00
}
DELETE /zoho-inventory/inventory/v1/items/{item_id}
# Mark as active
POST /zoho-inventory/inventory/v1/items/{item_id}/active
# Mark as inactive
POST /zoho-inventory/inventory/v1/items/{item_id}/inactive
GET /zoho-inventory/inventory/v1/contacts
Query Parameters:
filter_by - Status.All, Status.Active, Status.Inactive, Status.Duplicate, Status.Crmsearch_text - Search across contact fieldssort_column - contact_name, first_name, last_name, email, created_time, last_modified_timecontact_name, company_name, email, phone - Field-specific filtersExample:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/zoho-inventory/inventory/v1/contacts')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
GET /zoho-inventory/inventory/v1/contacts/{contact_id}
POST /zoho-inventory/inventory/v1/contacts
Content-Type: application/json
{
"contact_name": "Acme Corporation",
"contact_type": "customer",
"company_name": "Acme Corp",
"email": "billing@acme.com",
"phone": "+1-555-1234"
}
Required Fields:
contact_name - Display nameOptional Fields:
contact_type - customer or vendorcompany_name - Legal entity nameemail - Email addressphone - Phone numberbilling_address - Address objectshipping_address - Address objectpayment_terms - Days for paymentcurrency_id - Currency identifierwebsite - Website URLPUT /zoho-inventory/inventory/v1/contacts/{contact_id}
DELETE /zoho-inventory/inventory/v1/contacts/{contact_id}
# Mark as active
POST /zoho-inventory/inventory/v1/contacts/{contact_id}/active
# Mark as inactive
POST /zoho-inventory/inventory/v1/contacts/{contact_id}/inactive
GET /zoho-inventory/inventory/v1/salesorders
Example:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/zoho-inventory/inventory/v1/salesorders')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
GET /zoho-inventory/inventory/v1/salesorders/{salesorder_id}
POST /zoho-inventory/inventory/v1/salesorders
Content-Type: application/json
{
"customer_id": "1234567890000",
"date": "2026-02-06",
"line_items": [
{
"item_id": "1234567890001",
"quantity": 5,
"rate": 25.00
}
]
}
Required Fields:
customer_id - Customer identifierline_items - Array of items with item_id, quantity, rateOptional Fields:
salesorder_number - Auto-generated if not specified (do not specify if auto-generation is enabled)date - Order date (yyyy-mm-dd)shipment_date - Expected shipment datereference_number - External referencenotes - Internal notesterms - Terms and conditionsdiscount - Discount percentage or amountshipping_charge - Shipping costadjustment - Price adjustmentPUT /zoho-inventory/inventory/v1/salesorders/{salesorder_id}
DELETE /zoho-inventory/inventory/v1/salesorders/{salesorder_id}
# Mark as confirmed
POST /zoho-inventory/inventory/v1/salesorders/{salesorder_id}/status/confirmed
# Mark as void
POST /zoho-inventory/inventory/v1/salesorders/{salesorder_id}/status/void
GET /zoho-inventory/inventory/v1/invoices
Example:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/zoho-inventory/inventory/v1/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 /zoho-inventory/inventory/v1/invoices/{invoice_id}
POST /zoho-inventory/inventory/v1/invoices
Content-Type: application/json
{
"customer_id": "1234567890000",
"line_items": [
{
"item_id": "1234567890001",
"quantity": 5,
"rate": 25.00
}
]
}
Required Fields:
customer_id - Customer identifierline_items - Array of itemsOptional Fields:
invoice_number - Auto-generated if not specifieddate - Invoice date (yyyy-mm-dd)due_date - Payment due datepayment_terms - Days until duediscount - Discount percentage or amountshipping_charge - Shipping costnotes - Internal notesterms - Terms and conditionsPUT /zoho-inventory/inventory/v1/invoices/{invoice_id}
DELETE /zoho-inventory/inventory/v1/invoices/{invoice_id}
# Mark as sent
POST /zoho-inventory/inventory/v1/invoices/{invoice_id}/status/sent
# Mark as draft
POST /zoho-inventory/inventory/v1/invoices/{invoice_id}/status/draft
# Void invoice
POST /zoho-inventory/inventory/v1/invoices/{invoice_id}/status/void
# Email invoice to customer
POST /zoho-inventory/inventory/v1/invoices/{invoice_id}/email
# Get email content template
GET /zoho-inventory/inventory/v1/invoices/{invoice_id}/email
# List payments applied
GET /zoho-inventory/inventory/v1/invoices/{invoice_id}/payments
# Delete a payment
DELETE /zoho-inventory/inventory/v1/invoices/{invoice_id}/payments/{invoice_payment_id}
# List credits applied
GET /zoho-inventory/inventory/v1/invoices/{invoice_id}/creditsapplied
# Apply credits
POST /zoho-inventory/inventory/v1/invoices/{invoice_id}/credits
# Delete applied credit
DELETE /zoho-inventory/inventory/v1/invoices/{invoice_id}/creditsapplied/{creditnotes_invoice_id}
# List comments
GET /zoho-inventory/inventory/v1/invoices/{invoice_id}/comments
# Add comment
POST /zoho-inventory/inventory/v1/invoices/{invoice_id}/comments
# Update comment
PUT /zoho-inventory/inventory/v1/invoices/{invoice_id}/comments/{comment_id}
# Delete comment
DELETE /zoho-inventory/inventory/v1/invoices/{invoice_id}/comments/{comment_id}
GET /zoho-inventory/inventory/v1/purchaseorders
Example:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/zoho-inventory/inventory/v1/purchaseorders')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
GET /zoho-inventory/inventory/v1/purchaseorders/{purchaseorder_id}
POST /zoho-inventory/inventory/v1/purchaseorders
Content-Type: application/json
{
"vendor_id": "1234567890000",
"line_items": [
{
"item_id": "1234567890001",
"quantity": 100,
"rate": 10.00
}
]
}
Required Fields:
vendor_id - Vendor identifierline_items - Array of itemsOptional Fields:
purchaseorder_number - Auto-generated if not specified (do not specify if auto-generation is enabled)date - Order date (yyyy-mm-dd)delivery_date - Expected delivery datereference_number - External referenceship_via - Shipping methodnotes - Internal notesterms - Terms and conditionsPUT /zoho-inventory/inventory/v1/purchaseorders/{purchaseorder_id}
DELETE /zoho-inventory/inventory/v1/purchaseorders/{purchaseorder_id}
# Mark as issued
POST /zoho-inventory/inventory/v1/purchaseorders/{purchaseorder_id}/status/issued
# Mark as cancelled
POST /zoho-inventory/inventory/v1/purchaseorders/{purchaseorder_id}/status/cancelled
GET /zoho-inventory/inventory/v1/bills
Example:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/zoho-inventory/inventory/v1/bills')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
GET /zoho-inventory/inventory/v1/bills/{bill_id}
POST /zoho-inventory/inventory/v1/bills
Content-Type: application/json
{
"vendor_id": "1234567890000",
"bill_number": "BILL-001",
"date": "2026-02-06",
"due_date": "2026-03-06",
"line_items": [
{
"item_id": "1234567890001",
"quantity": 100,
"rate": 10.00
}
]
}
Required Fields:
vendor_id - Vendor identifierbill_number - Unique bill number (required, not auto-generated)date - Bill date (yyyy-mm-dd)due_date - Payment due dateline_items - Array of itemsOptional Fields:
reference_number - External referencenotes - Internal notesterms - Terms and conditionscurrency_id - Currency identifierexchange_rate - Exchange rate for foreign currencyPUT /zoho-inventory/inventory/v1/bills/{bill_id}
DELETE /zoho-inventory/inventory/v1/bills/{bill_id}
# Mark as open
POST /zoho-inventory/inventory/v1/bills/{bill_id}/status/open
# Mark as void
POST /zoho-inventory/inventory/v1/bills/{bill_id}/status/void
POST /zoho-inventory/inventory/v1/shipmentorders
Content-Type: application/json
{
"shipment_number": "SHP-001",
"date": "2026-02-06",
"delivery_method": "FedEx",
"tracking_number": "1234567890"
}
Required Fields:
shipment_number - Unique shipment numberdate - Shipment datedelivery_method - Carrier/delivery methodOptional Fields:
tracking_number - Carrier tracking numbershipping_charge - Shipping costnotes - Internal notesreference_number - External referenceGET /zoho-inventory/inventory/v1/shipmentorders/{shipmentorder_id}
PUT /zoho-inventory/inventory/v1/shipmentorders/{shipmentorder_id}
DELETE /zoho-inventory/inventory/v1/shipmentorders/{shipmentorder_id}
POST /zoho-inventory/inventory/v1/shipmentorders/{shipmentorder_id}/status/delivered
GET /zoho-inventory/inventory/v1/itemgroups
GET /zoho-inventory/inventory/v1/itemgroups/{itemgroup_id}
POST /zoho-inventory/inventory/v1/itemgroups
Content-Type: application/json
{
"group_name": "T-Shirts",
"unit": "pcs",
"items": [
{
"name": "T-Shirt - Small",
"rate": 20.00,
"purchase_rate": 8.00,
"sku": "TS-S"
},
{
"name": "T-Shirt - Medium",
"rate": 20.00,
"purchase_rate": 8.00,
"sku": "TS-M"
}
]
}
Required Fields:
group_name - Group nameunit - Unit of measurementPUT /zoho-inventory/inventory/v1/itemgroups/{itemgroup_id}
DELETE /zoho-inventory/inventory/v1/itemgroups/{itemgroup_id}
# Mark as active
POST /zoho-inventory/inventory/v1/itemgroups/{itemgroup_id}/active
# Mark as inactive
POST /zoho-inventory/inventory/v1/itemgroups/{itemgroup_id}/inactive
Zoho Inventory uses page-based pagination:
GET /zoho-inventory/inventory/v1/items?page=1&per_page=50
Response includes pagination info in page_context:
{
"code": 0,
"message": "success",
"items": [...],
"page_context": {
"page": 1,
"per_page": 50,
"has_more_page": true,
"sort_column": "name",
"sort_order": "A"
}
}
Continue fetching while has_more_page is true, incrementing page each time.
const response = await fetch(
'https://api.maton.ai/zoho-inventory/inventory/v1/items',
{
headers: {
'Authorization': `Bearer ${process.env.MATON_API_KEY}`
}
}
);
const data = await response.json();
import os
import requests
response = requests.get(
'https://api.maton.ai/zoho-inventory/inventory/v1/items',
headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'}
)
data = response.json()
code: 0 and a message fieldyyyy-mm-dd formatcustomer or vendorinventory, sales, purchases, sales_and_purchasesgoods or serviceorganization_id parameter is automatically handled by the gateway - you do not need to specify itsalesorder_number or purchaseorder_number unless auto-generation is disabled in settings/status/confirmed, /status/void)curl -g when URLs contain brackets to disable glob parsingjq or other commands, environment variables like $MATON_API_KEY may not expand correctly in some shell environments| Status | Meaning |
|---|---|
| -------- | --------- |
| 400 | Missing Zoho Inventory 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 Inventory API |
| Code | Description |
|---|---|
| ------ | ------------- |
| 0 | Success |
| 1 | Invalid value |
| 2 | Mandatory field missing |
| 3 | Resource does not exist |
| 5 | Invalid URL |
MATON_API_KEY environment variable is set:echo $MATON_API_KEY
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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))
EOF
zoho-inventory. For example:https://api.maton.ai/zoho-inventory/inventory/v1/itemshttps://api.maton.ai/inventory/v1/items共 2 个版本