Zoho Bookings API 集成:管理预约与员工 - Openclaw Skills

作者:互联网

2026-03-30

AI教程

什么是 Zoho Bookings?

此技能为 Zoho Bookings 生态系统提供了高性能桥梁,使开发人员能够绕过手动 OAuth 令牌管理的复杂性。通过在 Openclaw Skills 框架内利用此集成,您可以通过统一的 API 网关对工作空间、服务、工作人员和客户预约执行完整的 CRUD 操作。

该技能专为构建自动化调度助手、自定义预订门户或内部资源管理工具的开发人员而设计。它处理凭据的安全注入,并提供用于与 Zoho 调度基础架构交互的流线型接口,使其成为任何专业 Openclaw Skills 部署的重要组件。

下载入口:https://github.com/openclaw/skills/tree/main/skills/byungkyu/zoho-bookings

安装与下载

1. ClawHub CLI

从源直接安装技能的最快方式。

npx clawhub@latest install zoho-bookings

2. 手动安装

将技能文件夹复制到以下位置之一

全局模式 ~/.openclaw/skills/ 工作区 /skills/

优先级:工作区 > 本地 > 内置

3. 提示词安装

将此提示词复制到 OpenClaw 即可自动安装。

请帮我使用 Clawhub 安装 zoho-bookings。如果尚未安装 Clawhub,请先安装(npm i -g clawhub)。

Zoho Bookings 应用场景

  • 通过 AI 代理和聊天机器人自动化客户预约。
  • 将员工日程和服务可用性与外部仪表板同步。
  • 批量获取预约数据用于业务分析和报告。
  • 以程序化方式管理多办公室工作空间和服务列表。
  • 根据客户触发因素实现实时预约取消和状态更新。
Zoho Bookings 工作原理
  1. 用户使用其 Maton API 密钥进行身份验证以访问托管网关。
  2. 通过控制 API 建立与 Zoho Bookings 的连接,生成 OAuth 授权 URL。
  3. 授权后,网关会自动安全地存储并刷新 OAuth 令牌。
  4. 请求发送到 Maton 网关 URL,该 URL 将调用代理到带有正确标头的 Zoho Bookings API。
  5. 网关将结构化的 JSON 数据返回给调用应用程序或代理以进行进一步处理。

Zoho Bookings 配置指南

首先,将您的 Maton API 密钥设置为环境变量:

export MATON_API_KEY="YOUR_API_KEY"

要列出当前工作空间并验证连接,请使用以下命令:

curl -X GET "https://gateway.maton.ai/zoho-bookings/bookings/v1/json/workspaces" r
     -H "Authorization: Bearer $MATON_API_KEY"

要创建新的 OAuth 连接,请使用控制端点:

curl -X POST "https://ctrl.maton.ai/connections" r
     -H "Authorization: Bearer $MATON_API_KEY" r
     -H "Content-Type: application/json" r
     -d '{"app": "zoho-bookings"}'

Zoho Bookings 数据架构与分类体系

该技能围绕以下主要实体组织数据:

实体 关键字段 格式
工作空间 id, name JSON 对象
服务 id, name, duration, price, assigned_staffs JSON 对象
员工 id, name, email, designation JSON 对象
预约 booking_id, from_time, customer_details, status JSON 对象

重要提示: 日期必须遵循 dd-MMM-yyyy HH:mm:ss 格式(例如:20-Feb-2026 10:00:00)。预约 ID 通常包含 # 前缀,在查询参数中使用时必须进行 URL 编码为 %23

name: zoho-bookings
description: |
  Zoho Bookings API integration with managed OAuth. Manage appointments, services, staff, and workspaces.
  Use this skill when users want to book appointments, manage services, view staff availability, or manage workspaces in Zoho Bookings.
  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: ??
    homepage: "https://maton.ai"
    requires:
      env:
        - MATON_API_KEY

Zoho Bookings

Access the Zoho Bookings API with managed OAuth authentication. Manage appointments, services, staff, and workspaces with full CRUD operations.

Quick Start

# List workspaces
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/zoho-bookings/bookings/v1/json/workspaces')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Base URL

https://gateway.maton.ai/zoho-bookings/bookings/v1/json/{endpoint}

The gateway proxies requests to www.zohoapis.com/bookings/v1/json 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
  2. Go to maton.ai/settings
  3. Copy your API key

Connection Management

Manage your Zoho Bookings 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-bookings&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

Create Connection

python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'zoho-bookings'}).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))
EOF

Get 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": "3c358231-7ca7-4a63-8a3c-3a9d21be53ca",
    "status": "ACTIVE",
    "creation_time": "2026-02-18T00:17:23.498742Z",
    "last_updated_time": "2026-02-18T00:18:59.299114Z",
    "url": "https://connect.maton.ai/?session_token=...",
    "app": "zoho-bookings",
    "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))
EOF

Specifying Connection

If you have multiple Zoho Bookings 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-bookings/bookings/v1/json/workspaces')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '3c358231-7ca7-4a63-8a3c-3a9d21be53ca')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

If omitted, the gateway uses the default (oldest) active connection.

API Reference

Workspaces

Fetch Workspaces

GET /zoho-bookings/bookings/v1/json/workspaces

Query Parameters:

Parameter Type Description
workspace_id string Filter by specific workspace ID

Example:

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/zoho-bookings/bookings/v1/json/workspaces')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Response:

{
  "response": {
    "returnvalue": {
      "data": [
        {
          "name": "Main Office",
          "id": "4753814000000048016"
        }
      ]
    },
    "status": "success"
  }
}

Create Workspace

POST /zoho-bookings/bookings/v1/json/createworkspace
Content-Type: application/x-www-form-urlencoded

Form Parameters:

Parameter Type Required Description
name string Yes Workspace name (2-50 chars, no special characters)

Example:

python <<'EOF'
import urllib.request, os, json
from urllib.parse import urlencode
form_data = urlencode({'name': 'New York Office'}).encode()
req = urllib.request.Request('https://gateway.maton.ai/zoho-bookings/bookings/v1/json/createworkspace', data=form_data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/x-www-form-urlencoded')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Services

Fetch Services

GET /zoho-bookings/bookings/v1/json/services?workspace_id={workspace_id}

Query Parameters:

Parameter Type Required Description
workspace_id string Yes Workspace ID
service_id string No Filter by specific service ID
staff_id string No Filter by staff ID

Example:

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/zoho-bookings/bookings/v1/json/services?workspace_id=4753814000000048016')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Response:

{
  "response": {
    "returnvalue": {
      "data": [
        {
          "id": "4753814000000048054",
          "name": "Product Demo",
          "duration": "30 mins",
          "service_type": "APPOINTMENT",
          "price": 0,
          "currency": "USD",
          "assigned_staffs": ["4753814000000048014"],
          "assigned_workspace": "4753814000000048016",
          "embed_url": "https://example.zohobookings.com/portal-embed#/4753814000000048054",
          "let_customer_select_staff": true
        }
      ],
      "next_page_available": false,
      "page": 1
    },
    "status": "success"
  }
}

Create Service

POST /zoho-bookings/bookings/v1/json/createservice
Content-Type: application/x-www-form-urlencoded

Form Parameters:

Parameter Type Required Description
name string Yes Service name
workspace_id string Yes Workspace ID
duration integer No Duration in minutes
cost number No Service price
pre_buffer integer No Buffer time before (minutes)
post_buffer integer No Buffer time after (minutes)
description string No Service description
assigned_staffs string No JSON array of staff IDs

Example:

python <<'EOF'
import urllib.request, os, json
from urllib.parse import urlencode
form_data = urlencode({
    'name': 'Consultation',
    'workspace_id': '4753814000000048016',
    'duration': '60'
}).encode()
req = urllib.request.Request('https://gateway.maton.ai/zoho-bookings/bookings/v1/json/createservice', data=form_data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/x-www-form-urlencoded')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Staff

Fetch Staff

GET /zoho-bookings/bookings/v1/json/staffs?workspace_id={workspace_id}

Query Parameters:

Parameter Type Required Description
workspace_id string Yes Workspace ID
staff_id string No Filter by specific staff ID
service_id string No Filter by service ID
staff_email string No Filter by email (partial match)

Example:

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/zoho-bookings/bookings/v1/json/staffs?workspace_id=4753814000000048016')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Response:

{
  "response": {
    "returnvalue": {
      "data": [
        {
          "id": "4753814000000048014",
          "name": "John Doe",
          "email": "john@example.com",
          "designation": "Consultant",
          "assigned_services": ["4753814000000048054"],
          "assigned_workspaces": ["4753814000000048016"],
          "embed_url": "https://example.zohobookings.com/portal-embed#/4753814000000048014"
        }
      ]
    },
    "status": "success"
  }
}

Appointments

Book Appointment

POST /zoho-bookings/bookings/v1/json/appointment
Content-Type: application/x-www-form-urlencoded

Form Parameters:

Parameter Type Required Description
service_id string Yes Service ID
staff_id string Yes* Staff ID (*or resource_id/group_id)
from_time string Yes Start time: dd-MMM-yyyy HH:mm:ss (24-hour)
timezone string No Timezone (e.g., America/Los_Angeles)
customer_details string Yes JSON string with name, email, phone_number
notes string No Appointment notes
additional_fields string No JSON string with custom fields

Example:

python <<'EOF'
import urllib.request, os, json
from urllib.parse import urlencode
form_data = urlencode({
    'service_id': '4753814000000048054',
    'staff_id': '4753814000000048014',
    'from_time': '20-Feb-2026 10:00:00',
    'timezone': 'America/Los_Angeles',
    'customer_details': json.dumps({
        'name': 'Jane Smith',
        'email': 'jane@example.com',
        'phone_number': '+15551234567'
    })
}).encode()
req = urllib.request.Request('https://gateway.maton.ai/zoho-bookings/bookings/v1/json/appointment', data=form_data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/x-www-form-urlencoded')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Response:

{
  "response": {
    "returnvalue": {
      "booking_id": "#NU-00001",
      "service_name": "Product Demo",
      "staff_name": "John Doe",
      "start_time": "20-Feb-2026 10:00:00",
      "end_time": "20-Feb-2026 10:30:00",
      "duration": "30 mins",
      "customer_name": "Jane Smith",
      "customer_email": "jane@example.com",
      "status": "upcoming",
      "time_zone": "America/Los_Angeles"
    },
    "status": "success"
  }
}

Get Appointment

GET /zoho-bookings/bookings/v1/json/getappointment?booking_id={booking_id}

Query Parameters:

Parameter Type Required Description
booking_id string Yes Booking ID (URL-encoded, e.g., %23NU-00001)

Example:

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/zoho-bookings/bookings/v1/json/getappointment?booking_id=%23NU-00001')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Fetch Appointments

POST /zoho-bookings/bookings/v1/json/fetchappointment
Content-Type: application/x-www-form-urlencoded

Form Parameters:

Send parameters wrapped in a data field as JSON:

Parameter Type Description
from_time string Start date: dd-MMM-yyyy HH:mm:ss
to_time string End date: dd-MMM-yyyy HH:mm:ss
status string UPCOMING, CANCEL, COMPLETED, NO_SHOW, PENDING
service_id string Filter by service
staff_id string Filter by staff
customer_name string Filter by customer name (partial match)
customer_email string Filter by email (partial match)
page integer Page number
per_page integer Results per page (max 100)

Example:

python <<'EOF'
import urllib.request, os, json
from urllib.parse import urlencode
form_data = urlencode({
    'data': json.dumps({
        'from_time': '17-Feb-2026 00:00:00',
        'to_time': '20-Feb-2026 23:59:59'
    })
}).encode()
req = urllib.request.Request('https://gateway.maton.ai/zoho-bookings/bookings/v1/json/fetchappointment', data=form_data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/x-www-form-urlencoded')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Response:

{
  "response": {
    "returnvalue": {
      "response": [
        {
          "booking_id": "#NU-00001",
          "service_name": "Product Demo",
          "staff_name": "John Doe",
          "start_time": "20-Feb-2026 10:00:00",
          "customer_name": "Jane Smith",
          "status": "upcoming"
        }
      ],
      "next_page_available": false,
      "page": 1
    },
    "status": "success"
  }
}

Update Appointment

POST /zoho-bookings/bookings/v1/json/updateappointment
Content-Type: application/x-www-form-urlencoded

Form Parameters:

Parameter Type Required Description
booking_id string Yes Booking ID
action string Yes completed, cancel, or noshow

Example - Cancel Appointment:

python <<'EOF'
import urllib.request, os, json
from urllib.parse import urlencode
form_data = urlencode({
    'booking_id': '#NU-00001',
    'action': 'cancel'
}).encode()
req = urllib.request.Request('https://gateway.maton.ai/zoho-bookings/bookings/v1/json/updateappointment', data=form_data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/x-www-form-urlencoded')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Pagination

Appointments use page-based pagination:

python <<'EOF'
import urllib.request, os, json
from urllib.parse import urlencode
form_data = urlencode({
    'data': json.dumps({
        'from_time': '01-Feb-2026 00:00:00',
        'to_time': '28-Feb-2026 23:59:59',
        'page': 1,
        'per_page': 50
    })
}).encode()
req = urllib.request.Request('https://gateway.maton.ai/zoho-bookings/bookings/v1/json/fetchappointment', data=form_data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/x-www-form-urlencoded')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

Response includes pagination info:

{
  "response": {
    "returnvalue": {
      "response": [...],
      "next_page_available": true,
      "page": 1
    },
    "status": "success"
  }
}

Code Examples

JavaScript

// Fetch workspaces
const response = await fetch(
  'https://gateway.maton.ai/zoho-bookings/bookings/v1/json/workspaces',
  {
    headers: {
      'Authorization': `Bearer ${process.env.MATON_API_KEY}`
    }
  }
);
const data = await response.json();

Python

import os
import requests

# Fetch services
response = requests.get(
    'https://gateway.maton.ai/zoho-bookings/bookings/v1/json/services',
    headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'},
    params={'workspace_id': '4753814000000048016'}
)
data = response.json()

Notes

  • Date/time format: dd-MMM-yyyy HH:mm:ss (e.g., 20-Feb-2026 10:00:00)
  • Booking IDs include # prefix (URL-encode as %23)
  • customer_details must be a JSON string, not an object
  • fetchappointment requires parameters wrapped in data field as JSON
  • Other POST endpoints use regular form fields
  • Service types: APPOINTMENT, RESOURCE, CLASS, COLLECTIVE
  • Status values: UPCOMING, CANCEL, ONGOING, PENDING, COMPLETED, NO_SHOW
  • Default pagination: 50 appointments per page (max 100)
  • If you receive a scope error, contact Maton support at support@maton.ai with the specific operations/APIs you need and your use-case
  • IMPORTANT: When using curl commands, use curl -g when URLs contain brackets to disable glob parsing
  • IMPORTANT: When piping curl output to jq or other commands, environment variables like $MATON_API_KEY may not expand correctly in some shell environments

Error Handling

Status Meaning
400 Missing Zoho Bookings connection or invalid request
401 Invalid or missing Maton API key
429 Rate limited
4xx/5xx Passthrough error from Zoho Bookings API

Rate Limits

Plan Daily Limit
Free 250 calls/user
Basic 1,000 calls/user
Premium 3,000 calls/user
Zoho One 3,000 calls/user

Troubleshooting: API Key Issues

  1. Check that the MATON_API_KEY environment variable is set:
echo $MATON_API_KEY
  1. 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))
EOF

Troubleshooting: Invalid App Name

  1. Ensure your URL path starts with zoho-bookings. For example:
  • Correct: https://gateway.maton.ai/zoho-bookings/bookings/v1/json/workspaces
  • Incorrect: https://gateway.maton.ai/bookings/v1/json/workspaces

Resources

  • Zoho Bookings API Documentation
  • Book Appointment API
  • Fetch Appointments API
  • Fetch Services API
  • Fetch Staff API
  • Maton Community
  • Maton Support