如果您经营一家依赖预订的企业,您可能需要在多个地方保存预订数据。您的 CRM 需要知道新客户何时预订。您的 ERP 需要收入数据。您的营销工具需要触发欢迎电子邮件。您的自定义应用程序需要以编程方式创建预订。
Cowlendar 的 公共 API 和 Webhooks 使这一切成为可能。该 API 允许您读取您的服务和预订,并从任何外部系统创建新的预订。每次发生事件时,Webhook 都会向您的服务器推送实时通知:创建、确认、取消、重新安排或发生订阅事件。
这两个功能目前都处于 测试版 。
您可以使用 Cowlendar API 构建什么?
以下是 Cowlendar 商家目前正在构建的真实集成场景:
将每个预订同步到 HubSpot、Salesforce 或任何 CRM。 当客户预订理发、瑜伽课程或租赁时,网络钩子会立即触发,并包含完整的预订数据(姓名、电子邮件、电话、服务、日期、价格、团队成员)。您的 CRM 自动创建或更新联系人,无需手动输入数据。 构建您自己的预订页面或 移动应用。 使用 API 获取您的服务,包括持续时间、团队成员、设备和参与者类别,并从您自己的前端创建预订。预订会触发与通过 Cowlendar 小部件进行的任何预订相同的确认电子邮件、短信通知和 Google Calendar 同步。 使用 Zapier 或 Make 实现工作流程自动化,无需代码。 将 Cowlendar Webhook 指向您的 Zapier 或 Make Webhook URL。每一次预订事件都会成为一个触发器。当有人预订时发送 Slack 通知、向 Google 表格添加行、创建 Trello 卡片或在 Klaviyo 或 Mailchimp 中触发电子邮件序列。 将预订数据输入到您的报告或 BI 工具中。 使用列表预订端点来提取某个日期范围内的所有预订,并按状态、服务、出勤或客户电子邮件进行筛选。导出到您的数据仓库、Google Sheets 或 Airtable 以用于自定义仪表板。 将预订链接到订阅积分。 通过 API 创建预订时,传递 subscription_id 会自动从客户的计划中扣除一个积分,例如 10 节瑜伽通行证。 将 POS 或管理预订连接到外部系统。 Webhook 适用于所有预订源:店面小部件、管理面板、POS 和 API 本身。没有任何事情会被遗漏。
认证
每个 API 请求都需要由您的 Cowlendar 管理员生成的 不记名令牌 。令牌对您商店的预订和服务具有完全的读写权限。像对待密码一样对待它们:不要将它们提交给版本控制或在公共渠道中共享它们。
如何生成 API 令牌
步骤 1: 在您的 Shopify 管理员中,打开 Cowlendar 应用程序。
步骤 2: 转到 Settings > Public API 。
步骤 3: 单击“ Generate token ”。
步骤 4: 为您的令牌指定一个描述性名称,以便您以后可以识别它,例如“HubSpot sync”、“Zapier”或“Mobile app”。
步骤 5: 单击“ Generate ”。 Cowlendar 向您显示完整的令牌 仅一次 。立即复制它并将其存储在安全位置,例如密码管理器或服务器的环境变量。
您可以随时从同一页面撤销任何令牌。撤销令牌会立即停止使用它的所有 API 请求。
使用您的令牌
将令牌包含在每个 API 请求的 Authorization 标头中:
Authorization: Bearer YOUR_TOKEN_HERE
卷曲示例:
curl https://app.cowlendar.com/public-api/v1/services -H "Authorization: Bearer YOUR_TOKEN_HERE"
如果令牌丢失或无效,API 将返回 401。
API端点
基本网址:https://app.cowlendar.com
列出服务
GET /public-api/v1/services
Returns all non-archived services in your shop.在通过 API 创建预订之前,使用此端点来发现您的服务 ID、类型、持续时间、团队成员、设备和参与者类别。
查询参数:
limit(可选,1-100):每页结果数。
cursor(可选):来自先前响应的分页光标。
is_active(可选,true 或 false):按活动或非活动服务过滤。
type(可选):按服务类型过滤。值:classic-checkout、classic-no-checkout、multiday-checkout、multiday-no-checkout、multislot-checkout、multislot-no-checkout、fullday-checkout、fullday-no-checkout。
q(可选,最多 120 个字符):按标题搜索服务。
sort(可选):-id(默认,最新的在前)、id(最旧的在前)、title(A 到 Z)、-title(Z 到 A)。
请求示例:
curl "https://app.cowlendar.com/public-api/v1/services?is_active=true&limit=10" -H "Authorization: Bearer YOUR_TOKEN_HERE"
响应示例(缩短):
{
"data": [
{
"id": "6789abcdef0123456789abcd",
"title": "Haircut",
"type": "classic-checkout",
"is_active": true,
"timezone": "Europe/Paris",
"durations": [30, 45, 60],
"default_duration": 30,
"avs_type": "teammates",
"meeting_location": "in_person",
"enable_participants": false,
"participants": [],
"equipments": [],
"teammates": [
{
"id": "aaa111bbb222ccc333ddd444",
"firstname": "Marie",
"lastname": "Dupont",
"email": "[email protected]",
"thumbnail": null
}
],
"product": {
"handle": "haircut",
"title": "Haircut",
"image": "https://cdn.shopify.com/..."
},
"created_at": "2025-09-01T10:00:00.000Z",
"updated_at": "2026-05-10T08:30:00.000Z"
}
],
"pagination": {
"has_more": false,
"next_cursor": null
}
}
了解关键服务领域
avs_type 告诉您此服务如何管理可用性并确定您在创建预订时是否需要传递 teammate_id:
avs_type: "teammates"表示每个团队成员都有自己独立的日程安排。创建预订时,从 teammates 数组传递 teammate_id。如果省略它,店主将用作后备。
avs_type: "service" 表示服务本身拥有其可用性。指定的团队成员是根据预订时间自动确定的。您仍然可以传递 teammate_id 来强制分配特定人员。
avs_type: "equipment" 表示可用性是针对每台设备的。与服务模式类似,但与设备容量挂钩。
enable_participants 告诉您服务是否使用类型化的参与者类别,例如“成人”、“儿童”或“老年人”。当 true 时,participants 数组包含类别及其 ID、最小和最大数量以及默认值。创建包含详细参与者细分的预订时,您需要这些 ID。 设备 包含可预订的资源,例如房间、球场、车辆或自行车及其变体和 SKU。对于配备 tracking_type: "same" 的设备,所有单元均可互换,您可以使用任何 SKU,通常是 base。对于 tracking_type: "unique",每个单元都有自己的 SKU,您必须从 variants[].sku 中进行选择。 类型 告诉您预订模式。后缀 -checkout 或 -no-checkout 指示服务是否使用 Shopify 签出。前缀表示调度模型:单时段为classic,酒店住宿等多日为multiday,连续多时段为multislot,全天预订为fullday。
列出预订
GET /public-api/v1/bookings
返回您商店的预订。这是您用于 CRM 同步、报告导出和自定义预订仪表板的端点。
查询参数:
limit(可选,1-100):每页结果。
cursor(可选):分页光标。
start(可选,ISO 8601 日期时间):仅限在此日期或之后开始的预订。
end(可选,ISO 8601 日期时间):仅在此日期之前开始的预订。
service_id(可选,ID 数组):按一项或多项服务过滤。
subscription_id(可选,ID 数组):按订阅过滤。
status(可选,数组):confirmed、pending、declined、canceled。
attendance(可选,数组):booked、pending、arrived、started、completed、no-show、delayed、paid。
customer_email(可选):按确切的客户电子邮件过滤。
sort(可选):-id(默认,最新的在前)、id(最旧的在前)、start_date(最早的在前)、-start_date(最新的在前)。
示例:获取下周的所有已确认预订:
curl "https://app.cowlendar.com/public-api/v1/bookings?status=confirmed&start=2026-05-25T00:00:00Z&end=2026-06-01T00:00:00Z&sort=start_date" -H "Authorization: Bearer YOUR_TOKEN_HERE"
示例:查找特定客户的所有预订:
curl "https://app.cowlendar.com/public-api/v1/[email protected]" -H "Authorization: Bearer YOUR_TOKEN_HERE"
示例:导出特定服务中的所有缺席情况:
curl "https://app.cowlendar.com/public-api/v1/bookings?attendance=no-show&service_id=6789abcdef0123456789abcd" -H "Authorization: Bearer YOUR_TOKEN_HERE"
响应示例(缩短):
{
"data": [
{
"id": "abc123def456ghi789jkl012",
"booking_str": "COW-1234",
"service": {
"id": "6789abcdef0123456789abcd",
"title": "Haircut",
"type": "classic-checkout"
},
"start_date": "2026-05-27T14:00:00.000Z",
"end_date": "2026-05-27T14:30:00.000Z",
"timezone": "Europe/Paris",
"customer": {
"name": "Jane Smith",
"email": "[email protected]",
"phone": "+33612345678",
"locale": "en"
},
"form_data": {
"Special requests": "Window seat"
},
"quantity": 1,
"unit_quantity": 1,
"quantity_details": [],
"price": { "amount": 35, "currency": "EUR" },
"confirmation_status": "confirmed",
"attendance": "booked",
"financial_status": "paid",
"is_canceled": false,
"teammates": [
{
"id": "aaa111bbb222ccc333ddd444",
"firstname": "Marie",
"lastname": "Dupont"
}
],
"order_id": "gid://shopify/Order/123456789",
"subscription_id": null,
"created_at": "2026-05-20T09:15:00.000Z",
"updated_at": "2026-05-20T09:15:00.000Z"
}
],
"pagination": {
"has_more": false,
"next_cursor": null
}
}
了解关键预订字段
数量 和 单位数量 一起工作。对于理发等经典服务,quantity 是参加的顾客数量,unit_quantity 是 1。对于酒店住宿等多日服务,quantity 是房间数,unit_quantity 是住宿天数。对于多时隙服务,quantity 始终是 1,unit_quantity 是预订的时隙数。总计费单位始终为 quantity x unit_quantity。 数量_详细信息 是详细的细分。它可以包含三种类型的条目:default 用于匿名计数,participant 用于键入参与者(如“成人”或“儿童”),或 equipment 用于可预订资源(如“Court 3”)。旧预订此处可能有一个空数组。 confirmation_status 为 confirmed、pending 或 declined。某些服务需要管理员在预订生效之前进行手动确认。 出勤 跟踪客户的出勤生命周期:booked、pending、arrived、started、completed、no-show、delayed、paid。 order_id 是预订通过 Shopify 结账时的 Shopify 订单 ID。用于手动预订和 API 创建预订的 null。 subscription_id 将预订链接到订阅计划,例如 10 级通行证。
通过 API 创建预订
POST /public-api/v1/bookings
以编程方式创建预订。这被视为 手动预订 ,意味着不会创建 Shopify 订单。然而,所有常见的自动化仍然正常触发:向客户发送确认电子邮件、向团队发送通知电子邮件和短信,以及与 Google Calendar 或 Outlook 进行日历同步。
您在构建自定义预订前端、移动应用、自助服务终端或从其他系统导入预订时使用此端点。
必填字段:
service_id(字符串):服务的 ID,您从列表服务中获取。
start_date(ISO 8601 日期时间):预订开始时。
end_date(ISO 8601日期时间):预订结束时。
timezone(字符串):IANA 时区,例如 Europe/Paris、America/New_York、Asia/Tokyo。
customer(对象):必须至少包含email或phone。它还可以包括 name、firstname、lastname 和 locale,这是客户通知电子邮件的语言代码。
可选字段:
quantity(整数,默认1):预订的顶级单元。如果提供了 quantity_details,则忽略。
unit_quantity(整数,默认 1):每个顶级单元的子单元。
quantity_details(数组):按参与者类型或设备详细分类。如果提供,quantity 会自动计算为总和。
teammate_id(字符串):强制分配特定团队成员。
subscription_id(字符串):将此预订链接到现有订阅并扣除一个积分。
form_data(对象):预订表单中的自定义键或值对。
price(数字,默认 0):预订的净总价。
currency(字符串):ISO 4217 代码,如 USD、EUR 或 GBP。默认为您商店的货币。
示例:创建一个简单的预订
一位顾客与特定造型师预订了 30 分钟的理发服务:
curl -X POST https://app.cowlendar.com/public-api/v1/bookings -H "Authorization: Bearer YOUR_TOKEN_HERE" -H "Content-Type: application/json" -d '{
"service_id": "6789abcdef0123456789abcd",
"start_date": "2026-06-01T10:00:00.000Z",
"end_date": "2026-06-01T10:30:00.000Z",
"timezone": "Europe/Paris",
"customer": {
"email": "[email protected]",
"name": "John Doe",
"phone": "+33612345678",
"locale": "en"
},
"teammate_id": "aaa111bbb222ccc333ddd444",
"quantity": 1,
"price": 35,
"currency": "EUR"
}'
Cowlendar 创建预订并为客户和团队成员触发确认电子邮件、短信和日历邀请。
示例:与键入的参与者进行团体预订
一家人预订导游:3名成人和2名儿童,不同价位:
curl -X POST https://app.cowlendar.com/public-api/v1/bookings -H "Authorization: Bearer YOUR_TOKEN_HERE" -H "Content-Type: application/json" -d '{
"service_id": "6789abcdef0123456789abcd",
"start_date": "2026-06-15T09:00:00.000Z",
"end_date": "2026-06-15T11:00:00.000Z",
"timezone": "America/New_York",
"customer": {
"email": "[email protected]",
"firstname": "Sarah",
"lastname": "Miller",
"phone": "+15551234567",
"locale": "en"
},
"quantity_details": [
{
"type": "participant",
"name": "Adult",
"quantity": 3,
"participant_id": "adult_id_from_service"
},
{
"type": "participant",
"name": "Child (under 12)",
"quantity": 2,
"participant_id": "child_id_from_service"
}
],
"price": 175,
"currency": "USD"
}'
participant_id 值来自列表服务响应中服务的 participants[] 数组。总 quantity 自动设置为 5 (3 + 2)。
示例:使用设备预订
客户预订网球场1小时:
curl -X POST https://app.cowlendar.com/public-api/v1/bookings -H "Authorization: Bearer YOUR_TOKEN_HERE" -H "Content-Type: application/json" -d '{
"service_id": "6789abcdef0123456789abcd",
"start_date": "2026-06-10T16:00:00.000Z",
"end_date": "2026-06-10T17:00:00.000Z",
"timezone": "Europe/London",
"customer": {
"email": "[email protected]",
"name": "Tom Wilson"
},
"quantity_details": [
{
"type": "equipment",
"name": "Court 3",
"quantity": 1,
"equipment_id": "eee555fff666ggg777hhh888",
"equipment_sku": "COURT3",
"capacity": 4
}
],
"price": 25,
"currency": "GBP"
}'
equipment_id 和 equipment_sku 来自服务的 equipments[] 阵列。对于配备 tracking_type: "same" 的设备,可使用任何 SKU,通常是 base。对于 tracking_type: "unique",请使用适合您所需装置的特定 variants[].sku。
示例:订阅链接预订
瑜伽馆会员可使用其每月 10 节课程通行证中的一个积分:
curl -X POST https://app.cowlendar.com/public-api/v1/bookings -H "Authorization: Bearer YOUR_TOKEN_HERE" -H "Content-Type: application/json" -d '{
"service_id": "6789abcdef0123456789abcd",
"start_date": "2026-06-05T08:00:00.000Z",
"end_date": "2026-06-05T09:00:00.000Z",
"timezone": "America/Los_Angeles",
"customer": {
"email": "[email protected]",
"name": "Lisa Chen",
"locale": "en"
},
"subscription_id": "fff000eee111ddd222ccc333",
"price": 0
}'
订阅必须是active,属于同一服务,并且有remaining_credits > 0。 Cowlendar 自动减少信用计数并向客户发送订阅更新电子邮件。
错误代码
400 验证错误。必填字段缺失或格式错误。错误正文告诉您哪个字段。
401 令牌丢失或无效。
403 商店处于非活动状态或访问受到限制。
404 未找到服务。
422 预订被拒绝。时间段已被占用、团队成员无法使用、设备已满或订阅没有剩余积分。具体原因请查看错误信息。
429 超出速率限制。间隔您的请求并稍后重试。
分页
所有列表端点都使用基于光标的分页。当响应包含 "has_more": true 时,将 next_cursor 值作为 cursor 参数传递到下一个请求中:
curl "https://app.cowlendar.com/public-api/v1/bookings?cursor=eyJpZCI6IjY3ODlhYmNkIn0=&limit=50" -H "Authorization: Bearer YOUR_TOKEN_HERE"
排序顺序在页面之间保留。最大页面大小为 100 个结果。
Webhooks:实时预订通知
API 允许您按需提取数据,而 Webhook 可以立即将数据推送给您。每次创建、确认、取消或重新安排预订时,Cowlendar 都会将签名的 HTTP POST 发送到您配置的 URL。
Webhooks 对于构建实时集成至关重要:CRM 同步、Slack 通知、自动电子邮件序列、实时仪表板或任何需要对预订事件发生时做出反应的工作流程。
设置 Webhook 端点
步骤 1: 在您的 Shopify 管理员中,打开 Cowlendar 应用程序。
步骤 2: 转到 Settings > Webhooks 。
步骤 3: 单击“ Add endpoint ”。
步骤 4: 输入端点的名称,例如“HubSpot CRM”、“Zapier”或“Analytics pipeline”。
步骤 5: 粘贴您的 HTTPS URL 。 URL 必须使用 HTTPS。如果您使用的是 Zapier 或 Make,请粘贴它们提供的 Webhook URL。
步骤 6: 检查您想要接收的事件。您可以选择任何组合。
步骤 7: 单击“ Create ”。
Cowlendar 显示以 whsec_ 开头的 签名秘密 。立即复制并安全保存。此秘密仅显示一次,您需要它来验证服务器上传入的 Webhook 请求。
您可以稍后编辑任何端点以更改 URL 或启用或禁用特定事件:
8 个 Webhook 事件
booking.created 当从任何来源创建新预订时触发:店面小部件、管理面板、POS 或公共 API。 booking.confirmed 当管理员手动确认待处理的预订时触发。 booking.declined 当待处理的预订被拒绝时触发。 booking.canceled 当客户或管理员取消预订时触发。 booking.rescheduled 当预订日期或分配的团队成员更改时触发。 booking.attendance_changed 当出勤状态更改时触发,例如从“已预订”到“已完成”或标记为“缺席”时。 subscription.created 在创建新的定期订阅时触发。 subscription.billing_failed 当订阅计费尝试失败时触发。连续3次失败后,Shopify上的认购合约自动取消,本地状态变为canceled。
Webhook 负载是什么样子的
每个 Webhook 传递都是带有 JSON 正文的 HTTP POST。这是一个完整的 booking.created 示例:
{
"id": "evt_2b86f80a-1c3d-4e5f-9a8b-7c6d5e4f3a2b",
"type": "booking.created",
"created_at": "2026-05-20T09:15:00.000Z",
"shop_domain": "yourshop.myshopify.com",
"data": {
"id": "abc123def456ghi789jkl012",
"booking_str": "COW-1234",
"service": {
"id": "6789abcdef0123456789abcd",
"title": "Haircut",
"type": "classic-checkout"
},
"start_date": "2026-05-27T14:00:00.000Z",
"end_date": "2026-05-27T14:30:00.000Z",
"timezone": "Europe/Paris",
"customer": {
"name": "Jane Smith",
"email": "[email protected]",
"phone": "+33612345678",
"locale": "en"
},
"form_data": {},
"quantity": 1,
"unit_quantity": 1,
"quantity_details": [],
"price": { "amount": 35, "currency": "EUR" },
"confirmation_status": "confirmed",
"attendance": "booked",
"financial_status": null,
"is_canceled": false,
"teammates": [
{
"id": "aaa111bbb222ccc333ddd444",
"firstname": "Marie",
"lastname": "Dupont"
}
],
"order_id": null,
"subscription_id": null,
"created_at": "2026-05-20T09:15:00.000Z",
"updated_at": "2026-05-20T09:15:00.000Z"
}
}
data 字段包含完整的预订或订阅对象,其结构与 API 响应完全相同。
对于 subscription.billing_failed 事件,负载包括一个额外的 previous 对象以及当前尝试之前的 failure_count,因此您可以跟踪升级情况,例如在第二次失败后发送紧急电子邮件。
每个 Webhook 传递的请求标头
X-Cowlendar-Event-Id 是事件的唯一 ID。 Cowlendar 在重试失败的传递时重复使用相同的 ID。使用它在您这边进行重复数据删除。
X-Cowlendar-Event-Type 是事件类型字符串,例如 booking.created。
X-Cowlendar-Timestamp 是 Cowlendar 签署请求时的 Unix 时间戳(以秒为单位)。
X-Cowlendar-Signature 是 t=<timestamp>,v1=<hex> 格式的 HMAC-SHA256 签名。
验证 webhook 签名
每个 Webhook 请求都经过签名,因此您可以确认它确实来自 Cowlendar 并且未被篡改。使用端点的签名密钥将签名计算为 HMAC-SHA256(secret, timestamp + "." + raw_body)。
您还应该拒绝时间戳早于 5 分钟的请求,以防止重放攻击。
Node.js(Express):
import crypto from "crypto";
import express from "express";
const app = express();
app.post(
"/webhooks/cowlendar",
express.raw({ type: "application/json" }),
(req, res) => {
const sigHeader =
req.header("X-Cowlendar-Signature") || "";
const timestamp =
req.header("X-Cowlendar-Timestamp") || "";
const rawBody = req.body.toString("utf8");
// Reject requests older than 5 minutes
if (
Math.abs(Date.now() / 1000 - parseInt(timestamp, 10))
> 300
) {
return res.status(400).send("Timestamp too old");
}
const expected = crypto
.createHmac(
"sha256",
process.env.COWLENDAR_WEBHOOK_SECRET
)
.update(`${timestamp}.${rawBody}`)
.digest("hex");
const received = sigHeader
.split(",")
.find((p) => p.startsWith("v1="))
?.slice(3);
if (
!received ||
!crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(received)
)
) {
return res.status(401).send("Invalid signature");
}
const event = JSON.parse(rawBody);
// Short-circuit test pings
if (event.type === "webhook.ping") {
return res.status(200).send("pong");
}
// Handle real events here
res.status(200).send("ok");
}
);
Python(烧瓶):
import hmac, hashlib, os, time, json
from flask import Flask, request
app = Flask(__name__)
@app.post("/webhooks/cowlendar")
def cowlendar_webhook():
sig_header = request.headers.get(
"X-Cowlendar-Signature", ""
)
timestamp = request.headers.get(
"X-Cowlendar-Timestamp", ""
)
raw_body = request.get_data(as_text=True)
# Reject requests older than 5 minutes
if abs(time.time() - int(timestamp)) > 300:
return "Timestamp too old", 400
expected = hmac.new(
os.environ["COWLENDAR_WEBHOOK_SECRET"].encode(),
f"{timestamp}.{raw_body}".encode(),
hashlib.sha256,
).hexdigest()
received = next(
(p[3:] for p in sig_header.split(",")
if p.startswith("v1=")),
None,
)
if not received or not hmac.compare_digest(
expected, received
):
return "Invalid signature", 401
event = json.loads(raw_body)
if event["type"] == "webhook.ping":
return "pong", 200
# Handle real events here
return "ok", 200
PHP:
<?php
$secret = getenv("COWLENDAR_WEBHOOK_SECRET");
$rawBody = file_get_contents("php://input");
$sigHeader = $_SERVER["HTTP_X_COWLENDAR_SIGNATURE"] ?? "";
$timestamp = $_SERVER["HTTP_X_COWLENDAR_TIMESTAMP"] ?? "";
// Reject requests older than 5 minutes
if (abs(time() - (int)$timestamp) > 300) {
http_response_code(400);
exit("Timestamp too old");
}
$expected = hash_hmac(
"sha256",
$timestamp . "." . $rawBody,
$secret
);
$received = null;
foreach (explode(",", $sigHeader) as $part) {
if (str_starts_with($part, "v1=")) {
$received = substr($part, 3);
break;
}
}
if (!$received || !hash_equals($expected, $received)) {
http_response_code(401);
exit("Invalid signature");
}
$event = json_decode($rawBody, true);
if ($event["type"] === "webhook.ping") {
http_response_code(200);
exit("pong");
}
// Handle real events here
http_response_code(200);
echo "ok";
上线前测试您的 webhook
每个 Webhook 端点在管理中都有一个 Test 按钮。单击它会将合成的 webhook.ping 事件发送到您的 URL。此事件使用与真实事件相同的签名、标头和重试行为,但具有无害的测试负载:
{
"id": "evt_2b86f80a...",
"type": "webhook.ping",
"created_at": "2026-05-13T14:57:57.704Z",
"shop_domain": "yourshop.myshopify.com",
"data": {
"message": "This is a test event from Cowlendar. If you can read this, your endpoint is reachable."
}
}
使用它来确认 Cowlendar 可以到达您的 URL,DNS、HTTPS 和防火墙设置正常工作,并验证您的 HMAC 签名验证码 无需创建真正的预订 。真正的预订会向客户发送电子邮件、创建日历事件,并可能触发 Shopify 订单。
单击测试后,检查 See deliveries 按钮以查看端点返回的 HTTP 状态代码。绿色的 200 表示一切正常。
重试行为并自动禁用
如果您的终端返回 5xx 错误、429 或网络超时,Cowlendar 将按以下计划重试:
1分钟后、5分钟后、25分钟后、2小时后、10小时后、50小时后。总共 6 次尝试,持续大约 3 天。
在所有事件中连续大约 20 次失败后,端点将自动禁用,并且 Cowlendar 会向店主发送电子邮件。服务器重新上线后,您可以从 Settings > Webhooks 重新启用端点。
重试时会重复使用相同的 X-Cowlendar-Event-Id。始终存储已处理的事件 ID 并跳过重复项。
任何 2xx 响应均视为成功。您不需要返回特定的正文或内容类型。
Webhook 最佳实践
在 10 秒内响应。 如果您的处理程序需要执行繁重的工作,例如调用另一个 API、写入数据库或运行复杂的操作,请异步执行。立即使用 200 接受 Webhook,然后在后台作业或队列中处理它。 使用事件 ID 进行重复数据删除。 存储您处理的每个 X-Cowlendar-Event-Id。如果您再次收到相同的 ID,请跳过它。 Cowlendar 失败时使用相同的 ID 重试。 对签名使用常量时间比较。 Node.js 中为 crypto.timingSafeEqual,Python 中为 hmac.compare_digest,PHP 中为 hash_equals。像 === 这样的常规字符串比较很容易受到定时攻击。 请勿从您这边重试。 Cowlendar 自动处理重试。如果您的服务器出现临时问题,请返回 5xx,Cowlendar 将按其重试计划恢复。 显式处理 webhook.ping。 针对 ping 事件立即返回 200。这使您可以使用“测试”按钮,而无需触发业务逻辑。
目前的限制
通过 API 创建的预订是手动预订。 它们不会创建 Shopify 订单。如果您的服务通常使用 Shopify 结帐,则 API 会绕过它。确认电子邮件、短信和日历同步仍然正常工作。 尚无可用性端点。 当前的 API 允许您读取服务和预订,以及创建预订。它不公开可用的时间段。要检查时间段是否可用,请尝试创建预订并在该时间段已被占用时处理 422 响应。未来的更新中可能会添加可用性端点。 尚无更新或删除端点。 您可以创建和读取预订,但无法通过 API 更新、重新安排或取消它们。目前通过 Cowlendar 管理员管理这些操作。 适用速率限制。 如果您在短时间内发送过多请求,API 将返回 429。对于导出所有预订等批量操作,请在分页请求之间添加短暂的延迟,例如 200 到 500 毫秒。 Webhook 机密仅显示一次。 如果您丢失了签名机密,请删除端点并创建一个新端点以获取新的机密。 Webhook 需要 HTTPS。 不接受 HTTP 端点。
常见问题解答
我可以在不编写代码的情况下将 Cowlendar API 与 Zapier 或 Make 一起使用吗?
是的。对于 Webhook,从 Cowlendar 接收事件,在 Zapier 或 Make 中创建 "Custom Webhook" 触发器,复制它们为您提供的 URL,并将其添加为 Cowlendar Settings > Webhooks 中的端点。每个预订事件都会触发您的自动化。对于 API,向 Cowlendar 发送请求,使用 Zapier 或 Make 中的 "HTTP Request" 操作使用您的不记名令牌调用任何 Cowlendar API 端点。
通过 API 创建的预订是否会向客户发送电子邮件?
是的。 API 创建的预订的处理方式与手动预订完全相同。确认电子邮件、短信通知和日历同步都会自动触发,就像通过管理面板进行预订一样。
如果我的 webhook 端点出现故障会发生什么?
Cowlendar 在大约 3 天内重试失败的交付 6 次。连续大约 20 次失败后,端点将自动禁用,并且您会收到一封电子邮件。服务器恢复后,从 Settings > Webhooks 重新启用它。
我可以有多个 Webhook 端点吗?
是的。根据需要创建任意多个,每个都有不同的事件选择和 URL。例如,您的 CRM 的一个端点用于侦听 booking.created 和 booking.canceled,另一个端点用于您的 analytics pipeline 侦听所有事件。
我可以撤销 API 令牌吗? 是的。转到 Settings > Public API 并单击 Revoke 按钮。令牌立即停止工作。 是否有沙箱或暂存环境?
目前还没有。使用 webhook.ping 测试按钮验证您的 Webhook 设置,而无需创建实际预订。对于 API 测试,我们建议在您的 Cowlendar 管理员中创建一个仅用于开发的测试服务。
完整的 API 参考在哪里?
包含所有架构、参数和响应示例的交互式 API 文档位于 https://app.cowlendar.com/public-api/docs