Skip to main content

API Documentation

Build custom workflows for your team with our open API. Looking for something specific? Reach out to us for support.

Written by Andrew
  1. Navigate to API Keys
    While logged into your account navigate to settings -> API Keys

2. Create your API Key

Name and create your API Key

1. POST (Schedule a Virtual Call)

Schedules a new call and automatically sends a confirmation SMS to the customer with their unique join link. Returns both an agent join link (for your team) and a customer join link (already SMS'd to the customer).

You can either attach the call to an existing project (pass projectId) or create a new project on the fly (pass customerName).

You can assign the call to a specific member of your team by passing assignedToEmail (their Qube Sheets login email) or assignedToUserId (their user id from the List Users endpoint). This works with both variants below. Assigned calls appear on that rep's schedule in Qube Sheets, the confirmation SMS uses their name, and if they've connected Google Calendar the call is added to their calendar automatically. When the call creates a new project, that project is assigned to the rep as well.


Create new project + schedule call

POST https://app.qubesheets.com/api/external/video-calls
-H "Authorization: Bearer YOUR_API_KEY"
-H "Content-Type: application/json"
-d '{
"customerName": "Jane Doe",
"customerPhone": "5551234567",
"customerEmail": "jane@example.com",
"scheduledFor": "2026-06-15T20:00:00.000Z",
"timezone": "America/New_York",
"assignedToEmail": "rep@yourcompany.com"
}'

Schedule call on existing project

POST https://app.qubesheets.com/api/external/video-calls
-H "Authorization: Bearer YOUR_API_KEY"
-H "Content-Type: application/json"
-d '{
"projectId": "507f1f77bcf86cd799439011",
"customerPhone": "5551234567",
"scheduledFor": "2026-06-15T20:00:00.000Z",
"assignedToEmail": "rep@yourcompany.com"
}'

Success Response (201)

{
"success": true,
"message": "Video call scheduled successfully",
"videoCall": {
"id": "65f1b2c3d4e5f6a7b8c9d0e1",
"projectId": "65f1b2c3d4e5f6a7b8c9d0e2",
"roomId": "65f1b2c3d4e5f6a7b8c9d0e2-1717000000000-a1b2c3d4",
"scheduledFor": "2026-06-15T20:00:00.000Z",
"timezone": "America/New_York",
"status": "scheduled",
"customerName": "Jane Doe",
"customerPhone": "+15551234567",
"customerEmail": "jane@example.com",
"assignedTo": {
"userId": "user_2abc123def456",
"name": "Jane Smith",
"email": "rep@yourcompany.com"
},
"agentJoinLink": "https://app.qubesheets.com/join/video-call/65f1b2c3d4e5f6a7b8c9d0e1?t=...",
"customerJoinLink": "https://app.qubesheets.com/join/video-call/65f1b2c3d4e5f6a7b8c9d0e1?t=...",
"createdAt": "2026-05-01T12:00:00.000Z"
},
"assignment": {
"requested": "rep@yourcompany.com",
"assigned": true,
"calendarEventCreated": true
},
"confirmationSms": {
"attempted": true,
"delivered": true
}
}


💡 Tip: The customerJoinLink is automatically sent to the customer via SMS. Use the agentJoinLink in your team's calendar invite, CRM, or other.

💡 Assignment is forgiving: if the email or user id doesn't match anyone in your organization, the call is still created (unassigned) and the assignment object in the response tells you why the match failed — so a bad email never blocks a booking. assignedTo is null on unassigned calls.

2. GET (List Virtual Calls)

GET "https://app.qubesheets.com/api/external/video-calls?upcoming=true&limit=20"
-H "Authorization: Bearer YOUR_API_KEY"

Success Response (200)

{
"success": true,
"videoCalls": [
{
"id": "65f1b2c3d4e5f6a7b8c9d0e1",
"projectId": "65f1b2c3d4e5f6a7b8c9d0e2",
"roomId": "65f1b2c3d4e5f6a7b8c9d0e2-1717000000000-a1b2c3d4",
"scheduledFor": "2026-06-15T20:00:00.000Z",
"timezone": "America/New_York",
"status": "scheduled",
"customerName": "Jane Doe",
"customerPhone": "+15551234567",
"customerEmail": "jane@example.com",
"assignedTo": {
"userId": "user_2abc123def456",
"name": "Jane Smith",
"email": "rep@yourcompany.com"
},
"agentJoinLink": "https://app.qubesheets.com/join/video-call/...",
"customerJoinLink": "https://app.qubesheets.com/join/video-call/...",
"createdAt": "2026-05-01T12:00:00.000Z",
"updatedAt": "2026-05-01T12:00:00.000Z"
}
],
"pagination": {
"total": 1,
"limit": 20,
"skip": 0,
"returned": 1
}
}

💡 Optional filters: status, projectId, startDate, endDate, upcoming, limit, skip, and assignedTo — pass a user id or email to list only that rep's calls, e.g. ?assignedTo=rep@yourcompany.com&upcoming=true.

3. GET (Single Video Call)

GET https://app.qubesheets.com/api/external/video-calls/65f1b2c3d4e5f6a7b8c9d0e1
-H "Authorization: Bearer YOUR_API_KEY"

Success Response (200)

{
"success": true,
"videoCall": {
"id": "65f1b2c3d4e5f6a7b8c9d0e1",
"projectId": "65f1b2c3d4e5f6a7b8c9d0e2",
"roomId": "65f1b2c3d4e5f6a7b8c9d0e2-1717000000000-a1b2c3d4",
"scheduledFor": "2026-06-15T20:00:00.000Z",
"timezone": "America/New_York",
"status": "scheduled",
"customerName": "Jane Doe",
"customerPhone": "+15551234567",
"customerEmail": "jane@example.com",
"assignedTo": {
"userId": "user_2abc123def456",
"name": "Jane Smith",
"email": "rep@yourcompany.com"
},
"agentJoinLink": "https://app.qubesheets.com/join/video-call/...",
"customerJoinLink": "https://app.qubesheets.com/join/video-call/...",
"remindersSent": [
{ "type": "confirmation", "sentAt": "2026-05-01T12:00:01.000Z", "method": "sms" }
],
"createdAt": "2026-05-01T12:00:00.000Z",
"updatedAt": "2026-05-01T12:00:00.000Z"
}
}

4. PATCH (Reschedule or Reassign Virtual Call)

PATCH https://app.qubesheets.com/api/external/video-calls/{callId}

Updates a scheduled call. Provide scheduledFor to reschedule, assignedToEmail / assignedToUserId to reassign it to a different team member, or both at once. Only calls with status scheduled can be updated.

- Rescheduling automatically sends a reschedule SMS to the customer with their (still valid) join link, and moves the rep's Google Calendar event if one exists.

- Reassigning moves the call to the new rep's schedule (and their Google Calendar, if connected). No SMS is sent for a reassignment alone.

Reschedule

PATCH https://app.qubesheets.com/api/external/video-calls/65f1b2c3d4e5f6a7b8c9d0e1
-H "Authorization: Bearer YOUR_API_KEY"
-H "Content-Type: application/json"
-d '{
"scheduledFor": "2026-06-16T21:00:00.000Z",
"timezone": "America/New_York"
}'

Reassign Only

PATCH https://app.qubesheets.com/api/external/video-calls/65f1b2c3d4e5f6a7b8c9d0e1
-H "Authorization: Bearer YOUR_API_KEY"
-H "Content-Type: application/json"
-d '{ "assignedToEmail": "otherrep@yourcompany.com" }'

Success Response (200)

{
"success": true,
"message": "Video call rescheduled successfully",
"videoCall": {
"id": "65f1b2c3d4e5f6a7b8c9d0e1",
"projectId": "65f1b2c3d4e5f6a7b8c9d0e2",
"scheduledFor": "2026-06-16T21:00:00.000Z",
"timezone": "America/New_York",
"status": "scheduled",
"assignedTo": {
"userId": "user_2abc123def456",
"name": "Jane Smith",
"email": "rep@yourcompany.com"
},
"agentJoinLink": "https://app.qubesheets.com/join/video-call/...",
"customerJoinLink": "https://app.qubesheets.com/join/video-call/..."
},
"rescheduleSms": {
"attempted": true,
"delivered": true
}
}


5. DELETE (Cancel a Virtual Call)

DELETE https://app.qubesheets.com/api/external/video-calls/{callId}

Cancels a scheduled call. Optionally sends a cancellation SMS to the customer. Only calls with status scheduled can be cancelled.

Request Body (optional)

DELETE https://app.qubesheets.com/api/external/video-calls/65f1b2c3d4e5f6a7b8c9d0e1
-H "Authorization: Bearer YOUR_API_KEY"
-H "Content-Type: application/json"
-d '{ "sendSms": true }'

Success Response (200)

{
"success": true,
"message": "Video call cancelled",
"videoCall": {
"id": "65f1b2c3d4e5f6a7b8c9d0e1",
"status": "cancelled"
},
"cancellationSms": {
"attempted": true,
"delivered": true
}
}


6. POST (Create project and send customer upload link)

POST https://app.qubesheets.com/api/external/projects   
-H "Authorization: Bearer YOUR_API_KEY"
-H "Content-Type: application/json"
-d '{"customerName": "John Smith", "phone": "5551234567"}'

7. GET (List Users)

Lists the members of your organization. Use the returned id (as assignedToUserId) or email (as assignedToEmail) to assign video calls to a specific team member.

GET https://app.qubesheets.com/api/external/users
-H "Authorization: Bearer YOUR_API_KEY"

Success Response (200)

{
"success": true,
"users": [
{
"id": "user_2abc123def456",
"email": "rep@yourcompany.com",
"firstName": "Jane",
"lastName": "Smith",
"name": "Jane Smith",
"role": "org:member"
}
],
"total": 1
}

Notes:

- Timezones: Always pass an IANA timezone string (e.g. America/Chicago, Europe/London). The SMS confirmation displays the date/time in the timezone you specify.
- Phone format: Send 10-digit US numbers — they'll be normalized to +1XXXXXXXXXX automatically.
- Org-scoped: Each API key only sees calls within its own organization.
- Branding: Confirmation SMS messages use your company name from Settings → Branding and your custom SMS template from Settings (if configured).
- Join links: The customerJoinLink and agentJoinLink are signed tokens that work without a login. They're valid from immediately after creation through 24 hours after the scheduled time.
- Assignment: Email matching is case-insensitive against the team member's Qube Sheets login email — if your CRM stores a different address for the same person, use List Users to fetch the correct emails or assign by assignedToUserId instead. If both fields are sent, assignedToUserId wins. When a call is created without an assignee (or the assignee can't be matched), assignedTo is null in all responses.
Error Responses
400 — Invalid Request
{
"error": "Invalid scheduledFor",
"message": "scheduledFor must be in the future"
}

401 — Invalid or Missing API Key
{
"error": "Invalid or missing API key",
"message": "Please provide a valid API key in the Authorization header: Bearer qbs_keyId_secret"
}
404 — Not Found
{
"error": "Video call not found",
"message": "No video call with that id was found for this organization"
}

500 — Internal Server Error
{
"error": "Internal server error",
"message": "Failed to schedule video call. Please try again later."
}
Did this answer your question?