Organization Settings API
API endpoints for managing Zoho organization configurations. All endpoints require token_admin authentication.
Authentication
All endpoints require a valid JWT token:
Authorization: Bearer <token>Organizations
| Method | Path | Description |
|---|---|---|
| GET | /finances/organization | List all Zoho organizations |
GET /finances/organization
Returns all Zoho organizations (receivers) with country information.
Response (200):
{
"success": true,
"data": [
{
"id": 1,
"zoho_organization_id": 861752378,
"name": "TENDENCYS INNOVATIONS",
"rfc": "TIN1603038C4",
"locale_id": 1,
"country_name": "Mexico"
}
]
}Taxes
| Method | Path | Description |
|---|---|---|
| GET | /finances/organization/{orgId}/taxes | List all taxes for an organization |
| POST | /finances/organization/{orgId}/taxes | Create tax (individual or group) |
| PUT | /finances/organization/taxes/{id} | Update tax or group |
| DELETE | /finances/organization/taxes/{id} | Soft-delete tax (set inactive) |
| GET | /finances/organization/{orgId}/taxes/sync-preview | Preview taxes available from Zoho |
| POST | /finances/organization/{orgId}/taxes/sync | Bulk import taxes from Zoho |
POST /finances/organization/{orgId}/taxes
Creates a new individual tax or tax group. Syncs with Zoho Books API.
Path params: orgId (number) — Zoho organization ID
Request:
{
"label": "ReteRenta (2.5%)",
"rate": 0.025,
"tax_code": "002",
"tax_type": "retained",
"type": "individual",
"sort_order": 1
}For tax groups:
{
"tax_key": "ret_co_honorarios",
"label": "Honorarios + ReteIVA",
"tax_type": "retained",
"type": "group",
"child_ids": [5, 8]
}Payload fields:
| Field | Type | Required | Description |
|---|---|---|---|
label | string(100) | Yes | Human-readable label |
rate | number (0-1) | Individual only | Tax rate as decimal |
tax_code | string(10) | Individual only | Fiscal code |
tax_type | transferred | retained | Yes | Tax type |
type | individual | group | No | Default: individual |
child_ids | number[] (min 2) | Group only | Member tax IDs |
sort_order | number | No | Display order |
tax_key is auto-generated from label for individual taxes. For groups, it can be provided or auto-generated.
Response (201):
{
"success": true,
"data": { "id": 15, "zoho_tax_id": "5528319000006718624" }
}Errors:
| Code | Description |
|---|---|
| 400 | Invalid payload or missing required fields |
| 409 | Tax group requires at least 2 synced children |
| 500 | Zoho API rejected the operation |
GET /finances/organization/{orgId}/taxes/sync-preview
Compares Zoho taxes with local database and returns missing taxes.
Internally makes two Zoho API calls:
GET /v3/settings/taxes— standard taxesGET /v3/settings/taxes?tax_type=income_tax_tds— retention taxes + groups
For groups, fetches individual group details to resolve member taxes.
Response (200):
{
"success": true,
"data": [
{
"tax_id": "6656156000000105081",
"tax_name": "IVA",
"tax_percentage": 16,
"tax_type": "tax",
"already_synced": false
}
]
}POST /finances/organization/{orgId}/taxes/sync
Bulk inserts selected taxes from Zoho into local database.
Request:
{
"taxes": [
{
"tax_id": "6656156000000105081",
"tax_name": "IVA",
"tax_percentage": 16,
"tax_type": "tax"
}
]
}Accounts (Chart of Accounts)
| Method | Path | Description |
|---|---|---|
| GET | /finances/organization/{orgId}/accounts | List accounts for an organization |
| POST | /finances/organization/{orgId}/accounts | Create account (syncs to Zoho) |
| PUT | /finances/organization/accounts/{id} | Update account |
| PATCH | /finances/organization/accounts/{id}/toggle-active | Toggle active status |
| DELETE | /finances/organization/accounts/{id} | Delete account |
| GET | /finances/organization/{orgId}/accounts/sync-preview | Preview accounts from Zoho |
| POST | /finances/organization/{orgId}/accounts/sync | Bulk import accounts from Zoho |
POST /finances/organization/{orgId}/accounts
Creates an account in both Zoho and local database. The account_id is obtained from Zoho's response.
Request:
{
"description": "Office Supplies",
"account_type": "expense",
"parent_account_id": null,
"department_id": 3
}name is auto-generated by normalizing description (lowercase, no spaces, no accents).
department_id is only valid for parent accounts (ignored for children).
Payload fields:
| Field | Type | Required | Description |
|---|---|---|---|
description | string(255) | Yes | Human-readable name |
account_type | string | Yes | Zoho account type (expense, income, etc.) |
parent_account_id | number | null | No | Parent account ID for child accounts |
department_id | number | null | No | Department (parent accounts only) |
GET /finances/organization/{orgId}/accounts/sync-preview
Returns a 2-level hierarchical tree of accounts present in Zoho but missing in local DB.
Query params:
| Param | Type | Required | Description |
|---|---|---|---|
accountType | string | No | Filter by Zoho account type: Expense, Income, Asset, Liability, Equity, CostOfGoodsSold |
Response (200):
{
"success": true,
"data": [
{
"account_id": "5528319000000035001",
"account_name": "Cost of Goods Sold",
"account_type": "cost_of_goods_sold",
"is_parent": true,
"already_synced": false,
"children": [
{
"account_id": "5528319000000035005",
"account_name": "Raw Materials",
"account_type": "cost_of_goods_sold",
"already_synced": false
}
]
}
]
}Parents with all children already synced are shown with already_synced: true but include their unsynced children.
POST /finances/organization/{orgId}/accounts/sync
Bulk imports selected accounts. Parents are inserted first, then children with the correct parent_account_id.
Request:
{
"accounts": [
{
"account_id": "5528319000000035001",
"account_name": "Cost of Goods Sold",
"account_type": "cost_of_goods_sold",
"department_id": 3,
"children": [
{
"account_id": "5528319000000035005",
"account_name": "Raw Materials",
"account_type": "cost_of_goods_sold"
}
]
}
]
}Banks
| Method | Path | Description |
|---|---|---|
| GET | /finances/organization/{orgId}/banks | List banks for an organization |
| POST | /finances/organization/{orgId}/banks | Create bank |
| PUT | /finances/organization/banks/{id} | Update bank |
| PATCH | /finances/organization/banks/{id}/toggle-active | Toggle active status |
| GET | /finances/organization/{orgId}/banks/sync-preview | Preview banks from Zoho |
| POST | /finances/organization/{orgId}/banks/sync | Bulk import banks from Zoho |
POST /finances/organization/{orgId}/banks
Creates a new bank record.
Request:
{
"description": "BBVA Bancomer Principal",
"account_type": "bank"
}name is auto-generated from description.
Payload fields:
| Field | Type | Required | Description |
|---|---|---|---|
description | string(255) | Yes | Human-readable bank name |
account_type | string | Yes | bank, cash, or credit_card |
GET /finances/organization/{orgId}/banks/sync-preview
Returns a flat list of Zoho bank accounts not yet in local DB.
Response (200):
{
"success": true,
"data": [
{
"account_id": "5528319000000070001",
"account_name": "Petty Cash",
"account_type": "cash",
"is_active": true,
"already_synced": false
}
]
}POST /finances/organization/{orgId}/banks/sync
Bulk inserts selected bank accounts. name is auto-generated from description (the Zoho account_name).
Request:
{
"banks": [
{
"account_id": "5528319000000070001",
"account_name": "Petty Cash",
"account_type": "cash"
}
]
}Common Error Responses
All errors follow the Boom format:
{
"statusCode": 400,
"error": "Bad Request",
"message": "Descriptive error message"
}| Status | When |
|---|---|
| 400 | Validation failed (Joi schema) |
| 401 | Missing or invalid JWT |
| 403 | Insufficient permissions |
| 404 | Resource not found |
| 409 | Business rule conflict (e.g., deactivating parent with active children) |
| 500 | Zoho API rejected the operation |
