# Zen Planner API

> Every Zen Planner endpoint on Cotlet: inputs, JSON Schema, cURL, Python and Node.js examples and an example response for each call.

Source: https://cotlet.dev/docs/api/zen-planner

Docs sections: [Get started](https://cotlet.dev/docs.md) · [REST API](https://cotlet.dev/docs/api.md) · [MCP](https://cotlet.dev/docs/mcp.md) · [SDKs & CLI](https://cotlet.dev/docs/sdks.md) · [Integrations](https://cotlet.dev/docs/integrations.md)

14 endpoints for Zen Planner. Each one is a POST with a JSON body, called with your API key.

- Base URL: `https://cotlet.dev/api/v1/zen-planner`
- Connects with: Your own Zen Planner Studio staff account (the role must be allowed to see members, billing and reports)
- Integration page: https://cotlet.dev/integrations/zen-planner-api-mcp-server

## Endpoints

| Endpoint | Access | Description |
|---|---|---|
| `list_members` | read | People in your studio with status, email, phone and memberships. |
| `get_member` | read | Full profile: contact details, memberships and family members. |
| `list_classes` | read | Class schedule with time, instructor, capacity and open spots. |
| `get_class_roster` | read | Who reserved and who checked in for one class. |
| `list_attendance` | read | A member's class check-ins in a date range, newest first. |
| `list_prospects` | read | Leads with source, status and date added. |
| `list_failed_payments` | read | Payments that failed, with member, amount, date and reason. |
| `get_revenue_report` | read | Revenue for a period, grouped by membership type, class, instructor, location or retail. |
| `book_class` | write | Reserve a spot in a class for a member. |
| `cancel_reservation` | write | Cancel a member's class reservation. |
| `check_in_member` | write | Record that a member attended a class. |
| `create_prospect` | write | Add a lead with contact details and source. |
| `enroll_in_membership` | write | Add a membership to a member. Billing follows the membership type. |
| `promote_rank` | write | Move a student to their next belt or rank. |

## List members

`POST https://cotlet.dev/api/v1/zen-planner/list_members`

Access: read.

Lists people in your studio, filtered by name or email, status or last change date. Each item has a person_id, contact details and the names of their active memberships. Pages hold up to 200 people; pass next_cursor back as cursor for the next page.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `query` | string | no | Name or email to search for. |
| `status` | enum | no | member, prospect, alumni or all. Default: member. |
| `modified_after` | date | no | Only people changed on or after this date. |
| `limit` | integer | no | 1 to 200. Default: 50. |
| `cursor` | string | no | Next page cursor from the previous call. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/zen-planner/list_members \
  -H "Authorization: Bearer $COTLET_API_KEY"
```

**Python**

```python
result = client.call("zen-planner", "list_members")
```

**Node.js**

```js
const result = await cotlet.call('zen-planner', 'list_members');
```

**CLI**

```bash
cotlet call zen-planner list_members
```

### Example response

```json
{
  "members": [
    {
      "person_id": "p253ac9b9",
      "name": "Sarah Lee",
      "status": "member",
      "email": "sarah.lee@example.com",
      "phone": "+1 555 0142",
      "memberships": [
        "Unlimited Monthly"
      ]
    }
  ],
  "next_cursor": null
}
```

## Get member

`POST https://cotlet.dev/api/v1/zen-planner/get_member`

Access: read.

Returns one person with contact details, their memberships with start dates and the family members linked to the account. Use it to get a phone number or email before contacting someone.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `person_id` | string | yes | Person ID from list_members. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/zen-planner/get_member \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"person_id":"person_8c41d2"}'
```

**Python**

```python
result = client.call("zen-planner", "get_member", {"person_id":"person_8c41d2"})
```

**Node.js**

```js
const result = await cotlet.call('zen-planner', 'get_member', {"person_id":"person_8c41d2"});
```

**CLI**

```bash
cotlet call zen-planner get_member --data '{"person_id":"person_8c41d2"}'
```

### Example response

```json
{
  "person_id": "p253ac9b9",
  "name": "Sarah Lee",
  "email": "sarah.lee@example.com",
  "phone": "+1 555 0142",
  "memberships": [
    {
      "membership_id": "ms_3310",
      "type": "Unlimited Monthly",
      "start_date": "2026-03-01"
    }
  ],
  "family": []
}
```

## List classes

`POST https://cotlet.dev/api/v1/zen-planner/list_classes`

Access: read.

Returns the classes in a date range in start order, each with class_id, time, instructor, capacity and open spots. Filter by location or program to narrow the list. Use class_id with book_class and get_class_roster.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `from` | date | yes | First day. |
| `to` | date | no | Last day. Default: same as from. |
| `location_id` | string | no | Only classes at this location. |
| `program_id` | string | no | Only classes of this program. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/zen-planner/list_classes \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"from":"2026-10-01"}'
```

**Python**

```python
result = client.call("zen-planner", "list_classes", {"from":"2026-10-01"})
```

**Node.js**

```js
const result = await cotlet.call('zen-planner', 'list_classes', {"from":"2026-10-01"});
```

**CLI**

```bash
cotlet call zen-planner list_classes --data '{"from":"2026-10-01"}'
```

### Example response

```json
{
  "classes": [
    {
      "class_id": "c7e2a91f",
      "name": "CrossFit WOD",
      "starts_at": "2026-10-12T06:00:00-04:00",
      "instructor": "Coach Alex",
      "capacity": 12,
      "open_spots": 4
    }
  ]
}
```

## Get class roster

`POST https://cotlet.dev/api/v1/zen-planner/get_class_roster`

Access: read.

Returns the people who reserved one class, each with a reservation_id and whether they are checked in. Use reservation_id with cancel_reservation and person_id with check_in_member.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `class_id` | string | yes | Class ID from list_classes. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/zen-planner/get_class_roster \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"class_id":"class_8c41d2"}'
```

**Python**

```python
result = client.call("zen-planner", "get_class_roster", {"class_id":"class_8c41d2"})
```

**Node.js**

```js
const result = await cotlet.call('zen-planner', 'get_class_roster', {"class_id":"class_8c41d2"});
```

**CLI**

```bash
cotlet call zen-planner get_class_roster --data '{"class_id":"class_8c41d2"}'
```

### Example response

```json
{
  "class_id": "c4d8b1e0",
  "name": "Kids Karate",
  "starts_at": "2026-10-11T09:00:00-04:00",
  "roster": [
    {
      "reservation_id": "r_5501",
      "person_id": "p253ac9b9",
      "name": "Ava Lee",
      "checked_in": false
    },
    {
      "reservation_id": "r_5502",
      "person_id": "p77a1d03e",
      "name": "Sam Ortiz",
      "checked_in": false
    }
  ]
}
```

## List attendance

`POST https://cotlet.dev/api/v1/zen-planner/list_attendance`

Access: read.

Returns the classes one person checked into between two dates, newest first. An empty list means no visits in that range. Run it once per person.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `person_id` | string | yes | Person ID from list_members. |
| `from` | date | no | Start date. Default: 30 days ago. |
| `to` | date | no | End date. Default: today. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/zen-planner/list_attendance \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"person_id":"p253ac9b9","from":"2026-08-13","to":"2026-10-11"}'
```

**Python**

```python
result = client.call("zen-planner", "list_attendance", {"person_id":"p253ac9b9","from":"2026-08-13","to":"2026-10-11"})
```

**Node.js**

```js
const result = await cotlet.call('zen-planner', 'list_attendance', {"person_id":"p253ac9b9","from":"2026-08-13","to":"2026-10-11"});
```

**CLI**

```bash
cotlet call zen-planner list_attendance --data '{"person_id":"p253ac9b9","from":"2026-08-13","to":"2026-10-11"}'
```

### Example response

```json
{
  "person_id": "p253ac9b9",
  "attendance": [
    {
      "class_id": "c3a90b12",
      "name": "CrossFit WOD",
      "checked_in_at": "2026-10-07T06:02:00-04:00"
    }
  ]
}
```

## List prospects

`POST https://cotlet.dev/api/v1/zen-planner/list_prospects`

Access: read.

Lists prospects in your studio, newest first, filtered by status, source or date added. Status values are the ones set up in your studio. Use it to skip leads that already exist before create_prospect.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `status` | string | no | Prospect status as set up in your studio. |
| `source` | string | no | Lead source, e.g. Website or Walk-in. |
| `since` | date | no | Only prospects added on or after this date. |
| `cursor` | string | no | Next page cursor from the previous call. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/zen-planner/list_prospects \
  -H "Authorization: Bearer $COTLET_API_KEY"
```

**Python**

```python
result = client.call("zen-planner", "list_prospects")
```

**Node.js**

```js
const result = await cotlet.call('zen-planner', 'list_prospects');
```

**CLI**

```bash
cotlet call zen-planner list_prospects
```

### Example response

```json
{
  "prospects": [
    {
      "person_id": "p9be2c71a",
      "name": "Dana Ortiz",
      "source": "Open house",
      "status": "New",
      "added_on": "2026-10-09"
    }
  ],
  "next_cursor": null
}
```

## List failed payments

`POST https://cotlet.dev/api/v1/zen-planner/list_failed_payments`

Access: read.

Returns the payments Zen Planner marks as failed in a date range, newest first, with member, amount, date and the reason shown in the report. It is not the past-due total, which Zen Planner counts separately. The total is the sum of the listed amounts.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `from` | date | no | Start date. Default: 7 days ago. |
| `to` | date | no | End date. Default: today. |
| `location_id` | string | no | Only this location. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/zen-planner/list_failed_payments \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"from":"2026-10-05","to":"2026-10-11"}'
```

**Python**

```python
result = client.call("zen-planner", "list_failed_payments", {"from":"2026-10-05","to":"2026-10-11"})
```

**Node.js**

```js
const result = await cotlet.call('zen-planner', 'list_failed_payments', {"from":"2026-10-05","to":"2026-10-11"});
```

**CLI**

```bash
cotlet call zen-planner list_failed_payments --data '{"from":"2026-10-05","to":"2026-10-11"}'
```

### Example response

```json
{
  "payments": [
    {
      "person_id": "p253ac9b9",
      "name": "Sarah Lee",
      "amount": 129,
      "date": "2026-10-08",
      "reason": "Card declined"
    },
    {
      "person_id": "p41c7f0d2",
      "name": "Marcus Webb",
      "amount": 89,
      "date": "2026-10-06",
      "reason": "Expired card"
    }
  ],
  "total": 218,
  "currency": "USD"
}
```

## Get revenue report

`POST https://cotlet.dev/api/v1/zen-planner/get_revenue_report`

Access: read.

Returns revenue for one date range as Zen Planner reports it, grouped the way you choose. One call covers one period; compare two months with two calls. The total is the sum of the groups.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `from` | date | yes | Start date. |
| `to` | date | yes | End date. |
| `group_by` | enum | no | membership_type, class, instructor, location or retail. Default: membership_type. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/zen-planner/get_revenue_report \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"from":"2026-10-01","to":"2026-10-01"}'
```

**Python**

```python
result = client.call("zen-planner", "get_revenue_report", {"from":"2026-10-01","to":"2026-10-01"})
```

**Node.js**

```js
const result = await cotlet.call('zen-planner', 'get_revenue_report', {"from":"2026-10-01","to":"2026-10-01"});
```

**CLI**

```bash
cotlet call zen-planner get_revenue_report --data '{"from":"2026-10-01","to":"2026-10-01"}'
```

### Example response

```json
{
  "from": "2026-09-01",
  "to": "2026-09-30",
  "group_by": "membership_type",
  "groups": [
    {
      "name": "Unlimited Monthly",
      "revenue": 18450
    },
    {
      "name": "3x Week",
      "revenue": 9200
    },
    {
      "name": "Drop-in",
      "revenue": 1350
    }
  ],
  "total": 29000,
  "currency": "USD"
}
```

## Book class

`POST https://cotlet.dev/api/v1/zen-planner/book_class`

Access: write. Confirm: waits for the user's OK before it runs.

Reserves one spot in one class for one member and returns a reservation_id. The member is booked as your staff account does it in Zen Planner Studio. By default you confirm each call; you can switch that off for this tool.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `class_id` | string | yes | Class ID from list_classes. |
| `person_id` | string | yes | Person ID from list_members. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/zen-planner/book_class \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"class_id":"c7e2a91f","person_id":"p253ac9b9"}'
```

**Python**

```python
result = client.call("zen-planner", "book_class", {"class_id":"c7e2a91f","person_id":"p253ac9b9"})
```

**Node.js**

```js
const result = await cotlet.call('zen-planner', 'book_class', {"class_id":"c7e2a91f","person_id":"p253ac9b9"});
```

**CLI**

```bash
cotlet call zen-planner book_class --data '{"class_id":"c7e2a91f","person_id":"p253ac9b9"}'
```

### Example response

```json
{
  "reservation_id": "r_5510",
  "status": "reserved",
  "class": {
    "name": "CrossFit WOD",
    "starts_at": "2026-10-12T06:00:00-04:00",
    "instructor": "Coach Alex"
  },
  "open_spots_left": 3
}
```

## Cancel reservation

`POST https://cotlet.dev/api/v1/zen-planner/cancel_reservation`

Access: write. Confirm: waits for the user's OK before it runs.

Cancels one reservation, which frees the spot. Get reservation_id from get_class_roster or book_class. By default you confirm each call; you can switch that off for this tool.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `class_id` | string | yes | Class ID from list_classes. |
| `reservation_id` | string | yes | Reservation ID from get_class_roster. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/zen-planner/cancel_reservation \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"class_id":"class_8c41d2","reservation_id":"reservation_8c41d2"}'
```

**Python**

```python
result = client.call("zen-planner", "cancel_reservation", {"class_id":"class_8c41d2","reservation_id":"reservation_8c41d2"})
```

**Node.js**

```js
const result = await cotlet.call('zen-planner', 'cancel_reservation', {"class_id":"class_8c41d2","reservation_id":"reservation_8c41d2"});
```

**CLI**

```bash
cotlet call zen-planner cancel_reservation --data '{"class_id":"class_8c41d2","reservation_id":"reservation_8c41d2"}'
```

### Example response

```json
{
  "reservation_id": "r_5510",
  "status": "cancelled"
}
```

## Check in member

`POST https://cotlet.dev/api/v1/zen-planner/check_in_member`

Access: write. Confirm: waits for the user's OK before it runs.

Checks one member into one class, which adds a visit to their attendance. By default you confirm each call; you can switch that off for this tool.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `class_id` | string | yes | Class ID from list_classes. |
| `person_id` | string | yes | Person ID from list_members. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/zen-planner/check_in_member \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"class_id":"class_8c41d2","person_id":"person_8c41d2"}'
```

**Python**

```python
result = client.call("zen-planner", "check_in_member", {"class_id":"class_8c41d2","person_id":"person_8c41d2"})
```

**Node.js**

```js
const result = await cotlet.call('zen-planner', 'check_in_member', {"class_id":"class_8c41d2","person_id":"person_8c41d2"});
```

**CLI**

```bash
cotlet call zen-planner check_in_member --data '{"class_id":"class_8c41d2","person_id":"person_8c41d2"}'
```

### Example response

```json
{
  "class_id": "c4d8b1e0",
  "person_id": "p253ac9b9",
  "status": "checked_in",
  "checked_in_at": "2026-10-11T09:04:00-04:00"
}
```

## Create prospect

`POST https://cotlet.dev/api/v1/zen-planner/create_prospect`

Access: write. Confirm: waits for the user's OK before it runs.

Adds one prospect and returns its person_id. If your studio has lead follow-up workflows set up in Zen Planner, a new prospect can start them. By default you confirm each call; you can switch that off for this tool.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `first_name` | string | yes | First name. |
| `last_name` | string | yes | Last name. |
| `email` | string | no | Email address. |
| `phone` | string | no | Phone number. |
| `source` | string | no | Lead source, e.g. Open house. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/zen-planner/create_prospect \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"first_name":"Dana","last_name":"Ortiz","email":"dana.ortiz@example.com","phone":"+1 555 0163","source":"Open house"}'
```

**Python**

```python
result = client.call("zen-planner", "create_prospect", {"first_name":"Dana","last_name":"Ortiz","email":"dana.ortiz@example.com","phone":"+1 555 0163","source":"Open house"})
```

**Node.js**

```js
const result = await cotlet.call('zen-planner', 'create_prospect', {"first_name":"Dana","last_name":"Ortiz","email":"dana.ortiz@example.com","phone":"+1 555 0163","source":"Open house"});
```

**CLI**

```bash
cotlet call zen-planner create_prospect --data '{"first_name":"Dana","last_name":"Ortiz","email":"dana.ortiz@example.com","phone":"+1 555 0163","source":"Open house"}'
```

### Example response

```json
{
  "person_id": "p9be2c71a",
  "status": "created",
  "name": "Dana Ortiz",
  "source": "Open house"
}
```

## Enroll in membership

`POST https://cotlet.dev/api/v1/zen-planner/enroll_in_membership`

Access: write. Confirm: waits for the user's OK before it runs.

Adds a membership to a member from a given start date. Billing then follows the terms of that membership type in your studio, so this reaches money. By default you confirm each call; you can switch that off for this tool.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `person_id` | string | yes | Person ID from list_members. |
| `membership_type_id` | string | yes | Membership type, e.g. Unlimited Monthly. |
| `start_date` | date | no | Default: today. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/zen-planner/enroll_in_membership \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"person_id":"person_8c41d2","membership_type_id":"membership_type_8c41d2"}'
```

**Python**

```python
result = client.call("zen-planner", "enroll_in_membership", {"person_id":"person_8c41d2","membership_type_id":"membership_type_8c41d2"})
```

**Node.js**

```js
const result = await cotlet.call('zen-planner', 'enroll_in_membership', {"person_id":"person_8c41d2","membership_type_id":"membership_type_8c41d2"});
```

**CLI**

```bash
cotlet call zen-planner enroll_in_membership --data '{"person_id":"person_8c41d2","membership_type_id":"membership_type_8c41d2"}'
```

### Example response

```json
{
  "membership_id": "ms_4402",
  "person_id": "p253ac9b9",
  "type": "Unlimited Monthly",
  "start_date": "2026-10-12",
  "status": "active"
}
```

## Promote rank

`POST https://cotlet.dev/api/v1/zen-planner/promote_rank`

Access: write. Confirm: waits for the user's OK before it runs.

Records a new rank for a student from your own rank structure, as in Zen Planner's belt and skill tracking. By default you confirm each call; you can switch that off for this tool.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `person_id` | string | yes | Person ID from list_members. |
| `rank` | string | yes | New rank name from your rank structure. |
| `promoted_on` | date | no | Promotion date. Default: today. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/zen-planner/promote_rank \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"person_id":"person_8c41d2","rank":"rank"}'
```

**Python**

```python
result = client.call("zen-planner", "promote_rank", {"person_id":"person_8c41d2","rank":"rank"})
```

**Node.js**

```js
const result = await cotlet.call('zen-planner', 'promote_rank', {"person_id":"person_8c41d2","rank":"rank"});
```

**CLI**

```bash
cotlet call zen-planner promote_rank --data '{"person_id":"person_8c41d2","rank":"rank"}'
```

### Example response

```json
{
  "person_id": "p77a1d03e",
  "rank": "Yellow Belt",
  "promoted_on": "2026-10-11",
  "status": "promoted"
}
```
