Skip to content

SharePoint to Quip Migration: API Limits, Export Methods & Data Mapping

No native import path exists from SharePoint to Quip. Learn the real API limits, export methods, data mapping, and step-by-step workflow to migrate content.

Raaj Raaj · · 15 min read
SharePoint to Quip Migration: API Limits, Export Methods & Data Mapping

There is no native migration path from SharePoint to Quip. Quip retired its Upload/Import option and the Import API endpoint on January 19, 2024 — and Salesforce has since announced the full retirement of Quip, with subscriptions no longer renewable after March 1, 2027. If you are migrating SharePoint content into Quip today, you are working against two hard constraints: a target platform with no import tool and a ticking end-of-life clock.

This guide covers the real methods for moving SharePoint site pages, document libraries, and lists into Quip, the hard API constraints on both sides, the field-mapping decisions that determine whether your migration preserves data or silently drops it, and a practical workflow for API-driven migration.

Danger

Quip End-of-Life (March 2027): Salesforce is retiring all Quip products. Subscriptions cannot be renewed after March 1, 2027. After your subscription expires, the site enters a 90-day read-only phase, followed by blocked logins, then data deletion. If you are migrating into Quip for short-term Salesforce ecosystem consolidation, plan your exit strategy at the same time.

Why SharePoint to Quip Migrations Require Custom Engineering

SharePoint and Quip store content in fundamentally incompatible ways. SharePoint stores pages as .aspx files built from complex Web Part JSON structures via a canvasLayout of horizontalSections and webParts. Lists are typed columns backed by SQL-style storage. Document libraries hold versioned files with rich metadata columns, managed metadata, and granular permissions.

Quip stores everything as threads — documents containing rich text (HTML or Markdown), embedded spreadsheets, and a conversation pane. There are no Web Parts, no content types, no managed metadata taxonomy, and no permission inheritance model. A Quip spreadsheet is a flat grid with a hard 100,000-cell ceiling.

The structural mismatch means there is no drag-and-drop path. Every migration from SharePoint to Quip is a two-track operation: extract page content and list data via Microsoft Graph API, transform it into HTML/Markdown that Quip can accept, then push it through Quip's Automation API one document at a time.

Because Quip retired its bulk import tools, teams often evaluate third-party cloud migration tools. Most fall short for this specific pathway:

  • CloudFuze: Handles raw file transfers between Microsoft 365 and other drives, but lacks the transformation capabilities needed to convert SharePoint Web Parts into Quip's proprietary HTML/Markdown document structure.
  • Tzunami Deployer: A veteran enterprise content management (ECM) tool optimized for SharePoint-to-SharePoint moves. It forces a heavy, offline modeling process and has no specific handling for Quip's strict 50 requests/minute API rate limits.

To move structured content accurately, you need a pipeline designed specifically for these two APIs.

For a deep dive on getting data out of SharePoint, see our guide on How to Export Data from SharePoint: Methods, Limits & Migration Prep.

Best Migration Method for Each Use Case

Method Fidelity Lists/Tables Page Content Attachments Best For
Manual Copy-Paste Low Partial Partial Manual re-upload <20 pages, one-off moves
CSV Export → Quip Spreadsheet API Low–Medium ✅ (≤30K rows) Small lists (<50 columns)
Graph API + Quip Automation API (Custom Scripts) High ✅ (text + basic formatting) ✅ (separate blob upload) Full workspace migrations
ClonePartner Managed Migration Highest Complex sites, zero downtime

The hard constraints behind that summary: SharePoint's native CSV export caps at 30,000 list items with no workaround through the UI. Quip spreadsheets cap at 100,000 cells and 1,000 rows per API call. Modern SharePoint page content only comes from the Graph canvasLayout endpoint. And Quip's retired import tool means every document must be created via API.

Exporting Data from SharePoint: Graph API & Limitations

Site Pages (Articles, News Posts, Wiki-Style Content)

SharePoint modern pages are stored as .aspx files in the Site Pages library. The actual content lives inside a canvasLayout structure — a JSON tree of horizontal sections, columns, and web parts. To extract page content programmatically, use the Microsoft Graph Pages API:

GET /sites/{site-id}/pages/{page-id}/microsoft.graph.sitePage?$expand=canvasLayout

This returns the full page structure including horizontalSections, each containing columns and webparts. Text web parts expose an innerHtml property with the actual content. Image web parts, embed web parts, and custom SPFx web parts each have their own data structure that requires individual handling.

Warning

SDK Gotcha: When using the Microsoft Graph SDK for .NET, expanding canvasLayout on a baseSitePage throws a parsing error. You must cast to sitePage type explicitly or construct the URL manually. This is a known issue tracked in the Graph SDK repos.

Document Libraries (Word, Excel, PDF Files)

For files in document libraries, use the Graph driveItem endpoints:

GET /sites/{site-id}/drives/{drive-id}/items/{item-id}/content

Large file exports (50MB+) that attempt server-side PDF conversion via ?format=pdf frequently fail with HTTP 406 Not Acceptable or HTTP 500 Internal Server errors. The Office conversion service behind this endpoint has undocumented file-size thresholds. Download in native format and convert locally, or map files directly into Quip's document format.

SharePoint Lists

For lists under 30,000 items, the built-in Export to CSV works but silently drops version history, attachments, and lookup field references. For larger lists, use PnP PowerShell with Get-PnPListItem -PageSize 1000 and paginate through the full dataset.

The Graph API alternative:

GET /sites/{site-id}/lists/{list-id}/items?$expand=fields(select=Title,Created,Author,...)

Microsoft limits a single query to 12 lookup field expansions. Managed metadata columns require additional parsing — they return as term objects, not plain text. Your script must check for the @odata.nextLink property in each response and follow it until all items are retrieved.

Graph API Throttling: What Your Script Must Handle

SharePoint Online dynamically throttles API requests based on current server load. When limits are exceeded, the service returns HTTP 429 (Too Many Requests) or HTTP 503 (Server Too Busy), both with a Retry-After header indicating how many seconds to wait.

Real-world Retry-After values from SharePoint can reach 300+ seconds — far higher than most developers expect. If your script ignores the Retry-After header or retries immediately, SharePoint may escalate to a full application block and notify the tenant admin via the Office 365 Message Center.

import requests
import time
 
def graph_request_with_retry(url, headers, max_retries=5):
    for attempt in range(max_retries):
        response = requests.get(url, headers=headers)
        if response.status_code == 200:
            return response.json()
        if response.status_code in (429, 503):
            retry_after = int(response.headers.get('Retry-After', 30))
            print(f"Throttled. Waiting {retry_after}s (attempt {attempt+1})")
            time.sleep(retry_after)
        else:
            response.raise_for_status()
    raise Exception("Max retries exceeded")

Microsoft recommends choosing Graph APIs over CSOM and REST when possible — Graph consumes fewer resource units per request, reducing the likelihood of throttling.

For a detailed look at SharePoint's metadata and folder architecture, see Mastering SharePoint Information Architecture 2026.

Importing into Quip: API Rate Limits and Payload Formatting

Quip Automation API Rate Limits

Quip's Automation API enforces strict per-user and per-company rate limits:

Limit Default Value
Per-user requests 50 per minute
Per-company requests 600 per minute
Admin API per-admin 100 per minute / 1,500 per hour
Spreadsheet rows per call 1,000
Spreadsheet cells per sheet 100,000 (max) / 30,000 (recommended)
Document size ~1 MB per creation call
API keys per company 100
Danger

HTTP 503 Trap: Quip returns HTTP 503 — not the standard 429 — when rate-limited. Standard retry middleware will misclassify this as a server error, potentially triggering alert storms or aggressive retry loops that make throttling worse. Your retry logic must explicitly check for 503 with the X-Ratelimit-Remaining header at 0 and use exponential backoff.

The API response headers X-Ratelimit-Limit, X-Ratelimit-Remaining, and X-Ratelimit-Reset provide real-time rate limit state. At the company level, X-Company-RateLimit-Remaining and X-Company-Retry-After serve the same purpose. Build your migration pipeline to read these headers on every response and throttle preemptively — don't wait for the 503.

For identical Quip API constraints applied to a different source platform, see our Notion to Quip Migration: API Limits & Database Mapping guide.

Creating Documents via API

With the native import tool retired, the only programmatic way to create documents in Quip is the new-document endpoint:

POST https://platform.quip.com/1/threads/new-document

Key parameters:

  • content — HTML or Markdown body of the document
  • formathtml (default) or markdown
  • title — Document title (overridden by the first heading in content if they differ)
  • member_ids — Comma-separated folder IDs or user IDs for placement and access
  • typedocument or spreadsheet

Quip's HTML parser is opinionated. It accepts standard tags (<h1><h3>, <p>, <ul>, <ol>, <table>, <b>, <i>, <a>) but silently strips unsupported attributes, CSS classes, inline styles, and most data-* attributes. SharePoint's innerHtml from web parts often contains Microsoft-specific class names and inline styles that Quip will discard without warning.

import requests
import time
 
def push_to_quip(payload, token, max_retries=5):
    headers = {"Authorization": f"Bearer {token}"}
    for attempt in range(max_retries):
        response = requests.post(
            "https://platform.quip.com/1/threads/new-document",
            headers=headers,
            json=payload
        )
        if response.status_code == 503:
            # Quip returns 503 for rate limits. Apply exponential backoff.
            wait = min(60 * (2 ** attempt), 300)
            time.sleep(wait)
            continue
        response.raise_for_status()
        return response.json()
    raise Exception("Max retries exceeded")

Creating Spreadsheets via API

For SharePoint list data migrating into Quip spreadsheets, use the same new-document endpoint with type=spreadsheet and an HTML table as the content:

import quip
import time
 
client = quip.QuipClient(access_token=ACCESS_TOKEN)
 
# Create spreadsheet with HTML table template
html_template = """
<table>
  <thead>
    <tr><th>Title</th><th>Status</th><th>Due Date</th></tr>
  </thead>
  <tbody>
  </tbody>
</table>
"""
result = client.new_document(html_template, title="Project Tracker", type="spreadsheet")
thread_id = result['thread']['id']
 
# Add rows in batches of up to 1,000
for batch in chunked_rows(sharepoint_data, size=1000):
    markdown_rows = "\n".join(
        f"| {row['Title']} | {row['Status']} | {row['DueDate']} |" 
        for row in batch
    )
    client.edit_document(
        thread_id=thread_id,
        content=markdown_rows,
        format="markdown",
        operation=client.APPEND
    )
    time.sleep(1.5)  # Stay well under 50 req/min

The 100,000-cell hard limit means a SharePoint list with 20 columns can hold at most 5,000 rows in a single Quip spreadsheet. Larger lists must be split across multiple Quip spreadsheets or aggregated before import.

Mapping SharePoint Metadata and Permissions to Quip

Field Mapping Reference

SharePoint Field Quip Equivalent Handling
Title Document title / spreadsheet column Direct map
Created / Modified Not preserved natively Store as metadata columns in spreadsheet or document header
Author / Editor Thread member (if user exists) Map to Quip user IDs; fall back to text field
Content Type None Flatten to a text tag or prefix
Managed Metadata (Taxonomy) None Extract term label as plain text column
Choice columns Spreadsheet text column Direct map; no dropdown enforcement
Lookup columns None (no relational links) Resolve to display value before import
Attachments Blob upload → inline reference Separate upload step per attachment
Version History None Archive as a separate document or CSV
Permissions (Unique/Inherited) member_ids on thread Manual re-assignment; no inheritance model
Web Parts (Image, Embed, Custom) Inline HTML (partial) Text web parts → HTML; others require manual rebuild
Page Layout / Sections Flat document Section structure lost; content flattened to linear flow

Preserving Metadata in Quip

SharePoint relies heavily on custom columns and metadata tags to organize document libraries. Quip does not support custom document-level metadata outside of embedded spreadsheets or Salesforce record links.

To preserve this data, you have two practical options:

  1. Front-matter tables: Inject a standard HTML table at the top of every Quip document containing the SharePoint metadata (Author, Original Creation Date, Custom Tags).
  2. Salesforce record mapping: If the Quip document will be attached to a Salesforce record, map the SharePoint metadata directly to the parent Salesforce object rather than the Quip document itself.

What Gets Lost

Be explicit with stakeholders: Quip has no equivalent for:

  • SharePoint Web Parts beyond text (Hero, Quick Links, Events, People, custom SPFx). These must be rebuilt manually or excluded.
  • Managed metadata taxonomy. Quip has no tag/category system. Metadata becomes flat text.
  • Version history. Quip tracks edits per-session, but you cannot import historical versions.
  • Permission inheritance. Quip uses document-level sharing. SharePoint's site → library → folder → item inheritance chain does not translate.
  • Content approval workflows. No Quip equivalent.

For teams that rely heavily on SharePoint's metadata architecture, read our deep dive on Mastering SharePoint Information Architecture 2026 to understand what you are giving up.

Image Migration

Images in SharePoint pages are referenced as URLs pointing to the site's asset library or CDN. You cannot embed base64 images directly into a Quip document payload. Images must be uploaded as blobs to the target thread before they can be referenced in document content.

The workflow:

  1. Extract image URLs from SharePoint canvasLayout web parts (look for imageSources in the serverProcessedContent object)
  2. Download each image via Graph API: GET /sites/{site-id}/drives/{drive-id}/items/{item-id}/content
  3. Upload to Quip via the blob endpoint: POST /threads/{thread-id}/blob with the image binary
  4. Insert the returned blob URL into the document HTML

Each blob upload counts against the 50 requests/minute rate limit. A page with 15 images consumes 15 API calls just for images — plus the document creation call, plus any edit calls. Plan your rate budget accordingly.

SharePoint internal links follow patterns like https://tenant.sharepoint.com/sites/SiteName/SitePages/PageName.aspx. After migration, these links point to content that no longer lives at that URL.

The fix requires a two-pass approach:

  1. First pass: Extract all SharePoint documents and generate a mapping table of {SharePoint URL → Placeholder ID}. Create empty Quip threads for every document to generate Quip thread_ids. Update the mapping: {SharePoint URL → Quip Thread ID}.
  2. Second pass: Parse all HTML payloads, find SharePoint URLs, and replace them with the corresponding https://quip.com/{thread-id} links. Update the Quip documents with the final HTML using the edit-document endpoint.

This is one of the highest-value steps in any migration — and the one most often skipped. Broken internal links silently degrade the usefulness of your entire knowledge base.

Attachments on List Items

SharePoint list item attachments are stored separately from the list data and are not included in CSV exports. For each item with attachments:

GET /sites/{site-id}/lists/{list-id}/items/{item-id}/attachments

Download each attachment, upload to a Quip thread as a blob, and reference it in the spreadsheet or a linked document.

Step-by-Step: API-Driven Migration Workflow

Step 1: Inventory and Scope

Before writing any code, audit your SharePoint environment:

  • Count site pages, list items, document library files
  • Identify custom Web Parts that need manual handling
  • Map managed metadata columns that will become plain text
  • Flag lists exceeding 5,000 rows (Quip's 100K cell limit will force splitting)
  • Document which internal links cross site boundaries

Step 2: Configure API Access

SharePoint side: Register an Azure AD (Entra ID) app with Sites.Read.All application permissions for Graph API access. App-based auth avoids per-user throttling limits.

Quip side: Generate an OAuth access token via the Quip Admin Console (Settings → Integrations → New API Key). Select scopes for document creation, editing, and blob upload.

Step 3: Extract SharePoint Content

Run extraction in parallel tracks:

  • Pages: Fetch each page via $expand=canvasLayout, parse innerHtml from text web parts, extract image URLs from image web parts
  • Lists: Export via Graph API with pagination ($top=100, follow @odata.nextLink), resolve lookups and managed metadata to display values
  • Document Libraries: Download files via driveItem content endpoint, extract metadata via fields expansion

Step 4: Transform Content

This is where most migrations fail or lose fidelity:

  • Strip SharePoint-specific CSS classes and data-* attributes from HTML
  • Convert multi-section canvasLayout into linear HTML (Quip has no column layout)
  • Replace SharePoint image URLs with placeholder tokens (to be swapped after blob upload)
  • Convert managed metadata term objects to plain text strings
  • Chunk lists into spreadsheet batches respecting the 100K cell / 1K row-per-call limits

Step 5: Load into Quip

  • Create folder structure in Quip first (one API call per folder)
  • Create documents via new-document with transformed HTML/Markdown
  • Upload images via blob endpoint, then edit documents to insert blob URLs
  • Create spreadsheets for list data, add rows in 1,000-row batches
  • Respect the 50 req/min per-token limit — use sleep timers or token rotation across multiple service accounts

Build and apply the SharePoint URL → Quip thread ID mapping table. Use Quip's edit-document endpoint with REPLACE_SECTION to swap URLs in-place.

Step 7: Validate

  • Spot-check 10–15% of migrated documents for formatting accuracy
  • Verify all images render (broken blob references show as empty boxes)
  • Confirm spreadsheet row counts match source list item counts
  • Test internal links navigate to the correct Quip threads
  • Validate that shared folder permissions match the intended access model

Common Failures and How to Prevent Them

Failure Mode Root Cause Prevention
Silent data truncation Quip strips unrecognized HTML tags/attributes Pre-clean HTML; test with sample pages first
Spreadsheet import rejection Exceeding 100K cell limit or 1K rows/call Pre-calculate cell counts; chunk into multiple sheets
Retry storms causing prolonged lockout Treating Quip's 503 as a server error Check X-Ratelimit-Remaining; use exponential backoff
Broken images Blob upload succeeded but URL not inserted into document Two-step: upload blob, then edit document with returned URL
Graph API throttling escalation Ignoring Retry-After headers from SharePoint Always honor Retry-After; run heavy exports during off-peak hours
Missing list attachments CSV export doesn't include attachments Use Graph API attachment endpoint per item
Lost version history Quip has no version import Archive versions as a separate CSV or document before migration
Large file conversion failures Graph API PDF conversion fails on 50MB+ files Download in native format; convert locally
Managed metadata as raw objects Graph returns taxonomy fields as objects, not strings Parse term label before transformation

Automated Migration vs. DIY Scripts: Choosing Your Approach

When DIY Scripts Work

  • Small scope: <50 pages, <5 lists, few images
  • In-house team has Graph API and Python/Node.js experience
  • You accept lower fidelity (no image migration, flat text only)
  • Timeline is flexible (at 50 Quip API calls/minute, 500 documents with 5 images each takes ~1.5 hours of API time alone — plus extraction and transformation)

When DIY Scripts Break Down

  • Scale: 500+ pages with embedded images, dozens of lists with cross-references
  • Web Part diversity: Custom SPFx web parts, embedded Power BI, Forms, or Stream content
  • Rate limit math: A workspace with 1,000 documents, averaging 8 images each, requires ~9,000 Quip API calls for content creation alone. At 50/min, that is 3+ hours of pure API time — assuming zero errors or retries.
  • Link rewriting at scale: Building and applying a URL mapping table across thousands of cross-linked documents requires deterministic ordering and idempotent retries
  • Validation: Spot-checking 10% of 1,000 documents is 100 manual reviews

When to Bring in a Migration Service

If your SharePoint environment has 200+ pages, multiple sites, or complex Web Part usage, a managed migration service handles what scripts alone cannot: intelligent rate limit management with exponential backoff for Quip's 503 responses, pre-built transformation logic for SharePoint Web Parts to Quip-compatible HTML, automatic chunking for Quip's cell and row limits, and deterministic link rewriting with full mapping tables.

At ClonePartner, we've built migration pipelines across 1,200+ projects. We handle the rate limit math, the data transformation, and the post-migration validation so your team doesn't have to.

What to Do About Quip's End-of-Life

Given Salesforce's retirement announcement, any SharePoint → Quip migration should be paired with an exit plan. Salesforce is developing in-product tools to convert Quip documents into Slack Canvases and deeper Slack–Salesforce integrations to replace Quip's core workflows (account planning, case swarming, opportunity close plans).

Practical advice:

  • If migrating for short-term Salesforce integration needs (12–18 months): Proceed, but keep your SharePoint content intact as a fallback. Don't decommission the source.
  • If migrating for long-term knowledge management: Quip is not the right target. Consider Confluence, Notion, or keeping content in SharePoint. See our SharePoint to Confluence Migration guide for a platform with a longer runway.
  • If already on Quip and planning the exit: Start evaluating Quip → Coda, Quip → Notion, or Quip → Confluence paths now. Our Quip to Coda Migration guide covers the reverse direction.

Making the Right Call

SharePoint to Quip is an engineering project, not a settings toggle. The retired import tool, the 50 req/min API ceiling, the incompatible data models, and the looming end-of-life all make this a migration where preparation and tooling determine success or failure.

If you have a small scope and experienced developers, the DIY path works — follow the step-by-step workflow above and respect both platforms' rate limits. If you are moving a full SharePoint site collection with hundreds of pages, embedded assets, and list data, the API math and transformation complexity favor a managed approach.

Either way, don't skip the inventory step, don't ignore the rate limits, and don't forget to plan your next move after Quip.

Frequently Asked Questions

Can I import SharePoint documents directly into Quip?
No. Quip retired its native Upload/Import option and the Import API endpoint on January 19, 2024. The only way to create documents in Quip programmatically is through the Automation API's new-document endpoint, which accepts HTML or Markdown content. There is no bulk import tool.
What is the Quip API rate limit for migrations?
Quip's Automation API defaults to 50 requests per minute per user and 600 requests per minute per company. When rate-limited, Quip returns HTTP 503 (not 429), which can confuse standard retry logic. Use the X-Ratelimit-Remaining header to throttle proactively.
How do I export SharePoint site pages for migration?
Use the Microsoft Graph Pages API with $expand=canvasLayout to retrieve the full page structure including web parts and their innerHtml content. The native Export to CSV only works for lists (capped at 30,000 items) and does not export page content.
What is the maximum spreadsheet size in Quip?
Quip spreadsheets have a hard limit of 100,000 cells, with a recommended maximum of 30,000 cells for performance. The API restricts row additions to 1,000 rows per call. A SharePoint list with 20 columns can hold at most 5,000 rows in a single Quip spreadsheet.
Is Quip being discontinued?
Yes. Salesforce announced that all Quip products are being retired. Subscriptions cannot be renewed after March 1, 2027. After expiration, sites enter a 90-day read-only phase, then 90 days of blocked logins, followed by data deletion. Salesforce recommends transitioning to Slack Canvases and Agentforce.

More from our Blog