# How to Integrate Retool with Quip

- Tool: Retool
- Difficulty: Intermediate
- Time required: 20 minutes
- Last updated: April 2026

## TL;DR

Connect Retool to Quip by creating a REST API Resource using a Quip personal access token sent as a Bearer token. Since Quip is owned by Salesforce, it integrates naturally alongside Salesforce data in Retool. Use Quip's API to build a content management panel that creates, reads, and updates collaborative documents and spreadsheets — combining Quip content with Salesforce CRM data in a unified operations panel.

## Build a Quip Document Management Panel in Retool

Quip is deeply embedded in Salesforce-centric organizations — sales teams use Quip for account plans, mutual success plans, and deal-related documents that live alongside their Salesforce opportunities and accounts. Operations teams often need to manage Quip content at scale: creating templated documents for new accounts, linking Quip plans to Salesforce records, or reviewing document activity across a sales team. Retool provides the administrative interface for these bulk content operations.

With a Retool-Quip integration, your operations team can list all documents in a shared workspace, search Quip content by keyword, create new documents from templates for specific accounts or deals, and monitor document engagement (views, edits, comments) across the team. When combined with a Salesforce connection in the same Retool app, you can build a unified account management panel that shows Salesforce opportunity data alongside associated Quip account plans — all in one view without tab-switching.

Quip's API provides access to threads (the unified term for documents, spreadsheets, and chats), folders, and users. The personal access token authentication is straightforward, and the API returns JSON with consistent response structures. The primary use case for Retool-Quip integration is content operations for sales and account management teams working in Salesforce-heavy environments.

## Before you start

- A Quip account with API access (standard Quip accounts include API access; Quip for Salesforce enterprise accounts also support API)
- A Quip personal access token (Quip.com → Edit Profile → Developers → Get Personal Access Token)
- The Quip folder ID you want to access (visible in the URL when viewing a folder: quip.com/browse/folder/FOLDERID)
- A Retool account with permission to create Resources
- Optional: a Salesforce connection in the same Retool workspace if you want to combine Quip with CRM data

## Step-by-step guide

### 1. Generate a Quip personal access token and create a Retool Resource

To access Quip's API, generate a personal access token from your Quip account. Log into Quip and click your profile picture in the top left. Select 'Edit Profile' from the dropdown. On your profile page, scroll down to find the 'Developers' section and click 'Get Personal Access Token'. Quip generates a token immediately and displays it once — copy it now and store it securely. This token gives full API access to your Quip account including all documents you can see.

Now go to the Resources tab in your Retool instance and click Add Resource. Select REST API from the resource type list. Name the resource 'Quip API'.

In the Base URL field, enter https://platform.quip.com/1. This is Quip's API v1 base URL — all endpoint paths are appended to this. Do not include a trailing slash.

For authentication, select Bearer Token from the Authentication dropdown. In the Token field, enter your Quip personal access token.

For better security, store your token as a Retool configuration variable first: go to Settings → Configuration Variables, create a variable named QUIP_ACCESS_TOKEN, mark it as Secret, and use {{ retoolContext.configVars.QUIP_ACCESS_TOKEN }} in the Token field instead of the raw value.

Add a Content-Type header: key = Content-Type, value = application/json. Click Save Changes.

**Expected result:** The Quip API REST Resource is saved in Retool with Bearer token authentication configured. Testing with a simple GET to /users/current confirms authentication is working and returns your Quip user profile.

### 2. Query Quip folders and browse document threads

Quip's API organizes content around threads (documents, spreadsheets) and folders. The folder endpoint returns the folder structure and lists contained threads. The thread endpoint returns individual document content and metadata.

Create a query named getFolderContents and select the Quip API resource. Set Method to GET. In the Path field, enter /folders/{{ textInput_folderId.value || 'PRIVATE' }}. The folder ID comes from the Quip URL when viewing a folder. 'PRIVATE' is a special keyword that returns your personal folder tree.

The folder response includes a folder object with children — each child has a thread_id (for documents) or folder_id (for nested folders). Quip returns IDs rather than full objects, so you need a second query to fetch thread details.

Create a query named getThread (GET, /threads/{{ textInput_threadId.value }}) for fetching individual document metadata and content. This returns the thread object with fields including title, link, author_id, created_usec, updated_usec, and thread_class (document, spreadsheet, or chat).

For listing multiple threads at once, Quip supports a batch endpoint: POST /threads to get multiple threads by their IDs in a single request. This is more efficient than making individual GET requests for each thread in a folder.

Create a JavaScript query named buildDocumentList that combines the folder contents with batch thread fetching to build a complete listing:

Bind the result to a Table component with columns for title, thread_class, last modified date, and a link to open the document in Quip.

```
// JavaScript transformer — format Quip thread list from folder contents
// 'data' is the response from the batch threads endpoint
const threads = data || {};
return Object.values(threads).map(thread => ({
  id: thread.thread?.id || '',
  title: thread.thread?.title || 'Untitled',
  type: thread.thread?.thread_class || 'document',
  link: thread.thread?.link || '',
  author_id: thread.thread?.author_id || 'N/A',
  created: thread.thread?.created_usec
    ? new Date(thread.thread.created_usec / 1000).toLocaleDateString('en-US', {
        year: 'numeric', month: 'short', day: 'numeric'
      })
    : 'N/A',
  last_modified: thread.thread?.updated_usec
    ? new Date(thread.thread.updated_usec / 1000).toLocaleDateString('en-US', {
        year: 'numeric', month: 'short', day: 'numeric'
      })
    : 'N/A',
  is_stale: thread.thread?.updated_usec
    ? (Date.now() - thread.thread.updated_usec / 1000) > 30 * 24 * 60 * 60 * 1000
    : false
}));
```

**Expected result:** The folder contents query returns a list of thread IDs. The batch thread fetch retrieves metadata for all documents at once. The transformer formats the combined data into a Table-ready format with readable dates and a staleness flag for documents not updated in 30+ days.

### 3. Create Quip documents from Retool Forms

Build document creation functionality that allows your team to generate new Quip documents (account plans, meeting notes, status reports) directly from Retool.

Add a Form section to your Retool app with these input components:
- TextInput named input_title for the document title
- TextArea named input_content for the document body text
- Select named select_folder for choosing the destination folder

Create a query named createDocument. Set Method to POST. Path = /threads/new-document. Set Body type to Form (not JSON — Quip's document creation uses form-encoded data). Add form body parameters:
- key: title, value: {{ input_title.value }}
- key: content, value: {{ input_content.value }} (HTML content is supported)
- key: member_ids, value: {{ select_folder.value }} (the folder ID to add the document to)

For richer document content, Quip accepts HTML in the content field. Use a TextArea or a Code editor component in Retool for users to input formatted content, or pre-format the content in your query body using template literals.

Add a 'Create Document' button that triggers createDocument. In the On Success event handler, show a notification 'Document created successfully', and add a Link component that opens the created document: {{ createDocument.data.thread.link }}.

Trigger getFolderContents to refresh the document list after creation so the new document appears immediately.

For Salesforce-integrated workflows where documents need to link back to Salesforce records, add a second step in the event handler that updates the Salesforce record via your Salesforce resource with the new Quip thread URL.

```
// Quip document creation — form-encoded body
// Method: POST
// Path: /threads/new-document
// Body type: x-www-form-urlencoded

// Parameters to send:
title={{ input_title.value }}
content=<h1>{{ input_title.value }}</h1><h2>Overview</h2><p>{{ input_overview.value }}</p><h2>Next Steps</h2><p>{{ input_next_steps.value }}</p>
member_ids={{ select_folder.value }}

// After creation, the response includes:
// thread.id — the new document's thread ID
// thread.link — the shareable URL to open in Quip
// thread.title — confirms the title was saved
```

**Expected result:** Filling in the title, content, and destination folder, then clicking 'Create Document' sends the POST request to Quip and returns the new document's URL. The document link opens the newly created Quip document. The folder view refreshes to show the new document.

### 4. Combine Quip documents with Salesforce opportunity data

Since Quip is a Salesforce product, the most powerful Retool integration combines Quip document management with Salesforce CRM data. Add your Salesforce connection as a second resource in the same Retool app.

Create a Salesforce query named getOpenOpportunities. If using the native Salesforce connector: Action = SOQL Query, Query = SELECT Id, Name, Account.Name, Amount, CloseDate, StageName, Quip_Document_URL__c FROM Opportunity WHERE StageName NOT IN ('Closed Won', 'Closed Lost') ORDER BY CloseDate ASC LIMIT 50. The Quip_Document_URL__c field is a custom field where your team stores the associated Quip document link (adjust the API name to match your org's field).

Bind getOpenOpportunities to a Table. When a rep selects an opportunity, check whether a Quip document exists: if Quip_Document_URL__c is populated, show a 'View Account Plan' button linking to the document. If empty, show a 'Create Account Plan' button that triggers the document creation workflow.

For 'Create Account Plan': trigger the createDocument query with a pre-formatted template that includes the opportunity name, account name, and close date. On success, update the Salesforce opportunity to store the new Quip thread URL in Quip_Document_URL__c using a PATCH/update Salesforce query.

For viewing existing documents, add a Quip document preview by fetching the thread content (GET /threads/{id}/html) and rendering it in a Retool Custom Component or displaying a summary of the document sections.

RapidDev's team can help design more complex Quip-Salesforce workflows, such as automatically generating account plans for all new opportunities above a certain ARR threshold using Retool Workflows triggered by Salesforce record creation events.

```
// SOQL query — get opportunities with Quip document status
// Use in Salesforce resource query, Action: SOQL Query
SELECT
  Id,
  Name,
  Account.Name,
  Amount,
  CloseDate,
  StageName,
  OwnerId,
  Owner.Name,
  Quip_Document_URL__c
FROM Opportunity
WHERE StageName NOT IN ('Closed Won', 'Closed Lost')
  AND Amount >= 10000
ORDER BY CloseDate ASC
LIMIT 100
```

**Expected result:** The opportunities table shows all open deals with a status indicator for whether a Quip account plan exists. Deals without a plan show a 'Create Account Plan' button. Deals with an existing plan show a 'View Account Plan' link that opens the Quip document. Creating a plan updates the Salesforce record automatically.

### 5. Search Quip documents and manage document metadata

Add search functionality to let users find Quip documents by keyword, author, or date range without knowing the exact folder structure.

Create a query named searchThreads. Set Method to GET. Path = /threads/search. Add URL parameters:
- key = query, value = {{ textInput_search.value }}
- key = count, value = 20

Quip's search endpoint returns matching threads ordered by relevance. Bind results to a Table showing title, thread type, and last modified date.

Create a query named getUserProfile (GET, /users/{{ userId }}) to resolve author IDs returned by thread queries into human-readable names. Build a user ID-to-name lookup by first fetching /users/current and then resolving individual IDs as needed.

For document organization, create a query named addMember to add a user or folder to an existing thread's member list:
- Method: POST
- Path: /threads/{{ table_threads.selectedRow.id }}/add-members
- Body: Form encoded, key = member_ids, value = {{ textInput_member_email.value }}

Create a query named exportThread to get a thread's full HTML content for export or preview:
- Method: GET
- Path: /threads/{{ table_threads.selectedRow.id }}/html

Display the HTML content in a Retool HTML display component or a Custom Component for a document preview panel.

```
// JavaScript transformer — format Quip search results
const results = data || {};
// Quip search returns an object keyed by thread ID
return Object.entries(results).map(([id, thread]) => {
  const t = thread.thread || {};
  return {
    id,
    title: t.title || 'Untitled',
    type: t.thread_class || 'document',
    link: t.link || '',
    created: t.created_usec
      ? new Date(t.created_usec / 1000).toLocaleDateString('en-US')
      : 'N/A',
    last_modified: t.updated_usec
      ? new Date(t.updated_usec / 1000).toLocaleDateString('en-US')
      : 'N/A',
    // Days since last edit
    days_since_update: t.updated_usec
      ? Math.floor((Date.now() - t.updated_usec / 1000) / (1000 * 60 * 60 * 24))
      : null
  };
}).sort((a, b) => (a.days_since_update || 0) - (b.days_since_update || 0));
```

**Expected result:** The search input triggers a Quip search query and populates the results Table with matching documents sorted by recency. The days-since-update column helps identify stale documents. Selecting a result shows the document detail and enables member management actions.

## Best practices

- Store your Quip personal access token as a Secret configuration variable in Retool rather than pasting it directly into the Resource — this prevents the token from being visible in resource configuration history.
- Use a shared team Quip account for the API token rather than a personal account, so the Retool integration doesn't break when an individual team member leaves or changes their password.
- Convert Quip's microsecond timestamps (divide by 1000) in JavaScript transformers before passing to JavaScript's Date constructor — this is a common source of incorrect date display.
- Use Quip's batch thread endpoint (POST /threads with comma-separated IDs) instead of individual GET requests per thread when loading folder contents — this reduces API call volume significantly for large folders.
- Pair Quip with Salesforce data in the same Retool app — since Quip is a Salesforce product, combining account plans from Quip with opportunity data from Salesforce is the highest-value integration pattern.
- Store Quip thread URLs (not just thread IDs) in Salesforce custom fields so document links remain accessible even without the Retool panel.
- Add visibility conditions to document action buttons (Create Plan, View Plan) based on whether a Quip URL already exists in the linked Salesforce record, preventing duplicate document creation.
- For team-wide document audits (finding stale account plans), use the days_since_update calculation in your transformer to highlight documents that need attention rather than manually scanning folder contents.

## Use cases

### Build a team document library browser

Create a Retool app that shows all Quip documents in a shared folder, with columns for title, last editor, last modified date, and view count. Add a search input to filter documents by title, and a detail panel that shows the document's member list and recent messages when a row is selected.

Prompt example:

```
Build a document browser that queries /1/folders/{folderId} to get the folder tree, then fetches individual thread details for each document, displays document name, author, last_modified_usec formatted as a date, and member count in a Table, with a detail panel showing thread_class and section count for the selected document.
```

### Account plan creator linked to Salesforce opportunities

Build a Retool panel where account managers can select a Salesforce opportunity, fill in key deal details through a Form, and automatically create a structured Quip account plan document using a Quip template. The new document URL is then saved back to the Salesforce opportunity record as a custom field.

Prompt example:

```
Create an account plan generator with an opportunity selector (from Salesforce), form fields for discovery notes and next steps, a 'Create Account Plan' button that POSTs to /1/threads/new-document with formatted content, and a follow-up PATCH to Salesforce to store the returned thread_id as the account plan link on the opportunity.
```

### Sales team content activity dashboard

Build a management dashboard showing each sales rep's Quip document activity — documents created this week, last edit dates, and documents that haven't been updated in 30+ days. This helps sales managers identify stale account plans and encourage timely updates ahead of QBRs.

Prompt example:

```
Build a content activity panel that fetches threads from the team folder, groups by author_id using a JavaScript transformer, shows each rep's name with document count, last_modified_date, and a count of stale documents (not modified in 30+ days), with a Chart showing documents updated per day for the past 14 days.
```

## Troubleshooting

### All Quip API requests return 401 Unauthorized

Cause: The personal access token is invalid, expired, or incorrectly configured as a header instead of a Bearer token in the authentication field.

Solution: Verify your Quip personal access token by navigating to Quip.com → Edit Profile → Developers. Check that the token value in your Retool Resource matches exactly. Confirm that the Retool Resource Authentication type is set to Bearer Token (not a manual Authorization header). Test with a simple GET to /users/current to verify authentication before building complex queries.

### Folder contents query returns thread IDs but no document titles or metadata

Cause: Quip's folder endpoint returns child thread IDs rather than full thread objects. A separate thread lookup is required to get document titles, dates, and other metadata.

Solution: After fetching folder contents, extract the thread IDs from children and make a batch thread request. POST to /threads with the thread IDs as a comma-separated list to retrieve all thread metadata in a single API call rather than individual GET requests per thread ID.

```
// Batch thread fetch — Method: POST, Path: /threads
// Body (form-encoded):
// ids = threadId1,threadId2,threadId3
// Build the IDs from folder children:
ids={{ getFolderContents.data.children
  .filter(c => c.thread_id)
  .map(c => c.thread_id)
  .join(',') }}
```

### Document creation POST returns 400 Bad Request

Cause: Quip's thread creation endpoint requires form-encoded body data (application/x-www-form-urlencoded), not JSON. Sending a JSON body will result in a 400 error.

Solution: In your Retool query, set the Body type to 'Form' or 'x-www-form-urlencoded' rather than JSON. Add each parameter as a separate form field key-value pair. The content, title, and member_ids parameters must all be sent as form fields, not as a JSON object.

### Quip timestamps show as very large numbers in Retool Table columns

Cause: Quip uses microseconds (millionths of a second) for timestamps, not milliseconds. JavaScript's Date constructor expects milliseconds, so dividing by 1000 is required before conversion.

Solution: In your JavaScript transformer, convert Quip timestamps using new Date(thread.updated_usec / 1000).toLocaleDateString() — dividing by 1000 converts microseconds to milliseconds before passing to the Date constructor.

```
// Correct Quip timestamp conversion
last_modified: new Date(thread.updated_usec / 1000).toLocaleDateString('en-US', {
  year: 'numeric', month: 'short', day: 'numeric'
})
```

## Frequently asked questions

### Does Quip have a native connector in Retool?

No, Quip does not have a native connector in Retool. You connect via a REST API Resource using Quip's personal access token with Bearer authentication. Quip's REST API (https://platform.quip.com/1) provides access to threads, folders, users, and messages — covering the main operations needed for document management and content creation workflows.

### What's the difference between a Quip thread and a document?

In Quip's data model, a 'thread' is the universal term for any collaborative item — whether it's a document, spreadsheet, slide deck, or chat. When you create a new document in Quip's UI, it's stored as a thread with thread_class set to 'document'. A spreadsheet has thread_class 'spreadsheet'. The Quip API uses 'thread' consistently for all content types, so you'll see this term throughout the API responses regardless of the content type.

### Can I embed Quip documents directly inside a Retool app?

Quip does not officially support iframe embedding in external applications without an enterprise Salesforce agreement. You can display Quip document content in Retool by fetching the HTML content via GET /threads/{id}/html and rendering it in a Retool Custom HTML component, but this shows document content as static HTML rather than the full interactive Quip experience.

### How does Quip authentication work for team accounts?

Each Quip user generates their own personal access token from their account settings. This token provides access to all content the user can see in Quip — their private documents and all shared team folders they're a member of. For a Retool integration serving a whole team, generate the token from a dedicated service account that's a member of all the relevant Quip folders, so the Retool app has consistent access to all needed content.

### Can Retool receive real-time updates when Quip documents are changed?

Quip supports webhooks for document and folder events (thread created, message posted, etc.) that can be received by Retool Workflows. Create a Retool Workflow with a webhook trigger to get a URL, then configure Quip to send event notifications to that URL using Quip's automation features or the /webhooks API endpoint. The workflow processes the event and can trigger actions in Retool or update a Retool Database with the change event.

---

Source: https://www.rapidevelopers.com/retool-integrations/quip
© RapidDev — https://www.rapidevelopers.com/retool-integrations/quip
