### Install Dependencies Source: https://www.quo.com/docs/mdx/guides/sync-contacts Install the necessary packages for Google Sheets integration, HTTP requests, environment variables, and task scheduling. ```bash npm install googleapis axios dotenv node-cron ``` -------------------------------- ### GET /v1/tasks Source: https://www.quo.com/docs/mdx/api-reference/tasks/list-tasks Retrieve a list of tasks from the Quo platform. ```APIDOC ## GET /v1/tasks ### Description Retrieve a list of tasks. ### Method GET ### Endpoint /v1/tasks ### Parameters #### Query Parameters - **maxResults** (integer) - Required - Maximum number of results to return per page (default: 50, min: 1, max: 100). - **pageToken** (string) - Optional - Token for pagination. ### Response #### Success Response (200) - **data** (array) - List of task objects. - **totalItems** (integer) - Total number of items available. ``` -------------------------------- ### GET /v1/webhooks Source: https://www.quo.com/docs/mdx/api-reference/webhooks/lists-all-webhooks Retrieves a list of all webhooks for a user. ```APIDOC ## GET /v1/webhooks ### Description List all webhooks for a user. ### Method GET ### Endpoint /v1/webhooks ### Parameters #### Query Parameters - **userId** (string) - Optional - The unique identifier the user. Defaults to the workspace owner. ### Response #### Success Response (200) - **data** (array) - A list of webhook objects. ``` -------------------------------- ### GET /v1/users Source: https://www.quo.com/docs/mdx/api-reference/users/list-users Retrieve a paginated list of users in your Quo workspace. ```APIDOC ## GET /v1/users ### Description Retrieve a paginated list of users in your Quo workspace. ### Method GET ### Endpoint /v1/users ### Parameters #### Query Parameters - **maxResults** (integer) - Required - Maximum number of results to return per page. Default: 10, Minimum: 1, Maximum: 50. - **pageToken** (string) - Optional - Token for pagination. ### Response #### Success Response (200) - **data** (array) - List of user objects. - **totalItems** (integer) - Total number of items. - **nextPageToken** (string) - Token for the next page of results. ``` -------------------------------- ### Initialize Sync Script Setup Source: https://www.quo.com/docs/mdx/guides/sync-contacts Configure environment variables, API clients, and authentication for Google Sheets and Quo. ```js require("dotenv").config(); const { google } = require("googleapis"); const axios = require("axios"); const cron = require("node-cron"); const API_BASE_URL = "https://api.quo.com/v1"; const quo = axios.create({ baseURL: API_BASE_URL, headers: { Authorization: process.env.QUO_API_KEY, "Content-Type": "application/json", }, }); const googleAuth = new google.auth.GoogleAuth({ keyFile: process.env.GOOGLE_APPLICATION_CREDENTIALS, scopes: ["https://www.googleapis.com/auth/spreadsheets"], }); ``` -------------------------------- ### Initialize Node.js Project Source: https://www.quo.com/docs/mdx/guides/sync-contacts Commands to create and initialize a new Node.js project directory. ```bash mkdir quo-sync cd quo-sync npm init -y ``` -------------------------------- ### OpenAPI definition for Get a summary for a call Source: https://www.quo.com/docs/mdx/api-reference/calls/get-a-summary-for-a-call The OpenAPI specification defining the GET request for retrieving call summaries by call ID. ```yaml openapi: 3.1.0 info: title: Quo Public API version: 1.0.0 description: API for connecting with Quo. contact: name: Quo Support email: support@quo.com url: https://support.quo.com/ termsOfService: https://www.quo.com/terms servers: - description: Production server url: https://api.quo.com security: - apiKey: [] tags: - description: Operations related to calls name: Calls - description: >- Operations related to call summaries, including AI-generated summaries and Sona voice assistant summaries name: Call Summaries - description: >- Operations related to call transcripts, including AI-generated transcripts and Sona voice assistant transcripts name: Call Transcripts - description: Operations related to contacts name: Contacts - description: Operations related to conversations name: Conversations - description: Operations related to text messages name: Messages - description: Operations related to phone numbers name: Phone Numbers - description: Operations related to users name: Users - description: Operations related to webhooks name: Webhooks paths: /v1/call-summaries/{callId}: get: tags: - Calls summary: Get a summary for a call description: >- Retrieve a detailed summary of a specific call identified by its unique call ID. This endpoint supports summaries for both regular calls and calls handled by Sona. Call summaries are only available on business and scale plans. operationId: getCallSummary_v1 parameters: - in: path name: callId required: true schema: description: The unique identifier of the call associated with the summary. examples: - AC3700e624eca547eb9f749a06f pattern: ^AC(.*)$ type: string example: AC3700e624eca547eb9f749a06f responses: '200': description: OK content: application/json: schema: type: object required: - data properties: data: type: object required: - callId - nextSteps - status - summary properties: callId: description: >- The unique identifier of the call to which this summary belongs. examples: - ACea724hac8c30465bcbcff0b76e4c1c7b type: string example: ACea724hac8c30465bcbcff0b76e4c1c7b nextSteps: anyOf: - type: array items: examples: - Bring an umbrella. type: string example: Bring an umbrella. - type: 'null' status: type: string enum: - absent - in-progress - completed - failed description: The status of the call summary. examples: - completed example: completed summary: anyOf: - type: array items: examples: - You talked about the weather. type: string example: You talked about the weather. - type: 'null' jobs: anyOf: - type: array items: type: object required: - icon - name - result properties: ``` -------------------------------- ### OpenAPI Specification for Get Task by ID Source: https://www.quo.com/docs/mdx/api-reference/tasks/gets-a-task-by-id Defines the GET /v1/tasks/{taskId} endpoint, including the required taskId path parameter and the expected response schema. ```yaml openapi: 3.1.0 info: title: Quo Public API version: 1.0.0 description: API for connecting with Quo. contact: name: Quo Support email: support@quo.com url: https://support.quo.com/ termsOfService: https://www.quo.com/terms servers: - description: Production server url: https://api.quo.com security: - apiKey: [] tags: - description: Operations related to calls name: Calls - description: >- Operations related to call summaries, including AI-generated summaries and Sona voice assistant summaries name: Call Summaries - description: >- Operations related to call transcripts, including AI-generated transcripts and Sona voice assistant transcripts name: Call Transcripts - description: Operations related to contacts name: Contacts - description: Operations related to conversations name: Conversations - description: Operations related to text messages name: Messages - description: Operations related to phone numbers name: Phone Numbers - description: Operations related to users name: Users - description: Operations related to webhooks name: Webhooks paths: /v1/tasks/{taskId}: get: tags: - Tasks summary: Gets a task by ID description: Retrieve a single task by its ID operationId: getTaskById_v1 parameters: - in: path name: taskId required: true schema: pattern: ^TK(.*)$ type: string responses: '200': description: OK content: application/json: schema: type: object required: - data properties: data: type: object required: - taskId - phoneNumberId - conversationId - activityId - phoneNumberGroupId - orgId - title - description - dueDate - assignedTo - assignedBy - createdAt - createdBy - completed - isDeleted - revision properties: taskId: pattern: ^TK(.*)$ type: string phoneNumberId: anyOf: - pattern: ^PN(.*)$ type: string - type: 'null' conversationId: anyOf: - pattern: ^CN(.*)$ type: string - type: 'null' activityId: anyOf: - pattern: ^AC(.*)$ type: string - type: 'null' phoneNumberGroupId: anyOf: - type: string - type: 'null' orgId: pattern: ^OR(.*)$ type: string title: anyOf: - type: string - type: 'null' description: anyOf: - type: string - type: 'null' dueDate: anyOf: - format: date-time type: string - type: 'null' assignedTo: anyOf: - anyOf: - pattern: ^US(.*)$ type: string - pattern: ^SYU(.*)$ type: string - type: 'null' assignedBy: anyOf: - anyOf: - pattern: ^US(.*)$ type: string - pattern: ^SYU(.*)$ type: string - type: 'null' createdAt: format: date-time ``` -------------------------------- ### Execute Sync Script Source: https://www.quo.com/docs/mdx/guides/sync-contacts Command to initiate the synchronization process via Node.js. ```bash node sync.js ``` -------------------------------- ### Configure Environment Variables Source: https://www.quo.com/docs/mdx/guides/sync-contacts Define required credentials and identifiers in a .env file. ```bash QUO_API_KEY=your_quo_api_key GOOGLE_APPLICATION_CREDENTIALS=path/to/your/credentials.json GOOGLE_SHEET_ID=your_google_sheet_id ``` -------------------------------- ### GET /v1/webhooks/{id} Source: https://www.quo.com/docs/mdx/api-reference/webhooks/get-a-webhook-by-id Retrieves a webhook by its unique identifier. ```APIDOC ## GET /v1/webhooks/{id} ### Description Get a webhook by its unique identifier. ### Method GET ### Endpoint /v1/webhooks/{id} ### Parameters #### Path Parameters - **id** (string) - Required - The unique identifier of a webhook (pattern: ^WH(.*)$) ### Response #### Success Response (200) - **data** (object) - The webhook object containing id, userId, orgId, label, status, url, key, createdAt, updatedAt, deletedAt, events, and resourceIds. ``` -------------------------------- ### Directory Traversal and Routing Source: https://support.quo.com/changelog Logic for recursively walking the workspace to collect valid documentation files and mapping file paths to site routes. ```javascript function walk(dir) { const out = []; const stack = [dir]; while (stack.length) { const current = stack.pop(); const entries = fs.readdirSync(current, { withFileTypes: true }); for (const entry of entries) { const full = path.join(current, entry.name); const rel = path.relative(WORKSPACE_ROOT, full); const relPosix = normalizeToPosix(rel); if (entry.isDirectory()) { if (shouldSkipDir(entry.name)) continue; // Only traverse content roots for default and locale prefixes const isLocaleRoot = relPosix === 'es' || relPosix === 'fr-CA'; const isRoot = relPosix === '' || relPosix === '.'; if (isLocaleRoot) { // Traverse inside locale root only allowed content const allowedChildren = fs.readdirSync(full, { withFileTypes: true }); for (const child of allowedChildren) { const childRel = normalizeToPosix(path.relative(WORKSPACE_ROOT, path.join(full, child.name))); if (child.isDirectory()) { if (ALLOWED_CONTENT_ROOTS.has(child.name)) stack.push(path.join(full, child.name)); } else if (isMdLike(child.name) && ALLOWED_CONTENT_ROOTS.has(child.name)) { out.push(path.join(full, child.name)); } } continue; } if (isRoot) { // At the very top level, traverse only allowed content roots and locale dirs const allowedTopChildren = fs.readdirSync(full, { withFileTypes: true }); for (const child of allowedTopChildren) { const childFull = path.join(full, child.name); if (child.isDirectory()) { if (ALLOWED_CONTENT_ROOTS.has(child.name) || child.name === 'es' || child.name === 'fr-CA') { stack.push(childFull); } } else if (isMdLike(child.name) && ALLOWED_CONTENT_ROOTS.has(child.name)) { out.push(childFull); } } continue; } // For nested directories under allowed roots, traverse normally stack.push(full); continue; } // Files if (!isMdLike(entry.name)) continue; if (EXCLUDE_FILES.has(entry.name)) continue; if (isUnderChangelogDir(relPosix)) continue; // exclude dated changelogs // Keep it; actual allow-list enforcement is handled by limiting traversal above out.push(full); } } return out; } function detectLangAndSlug(posixPath) { // Returns { lang: 'en'|'es'|'fr-CA'|..., slug: 'path/without/ext' } let lang = 'en'; let slug = posixPath.replace(/\.(md|mdx)$/i, ''); if (slug.startsWith('es/')) { lang = 'es'; slug = slug.slice(3); } else if (slug.startsWith('fr-CA/')) { lang = 'fr-CA'; slug = slug.slice('fr-CA/'.length); } return { lang, slug }; } function routeFrom(lang, slug) { if (slug === 'index') { return lang === 'en' ? '/' : `/${lang}`; } return lang === 'en' ? `/${slug}` : `/${lang}/${slug}`; } function getLastModISO(filePath) { try { const out = execSync(`git log -1 ``` -------------------------------- ### GET /v1/tasks/{taskId} Source: https://www.quo.com/docs/mdx/api-reference/tasks/gets-a-task-by-id Retrieve a single task by its ID. ```APIDOC ## GET /v1/tasks/{taskId} ### Description Retrieve a single task by its ID. ### Method GET ### Endpoint /v1/tasks/{taskId} ### Parameters #### Path Parameters - **taskId** (string) - Required - The unique identifier of the task, starting with 'TK'. ### Response #### Success Response (200) - **data** (object) - The task object containing details such as taskId, title, description, and assignment information. ``` -------------------------------- ### POST /tasks Source: https://www.quo.com/docs/mdx/api-reference/tasks/create-a-task Creates a new task in the system. ```APIDOC ## POST /tasks ### Description Creates a new task with the provided details. ### Method POST ### Endpoint /tasks ### Request Body - **title** (string) - Required - The title of the task. - **description** (string) - Required - The description of the task. - **dueDate** (string, date-time) - Optional - The due date of the task. - **assignedTo** (string) - Optional - The ID of the user assigned to the task (pattern: ^US(.*)$). - **activityId** (string) - Optional - The ID of the activity associated with the task (pattern: ^AC(.*)$). ### Response #### Success Response (201) - **data** (object) - The created task data. - **taskId** (string) - The ID of the created task. - **revision** (string) - The revision identifier. - **phoneNumberId** (string) - The associated phone number ID. - **conversationId** (string) - The associated conversation ID. - **activityId** (string) - The associated activity ID. #### Error Response (400) - **message** (string) - Error message. - **code** (string) - Error code '0600400'. - **status** (number) - Status code 400. - **docs** (string) - Link to documentation. - **title** (string) - 'Bad Request'. #### Error Response (401) - **message** (string) - Error message. - **code** (string) - Error code '0600401'. - **status** (number) - Status code 401. - **docs** (string) - Link to documentation. - **title** (string) - 'Unauthorized'. ``` -------------------------------- ### GET /v1/messages/{id} Source: https://www.quo.com/docs/mdx/api-reference/messages/get-a-message-by-id Retrieves a message by its unique identifier. ```APIDOC ## GET /v1/messages/{id} ### Description Get a message by its unique identifier. ### Method GET ### Endpoint /v1/messages/{id} ### Parameters #### Path Parameters - **id** (string) - Required - The unique identifier of a message (pattern: ^AC(.*)$) ### Response #### Success Response (200) - **data** (object) - The message object containing id, to, from, text, phoneNumberId, conversationId, direction, userId, status, createdAt, and updatedAt. ``` -------------------------------- ### Generate sitemap.xml for Mintlify Source: https://support.quo.com/changelog A Node.js utility that scans documentation files, respects locale prefixes, and generates a sitemap.xml at the project root. ```javascript #!/usr/bin/env node /** * Generate sitemap.xml for Mintlify docs. * - Includes only page content (.md/.mdx) * - Includes top-level changelog.mdx but excludes any files under a changelog/ directory * - Handles locales via directory prefixes (e.g., es/, fr-CA/) * - Adds xhtml:link hreflang alternates for available language variants * - Overwrites /sitemap.xml at the project root */ const fs = require('fs'); const path = require('path'); const { execSync } = require('child_process'); const WORKSPACE_ROOT = path.resolve(__dirname, '..'); const OUTPUT_PATH = path.join(WORKSPACE_ROOT, 'sitemap.xml'); const DOCS_JSON_PATH = path.join(WORKSPACE_ROOT, 'docs.json'); // Directories to skip entirely when walking const SKIP_DIRS = new Set([ '.git', '.github', '.next', 'node_modules', 'scripts', 'images', 'logo', '.cache', 'dist', 'build', 'public', ]); // Allow-list of content roots per locale (relative to locale root) const ALLOWED_CONTENT_ROOTS = new Set([ 'index.mdx', 'index.md', 'changelog.mdx', 'changelog.md', 'getting-started', 'core-concepts', 'troubleshooting', 'community', 'help', ]); // File-level excludes const EXCLUDE_FILES = new Set([ ``` -------------------------------- ### File System and Path Utilities Source: https://support.quo.com/changelog Functions for reading JSON files safely, normalizing paths to POSIX format, and filtering directories or files based on project-specific rules. ```javascript function readJsonSafe(filePath) { try { const raw = fs.readFileSync(filePath, 'utf8'); return JSON.parse(raw); } catch (e) { return null; } } function getCanonicalOrigin() { const docs = readJsonSafe(DOCS_JSON_PATH); const defaultOrigin = 'https://support.quo.com'; if (!docs) return defaultOrigin; try { const c = docs.seo && docs.seo.metatags && docs.seo.metatags.canonical; if (typeof c === 'string' && c.trim().length > 0) return c.trim().replace(/\/$/, ''); } catch (_) {} return defaultOrigin; } function getLanguages() { const docs = readJsonSafe(DOCS_JSON_PATH); const langs = ['en']; if (!docs) return langs; try { const arr = docs.navigation && docs.navigation.languages; if (Array.isArray(arr)) { for (const entry of arr) { if (entry && typeof entry.language === 'string' && entry.language.trim()) { if (entry.language === 'en') { if (!langs.includes('en')) langs.unshift('en'); } else if (!langs.includes(entry.language)) { langs.push(entry.language); } } } } } catch (_) {} return langs; } function isMdLike(file) { return file.endsWith('.md') || file.endsWith('.mdx'); } function shouldSkipDir(dirName) { return SKIP_DIRS.has(dirName); } function normalizeToPosix(relativePath) { return relativePath.split(path.sep).join('/'); } function isUnderChangelogDir(posixPath) { // Exclude any path that contains "/changelog/" (localized or not) return /(^|\/)changelog\//.test(posixPath); } function isAllowedContentRelativeToLocaleRoot(posixRel) { // posixRel is relative to a locale root (e.g., '', 'es', 'fr-CA') const firstSegment = posixRel.split('/')[0]; if (!firstSegment) return false; if (ALLOWED_CONTENT_ROOTS.has(firstSegment)) return true; // directories // Also allow direct index/changelog at root if (ALLOWED_CONTENT_ROOTS.has(posixRel)) return true; return false; } ``` -------------------------------- ### GET /conversations Source: https://www.quo.com/docs/mdx/api-reference/conversations/list-conversations Retrieves a paginated list of conversations associated with the account. ```APIDOC ## GET /conversations ### Description Retrieves a list of conversations. The response includes a list of conversation objects and pagination metadata. ### Method GET ### Endpoint /conversations ### Response #### Success Response (200) - **items** (array) - List of conversation objects - **totalItems** (integer) - Total number of items available - **nextPageToken** (string|null) - Token for the next page of results #### Error Response (400) - **message** (string) - Error description - **code** (string) - Error code '1000400' - **status** (number) - Status code 400 #### Error Response (401) - **message** (string) - Error description - **code** (string) - Error code '1000401' - **status** (number) - Status code 401 ``` -------------------------------- ### Implement OptimizedImage and Heading Components Source: https://support.quo.com/changelog Use these components to render optimized images and structured headings within the application. Ensure the OptimizedImage component receives the necessary source, dimensions, and optimization flags. ```javascript _jsx(OptimizedImage, { src: "https://mintcdn.com/resource-center/atx7o8UPo0wTsPfo/images/749-85d39180c3bb4cf719bea292abc1d769ed49b0bf.png?fit=max&auto=format&n=atx7o8UPo0wTsPfo&q=85&s=37ae7f3d342d93d67afdfbce36567967", alt: "OP Merge Contacts.png", "data-og-width": "1120", width: "1120", "data-og-height": "850", height: "850", "data-path": "images/749-85d39180c3bb4cf719bea292abc1d769ed49b0bf.png", "data-optimize": "true", "data-opv": "3", srcset: "https://mintcdn.com/resource-center/atx7o8UPo0wTsPfo/images/749-85d39180c3bb4cf719bea292abc1d769ed49b0bf.png?w=280&fit=max&auto=format&n=atx7o8UPo0wTsPfo&q=85&s=dafbb1f3ee574586162ccbf7a1c4a991 280w, https://mintcdn.com/resource-center/atx7o8UPo0wTsPfo/images/749-85d39180c3bb4cf719bea292abc1d769ed49b0bf.png?w=560&fit=max&auto=format&n=atx7o8UPo0wTsPfo&q=85&s=cd8148c4c2a2cb0062798337732ac75d 560w, https://mintcdn.com/resource-center/atx7o8UPo0wTsPfo/images/749-85d39180c3bb4cf719bea292abc1d769ed49b0bf.png?w=840&fit=max&auto=format&n=atx7o8UPo0wTsPfo&q=85&s=1fdb9b248a4ad57fc73d02562b24a1bc 840w, https://mintcdn.com/resource-center/atx7o8UPo0wTsPfo/images/749-85d39180c3bb4cf719bea292abc1d769ed49b0bf.png?w=1100&fit=max&auto=format&n=atx7o8UPo0wTsPfo&q=85&s=55079f3b9d1cf304d816d2127aa716f4 1100w, https://mintcdn.com/resource-center/atx7o8UPo0wTsPfo/images/749-85d39180c3bb4cf719bea292abc1d769ed49b0bf.png?w=1650&fit=max&auto=format&n=atx7o8UPo0wTsPfo&q=85&s=b4c6bbd67883f552fd6c3fbab8605e04 1650w, https://mintcdn.com/resource-center/atx7o8UPo0wTsPfo/images/749-85d39180c3bb4cf719bea292abc1d769ed49b0bf.png?w=2500&fit=max&auto=format&n=atx7o8UPo0wTsPfo&q=85&s=a9e7769a873c241a079a4e0137a59352 2500w" }), _jsx(Heading, { level: "2", id: "improved-search-%F0%9F%94%8D", children: "Improved search 🔍" }) ``` -------------------------------- ### GET /v1/phone-numbers/{phoneNumberId} Source: https://www.quo.com/docs/mdx/api-reference/phone-numbers/get-a-phone-number-by-id Retrieves the details of a phone number by its unique identifier. ```APIDOC ## GET /v1/phone-numbers/{phoneNumberId} ### Description Get a phone number by its unique identifier. ### Method GET ### Endpoint /v1/phone-numbers/{phoneNumberId} ### Parameters #### Path Parameters - **phoneNumberId** (string) - Required - Unique identifier of the phone number. ### Response #### Success Response (200) - **data** (object) - The phone number object containing details such as id, groupId, formattedNumber, and status. ```