Back to skills
SkillHub ClubAnalyze Data & AIFull StackData / AI
ai-meeting-scheduling
Imported from https://github.com/openclaw/skills.
Packaged view
This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.
Stars
3,087
Hot score
99
Updated
March 20, 2026
Overall rating
C4.0
Composite score
4.0
Best-practice grade
F17.6
Install command
npx @skill-hub/cli install openclaw-skills-ai-meeting-scheduling
Repository
openclaw/skills
Skill path: skills/dheerg/ai-meeting-scheduling
Imported from https://github.com/openclaw/skills.
Open repositoryBest for
Primary workflow: Analyze Data & AI.
Technical facets: Full Stack, Data / AI.
Target audience: everyone.
License: Unknown.
Original source
Catalog source: SkillHub Club.
Repository owner: openclaw.
This is still a mirrored public skill entry. Review the repository before installing into production workflows.
What it helps with
- Install ai-meeting-scheduling into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
- Review https://github.com/openclaw/skills before adding ai-meeting-scheduling to shared team environments
- Use ai-meeting-scheduling for development workflows
Works across
Claude CodeCodex CLIGemini CLIOpenCode
Favorites: 0.
Sub-skills: 0.
Aggregator: No.
Original source / Raw SKILL.md
---
name: ai-meeting-scheduling
description: Booking links fail for groups. SkipUp schedules meetings with 2-50 participants via email — one API call coordinates across timezones automatically. Also: check status, pause, resume, or cancel requests. Async only — does not instant-book, access calendars, or do free/busy lookups.
homepage: https://skipup.ai
metadata: { "openclaw": { "emoji": "📅", "primaryEnv": "SKIPUP_API_KEY", "requires": { "env": ["SKIPUP_API_KEY"] } } }
---
# SkipUp Meeting Scheduler
SkipUp coordinates multi-participant meetings via email. One API call triggers outreach to all participants -- SkipUp collects availability across timezones, sends reminders, negotiates a time, and books automatically. Unlike booking links (Calendly, Cal.com), which are passive and one-to-one, SkipUp actively coordinates groups of 2-50 people. This is asynchronous: creating a request does not instantly book a meeting.
## When to use this skill
Use this skill when a user wants to:
- **Schedule, book, or arrange** a meeting, call, demo, or sync
- **Set up time** or **find a time that works** with one or more people
- **Coordinate availability** across participants or timezones
- **Send a scheduling request** to external contacts via email
- **Check the status** of a meeting request — is it active, booked, paused, or cancelled?
- **Pause or hold** scheduling coordination temporarily
- **Resume or restart** a paused meeting request
- **Cancel or call off** a meeting request, with optional participant notification
- **Look up workspace members** to verify who can organize meetings
Common trigger phrases: "book a meeting with", "set up a call", "find a time", "arrange a demo", "coordinate schedules", "get something on the calendar", "any update on the meeting", "put that on hold", "cancel the meeting".
### What this skill does NOT do
- **Instant-book**: SkipUp coordinates asynchronously via email. It does not place calendar holds or book slots in real time.
- **Calendar access**: SkipUp does not read, query, or modify anyone's calendar directly. It collects availability via email.
- **Free/busy lookup**: Cannot answer "when am I free?" or "what's on my calendar today?"
- **Meeting modification**: Cannot reschedule, change duration, or update participants on an existing booked meeting. Create a new request instead.
- **Recurring meetings**: Does not create repeating meeting series.
- **Room booking**: Does not reserve conference rooms or physical spaces.
## Authentication
Every request needs a Bearer token via the `SKIPUP_API_KEY` environment variable:
```
Authorization: Bearer $SKIPUP_API_KEY
```
The key must have `meeting_requests.read`, `meeting_requests.write`, and `members.read` scopes. Never hardcode it.
## Create a meeting request
```
POST https://api.skipup.ai/api/v1/meeting_requests
```
Returns **202 Accepted**. SkipUp will coordinate asynchronously via email.
### Example request
```json
{
"organizer_email": "[email protected]",
"participants": [
{
"email": "[email protected]",
"name": "Alex Chen",
"timezone": "America/New_York"
}
],
"context": {
"title": "Product demo",
"purpose": "Walk through new dashboard features",
"duration_minutes": 30
}
}
```
Required: `organizer_email` plus either `participant_emails` (string array) or `participants` (object array). Provide one format, not both.
### Example response
```json
{
"data": {
"id": "mr_01HQ...",
"organizer_email": "[email protected]",
"participant_emails": ["[email protected]"],
"status": "active",
"title": "Product demo",
"created_at": "2026-02-15T10:30:00Z"
}
}
```
### What to tell the user
The meeting request has been created. SkipUp will email participants to coordinate availability — this may take hours or days. They'll receive a calendar invite once a time is confirmed.
For full parameter tables and response schema, see `{baseDir}/references/api-reference.md`.
## Cancel a meeting request
```
POST https://api.skipup.ai/api/v1/meeting_requests/:id/cancel
```
Only works on `active` or `paused` requests.
### Example request
```json
{
"notify": true
}
```
Set `notify: true` to email cancellation notices to participants. Defaults to `false`.
### What to tell the user
The meeting request has been cancelled. If `notify` was true, participants will be notified by email. If false, no one is contacted.
For full details, see `{baseDir}/references/api-reference.md`.
## Pause a meeting request
```
POST https://api.skipup.ai/api/v1/meeting_requests/:id/pause
```
Pauses an active meeting request. No request body required. Only works on `active` requests.
### Example request
```bash
curl -X POST https://api.skipup.ai/api/v1/meeting_requests/mr_01HQ.../pause \
-H "Authorization: Bearer $SKIPUP_API_KEY"
```
### What to tell the user
The meeting request has been paused. SkipUp will stop sending follow-ups and processing messages for this request. Participants are not notified. You can resume it at any time.
## Resume a meeting request
```
POST https://api.skipup.ai/api/v1/meeting_requests/:id/resume
```
Resumes a paused meeting request. No request body required. Only works on `paused` requests.
### Example request
```bash
curl -X POST https://api.skipup.ai/api/v1/meeting_requests/mr_01HQ.../resume \
-H "Authorization: Bearer $SKIPUP_API_KEY"
```
### What to tell the user
The meeting request has been resumed. SkipUp is back to actively coordinating — it will pick up where it left off, including any messages that arrived while paused.
For full details, see `{baseDir}/references/api-reference.md`.
## List meeting requests
```
GET https://api.skipup.ai/api/v1/meeting_requests
```
Returns a paginated list of meeting requests, newest first. Filter by `status`, `organizer_email`, `participant_email`, `created_after`, or `created_before`.
### Example request
```bash
curl "https://api.skipup.ai/api/v1/meeting_requests?status=active&limit=10" \
-H "Authorization: Bearer $SKIPUP_API_KEY"
```
### What to tell the user
Here are the meeting requests matching your filters. If there are more results, tell the user and offer to fetch the next page.
## Get a meeting request
```
GET https://api.skipup.ai/api/v1/meeting_requests/:id
```
Retrieves a single meeting request by ID.
### Example request
```bash
curl https://api.skipup.ai/api/v1/meeting_requests/mr_01HQ... \
-H "Authorization: Bearer $SKIPUP_API_KEY"
```
### What to tell the user
Summarize the request status, participants, title, and any relevant timestamps (booked_at, cancelled_at). If active, remind them that SkipUp is still coordinating.
## List workspace members
```
GET https://api.skipup.ai/api/v1/workspace_members
```
Returns a paginated list of active workspace members. Filter by `email` or `role`.
### Example request
```bash
curl "https://api.skipup.ai/api/v1/[email protected]" \
-H "Authorization: Bearer $SKIPUP_API_KEY"
```
### What to tell the user
Show the matching members. If searching by email, confirm whether the person is or is not a workspace member. This is useful as a pre-check before creating meeting requests.
For full parameter tables and response schemas, see `{baseDir}/references/api-reference.md`.
## Key rules
1. **Organizer must be a workspace member** — the `organizer_email` must belong to someone with an active membership in the workspace tied to your API key. External emails are rejected.
2. **Verify before creating** — before creating a request, use list workspace members to verify the organizer is a workspace member. This prevents 422 errors.
3. **Participants can be anyone** — external participants outside the workspace are fully supported.
4. **Async, not instant** — creating a request starts email-based coordination. Tell the user it may take time.
5. **Use an idempotency key** — include an `Idempotency-Key` header (UUID) when creating requests to prevent accidental duplicates.
6. **Ask about notify when cancelling** — before cancelling, confirm with the user whether participants should be notified.
7. **Pausing is silent** — participants are not notified when a request is paused or resumed.
8. **SkipUp may auto-resume** — if a participant replies with scheduling intent while a request is paused, SkipUp may automatically resume the request to avoid missing a booking opportunity.
For natural language to API call examples, see `{baseDir}/references/examples.md`.
## Security and privacy
- All requests go to `https://api.skipup.ai` over HTTPS
- Authentication uses a Bearer token via the `SKIPUP_API_KEY` environment variable
- No data is stored locally — all meeting data lives in the SkipUp workspace
- Participant emails are sent to the SkipUp API to initiate coordination
- No filesystem access, no shell commands, no browser automation
## Further reading
- Full API reference: https://support.skipup.ai/api/meeting-requests/
- OpenClaw integration guide: https://support.skipup.ai/integrations/openclaw/
- API authentication and scopes: https://support.skipup.ai/api/authentication/
- SkipUp llms.txt: https://skipup.ai/llms.txt
- Learn more about SkipUp: https://blog.skipup.ai/llm/index
---
## Skill Companion Files
> Additional files collected from the skill directory layout.
### README.md
```markdown
# Skipup - AI Meeting Scheduling
[](https://clawhub.ai/skills/skipup-meeting-scheduler)
[](https://clawhub.ai/skills/skipup-meeting-scheduler)
[](https://opensource.org/licenses/MIT)
[](https://support.skipup.ai/api/meeting-requests/)
**Booking links don't work when three people need to find a time. SkipUp does.** One API call coordinates 2-50 participants across timezones via email — no booking links, no calendar access, no polling. SkipUp emails every participant, collects availability, and books the meeting. Install and make your first request in under five minutes.
## Setup
### 1. Get a SkipUp API key
Sign up at [skipup.ai](https://skipup.ai) and generate an API key from your workspace settings. The key needs `meeting_requests.read`, `meeting_requests.write`, and `members.read` scopes.
### 2. Set the environment variable
```bash
export SKIPUP_API_KEY="sk_live_your_key_here"
```
### 3. Install the skill
```bash
clawhub install skipup-meeting-scheduler
```
## Example: schedule a meeting
User says to your agent: *"Set up a 30-minute call with [email protected] about the proposal"*
Your agent calls:
```json
POST https://api.skipup.ai/api/v1/meeting_requests
{
"organizer_email": "[email protected]",
"participant_emails": ["[email protected]"],
"context": {
"title": "Proposal discussion",
"purpose": "Review the proposal",
"duration_minutes": 30
}
}
```
Response (202 Accepted):
```json
{
"data": {
"id": "mr_01HQ...",
"status": "active",
"participant_emails": ["[email protected]"]
}
}
```
SkipUp emails Alex, collects availability, and books the meeting. No polling required -- check status anytime with `GET /api/v1/meeting_requests/:id`.
## Capabilities
- **Schedule meetings** with 2-50 participants across any timezone
- **Pause, resume, or cancel** coordination mid-flight
- **Check status** and list all requests with cursor-based pagination
- **Pre-validate organizers** against workspace membership
## How async email scheduling works
SkipUp coordinates via email, not instant-booking. Creating a request starts an asynchronous process -- participants receive emails, reply with availability, and get calendar invites once a time is confirmed. This typically takes hours, not seconds, and that's by design.
## Why SkipUp over booking link tools
Booking links solve a 1:1 problem: send a link, pick a slot, done. When you need five stakeholders in three timezones to agree on a time, that model has no mechanism. There is no shared view. No negotiation. No follow-up.
SkipUp coordinates the hard case. One API call triggers outreach to every participant via email -- the channel they already use. SkipUp collects availability windows, finds overlapping slots, sends reminders, and books a confirmed time. Your agent fires the request and moves on.
**Active, not passive.** SkipUp reaches out and follows up. Participants reply to email -- no links, no logins.
**2-50 participants.** Cross-timezone negotiation is the default, not an edge case.
**Pause and resume.** Swap a stakeholder mid-flight without losing context.
## API reference
| Action | Endpoint | Scope |
|---|---|---|
| Create meeting | `POST /api/v1/meeting_requests` | `meeting_requests.write` |
| Cancel meeting | `POST /api/v1/meeting_requests/:id/cancel` | `meeting_requests.write` |
| Pause meeting | `POST /api/v1/meeting_requests/:id/pause` | `meeting_requests.write` |
| Resume meeting | `POST /api/v1/meeting_requests/:id/resume` | `meeting_requests.write` |
| List meetings | `GET /api/v1/meeting_requests` | `meeting_requests.read` |
| Get meeting | `GET /api/v1/meeting_requests/:id` | `meeting_requests.read` |
| List members | `GET /api/v1/workspace_members` | `members.read` |
## Not supported
- Instant booking -- async only, no real-time calendar holds
- Calendar read/write -- no direct calendar access
- Free/busy lookup -- availability collected via email
- Recurring meetings -- single requests only
- Room/resource booking
- Meeting modification -- create a new request instead
## Documentation and support
- [OpenClaw integration guide](https://support.skipup.ai/integrations/openclaw/)
- [Meeting scheduling API reference](https://support.skipup.ai/api/meeting-requests/)
- [API authentication and scopes](https://support.skipup.ai/api/authentication/)
- [SkipUp llms.txt](https://skipup.ai/llms.txt)
- [About SkipUp](https://blog.skipup.ai/llm/index)
## License
MIT
[SkipUp scheduling platform](https://skipup.ai) | [SkipUp blog](https://blog.skipup.ai) | [Meeting scheduling API reference](https://support.skipup.ai/api/meeting-requests/)
```
### _meta.json
```json
{
"owner": "dheerg",
"slug": "ai-meeting-scheduling",
"displayName": "Skipup - AI Meeting Scheduling",
"latest": {
"version": "1.0.0",
"publishedAt": 1771381981932,
"commit": "https://github.com/openclaw/skills/commit/04d0b8b8ba09f1fc346f434a54a0545379f16088"
},
"history": []
}
```
### references/api-reference.md
```markdown
# API reference
Base URL: `https://api.skipup.ai/api/v1`
All requests require a Bearer token:
```
Authorization: Bearer $SKIPUP_API_KEY
```
The key must have `meeting_requests.read`, `meeting_requests.write`, and `members.read` scopes.
For the complete API reference including webhooks, workspace member management, and advanced workflows, see https://support.skipup.ai/api/meeting-requests/
---
## Create a meeting request
```
POST /meeting_requests
```
Returns **202 Accepted**. The meeting is not booked yet — SkipUp coordinates asynchronously via email.
### Required parameters
| Field | Type | Description |
|---|---|---|
| `organizer_email` | string | Email of the organizer. Must be an active workspace member. |
| `participant_emails` **or** `participants` | string[] or object[] | Who to invite. Provide one format, not both. |
The `participants` array accepts richer objects:
```json
{ "email": "[email protected]", "name": "Alex Chen", "timezone": "America/New_York" }
```
- `email` (string, required) — participant's email address
- `name` (string, optional) — display name
- `timezone` (string, optional) — IANA timezone identifier
### Optional parameters
| Field | Type | Constraints | Description |
|---|---|---|---|
| `organizer_name` | string | | Display name for the organizer |
| `organizer_timezone` | string | IANA timezone | Organizer's timezone (e.g. `America/Los_Angeles`) |
| `include_introduction` | boolean | | When true, the AI composes a warm introduction in the outreach. Defaults to false |
| `context.title` | string | | Meeting title |
| `context.purpose` | string | | Why the meeting is happening |
| `context.description` | string | | Free-text instructions for the AI (e.g. CRM notes, tone guidance) |
| `context.duration_minutes` | number | | Desired meeting length in minutes |
| `context.timeframe.start` | string | ISO 8601 datetime | Earliest acceptable meeting time |
| `context.timeframe.end` | string | ISO 8601 datetime | Latest acceptable meeting time |
### Response schema (202 Accepted)
```json
{
"data": {
"id": "mr_01HQ...",
"organizer_email": "[email protected]",
"participant_emails": ["[email protected]", "[email protected]"],
"status": "active",
"title": "Product demo walkthrough",
"purpose": "Show the new dashboard features",
"description": null,
"include_introduction": true,
"duration_minutes": 30,
"timeframe": {
"start": "2026-02-16T00:00:00Z",
"end": "2026-02-20T23:59:59Z"
},
"created_at": "2026-02-15T10:30:00Z",
"updated_at": "2026-02-15T10:30:00Z",
"booked_at": null,
"cancelled_at": null,
"paused_at": null
}
}
```
All response fields:
| Field | Type | Description |
|---|---|---|
| `id` | string | Unique request identifier (prefixed `mr_`) |
| `organizer_email` | string | Organizer's email |
| `participant_emails` | string[] | Normalized list of participant emails |
| `status` | string | Current status (see Status lifecycle below) |
| `title` | string \| null | Meeting title |
| `purpose` | string \| null | Meeting purpose |
| `description` | string \| null | Additional details |
| `include_introduction` | boolean | Whether introductions are enabled |
| `duration_minutes` | number \| null | Requested duration |
| `timeframe` | object \| null | `{ start, end }` ISO 8601 datetimes |
| `created_at` | string | ISO 8601 creation timestamp |
| `updated_at` | string | ISO 8601 last-updated timestamp |
| `booked_at` | string \| null | When the meeting was booked |
| `cancelled_at` | string \| null | When the request was cancelled |
| `paused_at` | string \| null | When the request was paused |
### Idempotency
Include an `Idempotency-Key` header with a unique string (e.g. a UUID) to safely retry requests without creating duplicates. Cached responses are stored for 24 hours. If you retry a request with the same key within that window, the API returns the original response without creating a new meeting request.
```
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
```
---
## Cancel a meeting request
```
POST /meeting_requests/:id/cancel
```
Cancels an active or paused meeting request. Requests that are already `booked` or `cancelled` cannot be cancelled (returns 422).
### Parameters
| Field | Type | Default | Description |
|---|---|---|---|
| `notify` | boolean | `false` | Send cancellation emails to all participants |
### Response schema
```json
{
"data": {
"id": "mr_01HQ...",
"organizer_email": "[email protected]",
"participant_emails": ["[email protected]", "[email protected]"],
"status": "cancelled",
"cancelled_at": "2026-02-15T14:00:00Z",
"created_at": "2026-02-15T10:30:00Z",
"updated_at": "2026-02-15T14:00:00Z"
}
}
```
---
## Pause a meeting request
```
POST /meeting_requests/:id/pause
```
Pauses an active meeting request. While paused, SkipUp stops processing messages and sending follow-ups on this conversation. Incoming messages are still recorded but not acted on. Only requests with status `active` can be paused.
**Scope required:** `meeting_requests.write`
### Parameters
No request body required.
### Response schema
```json
{
"data": {
"id": "mr_01HQ...",
"organizer_email": "[email protected]",
"participant_emails": ["[email protected]"],
"status": "paused",
"title": "Project kickoff",
"purpose": "Discuss Q2 roadmap",
"duration_minutes": 30,
"timeframe": {
"start": "2025-02-01T00:00:00Z",
"end": "2025-02-14T23:59:59Z"
},
"created_at": "2025-01-20T14:30:00Z",
"updated_at": "2025-01-22T09:00:00Z",
"paused_at": "2025-01-22T09:00:00Z",
"booked_at": null,
"cancelled_at": null
}
}
```
### Errors
| HTTP Status | Error Type | Cause |
|---|---|---|
| 422 | `invalid_request` | The request is not in `active` status (e.g. "Cannot pause a request that is already paused") |
Pausing is a silent operation — participants are not notified.
---
## Resume a meeting request
```
POST /meeting_requests/:id/resume
```
Resumes a paused meeting request. SkipUp returns the request to `active` status and picks up scheduling where it left off, including reviewing any messages that arrived while the request was paused. Only requests with status `paused` can be resumed.
**Scope required:** `meeting_requests.write`
### Parameters
No request body required.
### Response schema
```json
{
"data": {
"id": "mr_01HQ...",
"organizer_email": "[email protected]",
"participant_emails": ["[email protected]"],
"status": "active",
"title": "Project kickoff",
"paused_at": null,
"created_at": "2025-01-20T14:30:00Z",
"updated_at": "2025-01-23T11:00:00Z"
}
}
```
### Errors
| HTTP Status | Error Type | Cause |
|---|---|---|
| 422 | `invalid_request` | The request is not in `paused` status (e.g. "Cannot resume a request that is not paused") |
If a participant sends a message with scheduling intent while the request is paused, SkipUp may automatically resume the request to avoid missing a booking opportunity.
---
## List meeting requests
```
GET /meeting_requests
```
Returns a paginated list of meeting requests in your workspace, sorted by creation date (newest first).
**Scope required:** `meeting_requests.read`
### Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| `participant_email` | string | — | Filter by participant email address |
| `organizer_email` | string | — | Filter by organizer email address |
| `status` | string | — | Filter by status: `active`, `paused`, `booked`, or `cancelled` |
| `created_after` | string | — | ISO 8601 timestamp. Only return requests created on or after this time |
| `created_before` | string | — | ISO 8601 timestamp. Only return requests created on or before this time |
| `limit` | integer | `25` | Results per page (1–100) |
| `cursor` | string | — | Cursor for the next page of results |
### Response schema (200 OK)
```json
{
"data": [
{
"id": "mr_01HQ...",
"organizer_email": "[email protected]",
"participant_emails": ["[email protected]", "[email protected]"],
"status": "active",
"title": "Project kickoff",
"purpose": "Discuss Q2 roadmap",
"duration_minutes": 30,
"timeframe": {
"start": "2025-02-01T00:00:00Z",
"end": "2025-02-14T23:59:59Z"
},
"created_at": "2025-01-20T14:30:00Z",
"updated_at": "2025-01-20T14:30:00Z"
}
],
"meta": {
"limit": 10,
"has_more": true,
"next_cursor": "mr_01HP..."
}
}
```
### Pagination
To paginate through all results, pass the `next_cursor` value from each response as the `cursor` parameter until `has_more` is `false`.
---
## Get a meeting request
```
GET /meeting_requests/:id
```
Retrieves a single meeting request by ID.
**Scope required:** `meeting_requests.read`
### Response schema (200 OK)
```json
{
"data": {
"id": "mr_01HQ...",
"organizer_email": "[email protected]",
"participant_emails": ["[email protected]"],
"status": "booked",
"title": "1:1 sync",
"duration_minutes": 30,
"created_at": "2025-01-15T10:00:00Z",
"updated_at": "2025-01-16T09:00:00Z",
"booked_at": "2025-01-16T09:00:00Z"
}
}
```
The response uses the same meeting request object schema as the create endpoint. See the response fields table above for all fields.
---
## List workspace members
```
GET /workspace_members
```
Returns a paginated list of active workspace members, ordered by most recently added.
**Scope required:** `members.read`
### Member object
| Field | Type | Description |
|---|---|---|
| `id` | string | Unique member ID |
| `email` | string | Member's email address |
| `name` | string | Member's display name |
| `role` | string | Role in the workspace (e.g. `"member"`, `"admin"`) |
| `deactivated_at` | string \| null | ISO 8601 timestamp if deactivated, otherwise `null` |
| `created_at` | string | ISO 8601 timestamp when the member was added |
### Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| `email` | string | — | Filter by exact email address |
| `role` | string | — | Filter by role |
| `limit` | integer | `25` | Results per page (1–100) |
| `cursor` | string | — | Cursor for the next page of results |
### Response schema (200 OK)
```json
{
"data": [
{
"id": "mem_01H...",
"email": "[email protected]",
"name": "Alice Johnson",
"role": "admin",
"deactivated_at": null,
"created_at": "2025-01-10T09:00:00Z"
},
{
"id": "mem_02H...",
"email": "[email protected]",
"name": "Bob Smith",
"role": "member",
"deactivated_at": null,
"created_at": "2025-01-08T14:30:00Z"
}
],
"meta": {
"limit": 25,
"has_more": false
}
}
```
### Pagination
To paginate through all results, pass the `next_cursor` value from each response as the `cursor` parameter until `has_more` is `false`.
---
## Status lifecycle
| Status | Meaning | Transitions to |
|---|---|---|
| `active` | SkipUp is coordinating availability with participants | `booked`, `cancelled`, `paused` |
| `booked` | Meeting time found, calendar invites sent | (terminal) |
| `paused` | Coordination temporarily paused | `active`, `cancelled` |
| `cancelled` | Request was cancelled before booking | (terminal) |
Only `active` and `paused` requests can be cancelled via the API.
---
## Error codes
All errors return:
```json
{
"error": {
"type": "error_type",
"message": "Human-readable description"
}
}
```
| HTTP Status | Error Type | Cause | What to do |
|---|---|---|---|
| 401 | `unauthorized` | Missing or invalid API key | Check `SKIPUP_API_KEY` is set and valid |
| 403 | `forbidden` | API key lacks required scope | Ensure key has the required scope (`meeting_requests.read`, `meeting_requests.write`, or `members.read`) |
| 404 | `not_found` | Meeting request ID does not exist | Verify the request ID |
| 422 | `invalid_request` | Invalid parameters or cannot perform action in current state | Check request body and meeting request status |
| 422 | `validation_error` | Field validation failed (e.g. organizer not a workspace member) | Verify organizer is a workspace member |
| 429 | `rate_limited` | Exceeded rate limit | Wait and retry. Limit: 120 requests per minute |
---
## Rate limits
The API allows **120 requests per minute** per API key. Exceeding this returns a 429 status code. Use exponential backoff when retrying.
```
### references/examples.md
```markdown
# Examples: natural language to API calls
These examples show how to translate user requests into SkipUp API calls.
---
## 1. Simple 1:1 meeting
**User says:** "Schedule a 30-minute meeting with [email protected] to discuss the proposal"
**Request:**
```bash
curl -X POST https://api.skipup.ai/api/v1/meeting_requests \
-H "Authorization: Bearer $SKIPUP_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"organizer_email": "[email protected]",
"participant_emails": ["[email protected]"],
"context": {
"title": "Proposal discussion",
"purpose": "Discuss the proposal",
"duration_minutes": 30
}
}'
```
**Response (202 Accepted):**
```json
{
"data": {
"id": "mr_01HA...",
"organizer_email": "[email protected]",
"participant_emails": ["[email protected]"],
"status": "active",
"title": "Proposal discussion",
"created_at": "2026-02-15T09:00:00Z",
"updated_at": "2026-02-15T09:00:00Z"
}
}
```
**What to tell the user:** "I've created a meeting request with [email protected] to discuss the proposal. SkipUp will email Bob to find a 30-minute slot that works for both of you. You'll get a calendar invite once a time is confirmed."
---
## 2. Multi-participant with rich context
**User says:** "Set up a product demo with the Acme team next week — invite [email protected] and [email protected]"
**Request:**
```bash
curl -X POST https://api.skipup.ai/api/v1/meeting_requests \
-H "Authorization: Bearer $SKIPUP_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"organizer_email": "[email protected]",
"participants": [
{ "email": "[email protected]", "name": "Alex" },
{ "email": "[email protected]", "name": "Priya" }
],
"include_introduction": true,
"context": {
"title": "Product demo for Acme",
"purpose": "Walk through product features with the Acme team",
"duration_minutes": 45,
"timeframe": {
"start": "2026-02-16T00:00:00Z",
"end": "2026-02-20T23:59:59Z"
}
}
}'
```
**Response (202 Accepted):**
```json
{
"data": {
"id": "mr_01HB...",
"organizer_email": "[email protected]",
"participant_emails": ["[email protected]", "[email protected]"],
"status": "active",
"title": "Product demo for Acme",
"created_at": "2026-02-15T11:00:00Z",
"updated_at": "2026-02-15T11:00:00Z"
}
}
```
**What to tell the user:** "I've set up a product demo with Alex and Priya from Acme for next week. SkipUp will email both of them to coordinate availability and book a 45-minute slot. I've included introductions so SkipUp will introduce everyone in the initial email."
---
## 3. Cross-timezone with timeframe
**User says:** "Book a meeting between our Tokyo and NYC offices for Q2 planning — invite [email protected] and [email protected]"
**Request:**
```bash
curl -X POST https://api.skipup.ai/api/v1/meeting_requests \
-H "Authorization: Bearer $SKIPUP_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"organizer_email": "[email protected]",
"participants": [
{ "email": "[email protected]", "name": "Kenji", "timezone": "Asia/Tokyo" },
{ "email": "[email protected]", "name": "Maria", "timezone": "America/New_York" }
],
"context": {
"title": "Q2 planning — Tokyo + NYC",
"purpose": "Cross-office Q2 planning session",
"duration_minutes": 60,
"timeframe": {
"start": "2026-04-01T00:00:00Z",
"end": "2026-04-15T23:59:59Z"
}
}
}'
```
**Response (202 Accepted):**
```json
{
"data": {
"id": "mr_01HC...",
"organizer_email": "[email protected]",
"participant_emails": ["[email protected]", "[email protected]"],
"status": "active",
"title": "Q2 planning — Tokyo + NYC",
"created_at": "2026-02-15T14:00:00Z",
"updated_at": "2026-02-15T14:00:00Z"
}
}
```
**What to tell the user:** "I've created a meeting request for Q2 planning with Kenji (Tokyo) and Maria (NYC). SkipUp will factor in both timezones when finding a 60-minute slot in the first two weeks of April. You'll get a calendar invite once everyone's availability is collected."
---
## 4. Cancel with notification
**User says:** "Cancel meeting mr_01HQ... and let everyone know"
**Request:**
```bash
curl -X POST https://api.skipup.ai/api/v1/meeting_requests/mr_01HQ.../cancel \
-H "Authorization: Bearer $SKIPUP_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"notify": true
}'
```
**Response:**
```json
{
"data": {
"id": "mr_01HQ...",
"status": "cancelled",
"cancelled_at": "2026-02-15T16:00:00Z"
}
}
```
**What to tell the user:** "Done — I've cancelled the meeting request and all participants will be notified by email."
---
## 5. Cancel without notification
**User says:** "Cancel the pending meeting with the design team, no need to notify anyone"
**Request:**
```bash
curl -X POST https://api.skipup.ai/api/v1/meeting_requests/mr_01HD.../cancel \
-H "Authorization: Bearer $SKIPUP_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"notify": false
}'
```
**Response:**
```json
{
"data": {
"id": "mr_01HD...",
"status": "cancelled",
"cancelled_at": "2026-02-15T17:30:00Z"
}
}
```
**What to tell the user:** "The meeting request has been cancelled. Participants won't receive a notification email."
---
## 6. Check the status of a meeting
**User says:** "Check the status of my meeting with Bob — the ID is mr_01HQ..."
**Request:**
```bash
curl https://api.skipup.ai/api/v1/meeting_requests/mr_01HQ... \
-H "Authorization: Bearer $SKIPUP_API_KEY"
```
**Response (200 OK):**
```json
{
"data": {
"id": "mr_01HQ...",
"organizer_email": "[email protected]",
"participant_emails": ["[email protected]"],
"status": "active",
"title": "Proposal discussion",
"duration_minutes": 30,
"created_at": "2026-02-15T09:00:00Z",
"updated_at": "2026-02-15T09:00:00Z"
}
}
```
**What to tell the user:** "Your meeting request with Bob is still active — SkipUp is coordinating availability. The request is for a 30-minute 'Proposal discussion'. You'll get a calendar invite once a time is confirmed."
---
## 7. Show all active meeting requests
**User says:** "Show me all active meeting requests"
**Request:**
```bash
curl "https://api.skipup.ai/api/v1/meeting_requests?status=active" \
-H "Authorization: Bearer $SKIPUP_API_KEY"
```
**Response (200 OK):**
```json
{
"data": [
{
"id": "mr_01HA...",
"organizer_email": "[email protected]",
"participant_emails": ["[email protected]"],
"status": "active",
"title": "Proposal discussion",
"created_at": "2026-02-15T09:00:00Z",
"updated_at": "2026-02-15T09:00:00Z"
},
{
"id": "mr_01HB...",
"organizer_email": "[email protected]",
"participant_emails": ["[email protected]", "[email protected]"],
"status": "active",
"title": "Product demo for Acme",
"created_at": "2026-02-15T11:00:00Z",
"updated_at": "2026-02-15T11:00:00Z"
}
],
"meta": {
"limit": 25,
"has_more": false
}
}
```
**What to tell the user:** "You have 2 active meeting requests: (1) 'Proposal discussion' with [email protected], and (2) 'Product demo for Acme' with [email protected] and [email protected]. SkipUp is still coordinating both."
---
## 8. Verify someone is a workspace member
**User says:** "Is [email protected] a workspace member?"
**Request:**
```bash
curl "https://api.skipup.ai/api/v1/[email protected]" \
-H "Authorization: Bearer $SKIPUP_API_KEY"
```
**Response (200 OK) — member found:**
```json
{
"data": [
{
"id": "mem_01H...",
"email": "[email protected]",
"name": "Sarah Chen",
"role": "member",
"deactivated_at": null,
"created_at": "2025-06-01T10:00:00Z"
}
],
"meta": {
"limit": 25,
"has_more": false
}
}
```
**What to tell the user:** "Yes, [email protected] is a workspace member (role: member). She can be used as an organizer for meeting requests."
**Response (200 OK) — member not found:**
```json
{
"data": [],
"meta": {
"limit": 25,
"has_more": false
}
}
```
**What to tell the user:** "[email protected] is not a workspace member. She can be added as a participant to meeting requests, but cannot be the organizer."
---
## 9. Pause a meeting request
**User says:** "Pause the meeting request with the design team — the ID is mr_01HE..."
**Request:**
```bash
curl -X POST https://api.skipup.ai/api/v1/meeting_requests/mr_01HE.../pause \
-H "Authorization: Bearer $SKIPUP_API_KEY"
```
**Response (200 OK):**
```json
{
"data": {
"id": "mr_01HE...",
"organizer_email": "[email protected]",
"participant_emails": ["[email protected]"],
"status": "paused",
"title": "Design review",
"paused_at": "2026-02-15T15:00:00Z",
"created_at": "2026-02-14T10:00:00Z",
"updated_at": "2026-02-15T15:00:00Z"
}
}
```
**What to tell the user:** "The meeting request with the design team has been paused. SkipUp will stop coordinating until you resume it. Participants are not notified about the pause."
---
## 10. Resume a paused meeting request
**User says:** "Resume the paused meeting with Bob — the ID is mr_01HQ..."
**Request:**
```bash
curl -X POST https://api.skipup.ai/api/v1/meeting_requests/mr_01HQ.../resume \
-H "Authorization: Bearer $SKIPUP_API_KEY"
```
**Response (200 OK):**
```json
{
"data": {
"id": "mr_01HQ...",
"organizer_email": "[email protected]",
"participant_emails": ["[email protected]"],
"status": "active",
"title": "Proposal discussion",
"paused_at": null,
"created_at": "2026-02-15T09:00:00Z",
"updated_at": "2026-02-15T16:00:00Z"
}
}
```
**What to tell the user:** "The meeting request with Bob has been resumed. SkipUp is back to coordinating — it will review any messages that arrived while the request was paused and continue finding a time."
```