Launched:self-serve migrations intoSuperhuman Docs (Coda)
Try it now
01Agent-first
Runs where you already work
Plug it into Claude, ChatGPT or Cursor. Describe the move in plain English; the agent runs it.
02Engineer-led
Our production engine, unlocked
The pipeline our engineers use on managed enterprise migrations — the same code, now something you can drive yourself.
03Pricing
Try 10 pages free, then $1 a page
Credit-based, pay-as-you-go. No scoping call, no quote — sample it on your own docs before you spend anything.
04Sources
NotionSlabConfluenceSoonGoogle DocsSoon
Skip to content

Document360 to Slack Canvas Migration: The Audience Shift Guide

Migrating Document360 to Slack Canvas is an audience change first: reader SSO, custom domains, analytics, and public URLs all disappear. Here's what breaks and how to handle it.

Nachi Raman Nachi Raman · · 16 min read
Document360 to Slack Canvas Migration: The Audience Shift Guide
TALK TO AN ENGINEER

Planning a migration?

Get a free 30-min call with our engineers. We'll review your setup and map out a custom migration plan — no obligation.

Schedule a free call
  • 1,500+ migrations completed
  • Zero downtime guaranteed
  • Transparent, fixed pricing
  • Project success responsibility
  • Post-migration support included

Document360 to Slack Canvas Migration: The Audience Shift Guide

Moving a Document360 knowledge base into Slack Canvas is an audience change first and a data migration second. Document360 is a published, often public-facing knowledge base with custom domains, reader SSO, search analytics, article ratings, and redirect rules. A Slack Canvas is internal collaboration content — gated by Slack workspace membership and channel-level permissions. Before you plan how to extract articles and push markdown, you need to decide which readers you're willing to cut off, which capabilities vanish entirely, and which content features silently break during the transition.

This guide covers the audience implications, the content hazards specific to Document360, the API mechanics on both sides, and the redirect decisions you need to make before retiring public URLs. For a broader framework on zero-downtime knowledge base moves, see The Ultimate Knowledge Base Migration Checklist.

Info

Do not confuse Document360's Slack integration with a migration path. The integration lets Slack users search and share Document360 articles from Slack, but it does not recreate your knowledge base as Slack canvases.

What stops working the moment content enters Slack

Document360 and Slack Canvas serve fundamentally different audiences through different access models. Everything listed below exists in Document360 and has no equivalent in Slack Canvas:

Document360 Capability Slack Canvas Equivalent
Custom domain (1 per project) None — canvases live at slack.com URLs
Reader SSO (SAML, OpenID, JWT) Slack workspace SSO only — no per-content reader auth
Reader groups with per-category access Channel membership or explicit canvas sharing
Article ratings and feedback None
Search analytics (queries, failed searches) None
SEO metadata (meta title, description, robots) None — canvases are not indexed by search engines
Article redirect rules (ends-with, replace-with) None
Public article URLs None — canvases require Slack authentication
Glossary auto-highlighting None
Content variables (render-time substitution) Slack canvas variables exist but serve a completely different purpose

This is not a feature-gap table you can work around. It represents a permanent change in how your content reaches its audience.

Who loses access entirely

Any reader who currently accesses your Document360 knowledge base without a Slack account in your workspace loses access completely. This typically includes:

  • External customers browsing a public or mixed-access knowledge base
  • Partners or vendors authenticated through Document360's reader SSO against your IdP
  • Anonymous visitors arriving through search engines
  • Reader groups scoped to specific categories — there is no way to replicate Document360's per-category reader group permissions in Slack

Document360's reader management controls who can access private or mixed-access knowledge bases, including SSO-based readers auto-assigned to reader groups. In Slack, canvas access defaults to invite-only and is controlled through workspace membership and explicit sharing — a completely different trust boundary.

Watch for the Slack permission trap. If you share an invite-only canvas in a public channel, it becomes visible to everyone in the workspace or Enterprise organization. That is the opposite of how many teams expect "invite only" to behave. If your Document360 project used reader groups to keep content segmented, the closest Slack equivalent is separate private channels with canvases added as tabs inside each one.

Slack plan gate: Standalone canvases — the kind you'd create programmatically and attach to channels as tabs — require a paid Slack plan (Pro, Business+, or Enterprise Grid). Teams on Slack Free can only use the single canvas per channel and cannot create standalone canvases via the API at all. Determine your Slack plan tier before designing your migration architecture, not after.

If your knowledge base has any external audience, migrating it entirely into Slack Canvas means retiring that public surface. The content becomes internal-only. Be deliberate about that decision.

How variables, snippets, and glossary terms break during export

Three content patterns create most of the cleanup work during extraction. If you miss any of them, the migration looks complete in article counts while content quality quietly degrades.

Variables and snippets must be expanded before conversion

Document360 variables are plain-text substitution tokens (product names, version numbers, support emails) limited to 300 characters each. They resolve at render time through merge code syntax like {{variable.product_name}}. Document360 snippets are reusable content blocks — paragraphs, tables, images, callouts — stored centrally and inserted into articles by reference.

Warning

Variables, snippets, and glossary terms are excluded from Document360's ZIP export. Content reuse elements — templates, variables, snippets, and glossary terms — are not exported or imported via the ZIP path. Only articles and media files are included. You must resolve all tokens before or during extraction.

When you pull article bodies through the API (GET /v2/Articles/{id}), variable merge codes appear as unresolved tokens — literal {{variable_name}} placeholders — rather than their rendered values. Your migration script must:

  1. Pre-fetch all variables via GET /v2/ProjectVersions/{versionId}/Variables and build a lookup table keyed by merge code
  2. Find-and-replace every merge code in article HTML/Markdown before converting to canvas markdown
  3. Expand all snippet references into their full content inline, since Slack Canvas has no equivalent of reusable content blocks

A snippet is a reusable block of content that you create once and insert into multiple articles. Once you flatten snippets into individual canvases, that single-source-of-truth relationship is gone. Future edits require updating every canvas that contained the snippet.

One nuance worth knowing: if authors used the snippet option to insert content as a local copy rather than a live reference, that specific article may already contain fixed text instead of a merge code. The Document360 API returns a content_type field on snippet insertions — check this field during extraction to distinguish live references from local copies, and handle each differently.

Glossary terms lose auto-highlighting

Document360's glossary feature automatically highlights terms in published articles and shows hover-over definitions with a dotted underline. When you edit an article, Document360 detects content that matches existing glossary terms and surfaces them as recommendations. Only the first occurrence of a term is highlighted per article.

Slack Canvas has no glossary feature. Terms that were auto-highlighted with tooltip definitions will render as plain text. You have three options:

  1. Drop the feature entirely — the most common choice; inline definitions clutter the reading experience
  2. Append a standalone glossary canvas to each relevant channel as a pinned tab
  3. Write a script to insert inline parenthetical definitions on first use per canvas

Most engineering teams choose option 1. If glossary terms were definitionally important to your content (legal, compliance, medical documentation), pre-export the full glossary via GET /v2/ProjectVersions/{versionId}/Glossary before decommissioning Document360.

How to flatten six category levels into three heading levels

Document360 supports up to six levels of subcategories — seven total including the root. The hierarchy is: Project → Category → Subcategory → Article, with up to six nested subcategory levels.

Slack Canvas supports headings h1 through h3 only. There is no h4, h5, or h6. A deep Document360 hierarchy cannot be represented as heading nesting inside a single canvas.

Decision criteria for the flattening choice

Use this decision framework rather than picking an approach by feel:

Condition Recommended approach
Category tree ≤ 3 levels deep in 80%+ of branches Flatten within canvases: levels 1–3 → h1–h3
Category tree > 3 levels in more than 20% of branches Split across channels: top-level categories → channels, subcategories → canvas tabs
Total article count < 50 Flatten within canvases regardless of depth
Total article count 50–300 Split by audience or product area first, then flatten within each segment
Total article count > 300 Channel-per-category with canvases-as-tabs; plan for a canvas index per channel
Multiple Document360 workspaces One channel set per workspace; never merge workspaces into a single channel

Flatten within a canvas: Collapse the category tree so that levels 1–3 map to h1–h3, and levels 4–6 become bold text or nested lists. This works for shallow knowledge bases but degrades readability for deeply nested content.

Split across channels: Map top-level Document360 categories to Slack channels, with each channel's canvas tab containing articles from that branch. Subcategories at levels 2–3 become headings; deeper levels become separate canvases added as channel tabs. This preserves navigability but multiplies the number of canvases and channels to manage.

Neither option perfectly preserves the original structure. Document the mapping before you start writing canvases, and preserve the Document360 order field from the category tree API response — Slack Canvas has no native ordering concept, so sequence must be enforced through heading order and canvas tab naming conventions.

Mapping workspaces, languages, and reader groups

Do not mirror the Document360 tree one-for-one; map audience boundaries first, then content hierarchy. Document360 workspaces act as distinct version areas with their own categories, articles, and languages, while Slack's current UX centers on canvases shared directly or added as channel tabs. Slack started converting legacy channel and DM canvases to canvases in tabs on April 9, 2025, so design for tabs and channel access, not for the older surface.

A workable mapping pattern:

  • Workspace or audience → channel set. If two Document360 workspaces represent different products or audiences, put them in different channels.
  • Language → separate channel or clearly labeled sibling canvases. Slack has no built-in language selector comparable to a multilingual knowledge base.
  • Reader group → private channel. Document360 reader groups are access rules on content; private Slack channels are the nearest operational match.
  • Deep category branches → multiple canvases. Anything beyond three levels needs flattening or splitting.

Extracting content from Document360: API limits and constraints

Document360's API (https://apihub.document360.io/v2) requires a static API key passed in the api_token header. Keys are project-scoped — a separate token is required per Document360 project; cross-project operations are not supported from a single token.

Rate limits by plan

Plan Requests per minute per token
Standard No API access
Professional / Business 60 requests/minute
Enterprise / Enterprise Plus / Trial 100 requests/minute
Bulk export API (all plans) 2 calls/day maximum

The 2-calls-per-day bulk export ceiling makes the bulk export API unsuitable as a primary extraction path for anything beyond a one-time snapshot.

Article status filtering

The Document360 article list endpoint returns articles in all statuses by default: published, draft, and new (unpublished). Most migrations should extract only published articles. Filter explicitly using the status query parameter on GET /v2/Articles — importing draft content into Slack Canvas without review creates immediate visibility problems, since Slack has no draft/review state.

Article ordering

The category tree API response (GET /v2/Categories) includes an order field for each category and article. Extract and store this value during your initial tree fetch. Slack Canvas has no native ordering mechanism — you must enforce article sequence through heading order within a canvas and through deliberate canvas naming conventions (e.g., prefixing tab names with 01_, 02_) if you're splitting across multiple canvases.

Extraction workflow

  1. Fetch the category tree via GET /v2/Categories to build your hierarchy map, preserving order fields
  2. List articles per category — the articles list endpoint returns metadata but not full content; filter by status=published
  3. Fetch each article individually via GET /v2/Articles/{articleId} — bulk content retrieval through the API is not available
  4. Resolve variables and snippets in each article body before storing
  5. Download media from Document360's Drive — these URLs are project-scoped and will stop resolving after migration
import requests
import time
 
API_BASE = "https://apihub.document360.io/v2"
HEADERS = {"api_token": "YOUR_PROJECT_TOKEN"}
RATE_LIMIT = 60  # 60 for Professional/Business; 100 for Enterprise
 
def build_variable_lookup(version_id):
    """Pre-fetch all variables and return a merge-code-to-value dict."""
    resp = requests.get(
        f"{API_BASE}/ProjectVersions/{version_id}/Variables",
        headers=HEADERS
    )
    resp.raise_for_status()
    variables = resp.json().get("data", [])
    return {v["merge_code"]: v["value"] for v in variables}
 
def resolve_variables(content, variable_lookup):
    """Replace all merge codes in article content with their values."""
    for merge_code, value in variable_lookup.items():
        content = content.replace(f"{{{{{merge_code}}}}}", value)
    return content
 
def fetch_published_articles(category_id, variable_lookup):
    articles = []
    resp = requests.get(
        f"{API_BASE}/Articles",
        headers=HEADERS,
        params={"categoryId": category_id, "status": "published"}
    )
    resp.raise_for_status()
 
    for item in resp.json().get("data", []):
        # Respect rate limit before each detail fetch
        remaining = int(resp.headers.get("X-RateLimit-Remaining", RATE_LIMIT))
        if remaining < 5:
            time.sleep(10)  # back off early before hitting 429
        else:
            time.sleep(60 / RATE_LIMIT)
 
        detail_resp = requests.get(
            f"{API_BASE}/Articles/{item['articleId']}",
            headers=HEADERS
        )
        if detail_resp.status_code == 429:
            # Exponential backoff — Document360 does not return Retry-After
            time.sleep(30)
            detail_resp = requests.get(
                f"{API_BASE}/Articles/{item['articleId']}",
                headers=HEADERS
            )
        detail_resp.raise_for_status()
 
        article = detail_resp.json()["data"]
        article["content"] = resolve_variables(
            article.get("content", ""), variable_lookup
        )
        articles.append(article)
 
    return articles

Monitor the X-RateLimit-Remaining header in every response. When the limit is hit, the API returns HTTP 429. Document360 does not return a Retry-After header, so implement exponential backoff starting at 30 seconds.

Article version history is read-only

Document360 stores article versions (draft, published, unpublished) with real revision history. The version data retrieved from the API is read-only — you can read previous versions but cannot replay a version chain into Slack Canvas. The canvases.create Slack API method creates a new standalone canvas always as a single current version. Treat old Document360 versions as archive evidence, not as objects you can faithfully import into Slack. If compliance requires audit trails, export historical versions to a separate archive store (S3, Google Drive, or a Git repository) before decommissioning Document360.

Writing content into Slack Canvas: API format and limits

The Slack Canvas API accepts markdown through the document_content object, but requires navigating strict structural limits:

{
  "title": "Getting Started Guide",
  "document_content": {
    "type": "markdown",
    "markdown": "# Overview\nYour article content here..."
  }
}

When creating or editing a canvas with the API, the document_content object contains two properties: type and markdown. Currently, the only supported type is markdown.

Slack Canvas constraints

Constraint Limit
Content per document_content object 1 MiB (1,048,576 characters)
Table cells per table 300 cells
canvases.create rate limit Tier 2: 20+ per minute
canvases.edit rate limit Tier 3: 50+ per minute
Operations per canvases.edit call One operation per API call
Heading levels h1, h2, h3 only
Standalone canvases Paid Slack plans only (Pro, Business+, Enterprise Grid)
Slack Free plan Channel canvas only; no standalone canvases via API

Calling conversations.canvases.create when a channel canvas already exists returns a channel_canvas_already_exists error. If you're creating per-channel canvases, you must use canvases.edit to append content to an existing channel canvas, or create standalone canvases and attach them as tabs.

Channel canvas vs. standalone canvas is a structural decision, not just a technical one. Channel canvases (one per channel, pinned automatically) suit single-topic channels where all content belongs to one audience. Standalone canvases (created via canvases.create, attached as tabs) suit situations where a channel covers multiple topics or where content needs to be shared across multiple channels. For most Document360 migrations, standalone canvases per article or per category section give more structural flexibility than forcing all content into a single channel canvas.

Editing existing canvases by section: If you need to update canvases after creation — for example, during iterative migration runs or resume-after-failure scenarios — use canvases.sections.lookup to retrieve section IDs within an existing canvas, then target specific sections with canvases.edit. This is the only reliable way to update canvas content programmatically without overwriting the entire document.

If your Document360 articles contain complex HTML tables, custom CSS classes, or embedded iframes (YouTube videos, interactive code environments), the Slack API will reject the payload or render it as raw text. You must pass the Document360 source through a Markdown parser, strip unsupported HTML tags, convert tables to stay within the 300-cell limit, and remove any embedded scripts or Block Kit markup (which is not supported in canvases).

Warning

Watch for payload size near the 1 MiB ceiling. If you are combining multiple Document360 articles into a single canvas to preserve hierarchy, measure your combined article sizes before sending. Documents approaching 800KB–900KB in raw markdown are candidates for splitting into multiple linked canvases. Split proactively rather than debugging API rejections reactively.

Rollback and resume strategy

Every production migration fails partway through. Without a recovery plan, a partial migration creates duplicate canvases on retry or orphaned content that must be manually cleaned up.

Before starting:

  1. Export a full content snapshot from Document360 to a local store (file system or S3) before making any API calls to Slack. This snapshot is your rollback point.
  2. Maintain a migration state file — a simple JSON or SQLite database — that records {article_id, canvas_id, status} for every article processed.

On failure:

  • On HTTP 429 from Slack: pause for 30 seconds, retry with exponential backoff, then resume from the last successfully recorded state file entry.
  • On canvas creation failure after partial content write: use canvases.sections.lookup to inspect what was written, then either delete and recreate or append missing sections using canvases.edit.
  • On network interruption mid-run: resume from the last status: "complete" entry in the state file. Articles with status: "started" should be treated as potentially partial — verify via canvases.sections.lookup before marking complete.

Avoiding duplicates on retry: Before calling canvases.create for any article, check the state file. If an entry exists with status: "complete", skip it. If an entry exists with status: "started", inspect the existing canvas before proceeding.

Media must be re-uploaded

Images and files stored in Document360's Drive are served from Document360-scoped CDN URLs (typically cdn.document360.io). Those URLs are tied to your project and will return 404 errors when your Document360 subscription ends.

Your migration script needs to:

  1. Parse article bodies for all cdn.document360.io URLs
  2. Download each binary file to a local buffer
  3. Upload the file to Slack using the files.getUploadURLExternal plus files.completeUploadExternal flow (preferred over the deprecated files.upload method)
  4. Retrieve the new Slack file URL from the completeUploadExternal response
  5. Rewrite the image references in the canvas markdown payload with the new Slack URLs

For a detailed treatment of image and attachment migration patterns, see How to Migrate Images, Attachments & Embeds Without Broken Links.

What to do with your public article URLs

Retiring Document360 means your public article URLs stop resolving. This is a separate decision from the content migration itself, and it has its own consequences:

  • SEO impact: Every indexed article URL returns a 404 unless you set up redirects. Slack canvases are not indexable by search engines, so organic traffic to those URLs is permanently lost.
  • Inbound links: Support tickets, Intercom articles, marketing pages, and partner docs that link to your knowledge base will break.
  • Document360 redirect rules die with the subscription. When you change a slug, any existing links pointing to the old URL break unless you set up a redirect rule — but those rules live inside Document360. Once you cancel the subscription, the domain and all redirect rules disappear.

Your options:

  1. Keep the custom domain and point it to a static page explaining where content has moved (requires maintaining DNS and a simple web server or CDN origin)
  2. Set up redirects at the DNS or proxy level (e.g., Cloudflare Workers, AWS CloudFront, or Nginx) to a landing page or your main site. Use HTTP 410 (Gone) rather than 404 for retired pages — 410 explicitly signals permanent removal to search engines and crawlers, whereas 404 leaves the status ambiguous.
  3. Accept the 404s if the knowledge base was low-traffic or genuinely internal-only

If you used Document360's default subdomain (yourproject.document360.io), you have no control over that URL after cancellation. There is no way to set redirects on a subdomain you don't own.

Danger

Retiring public article URLs is its own cutover. A technically clean canvas migration can still be a bad customer experience if your old knowledge-base links now point to content that only Slack members can open. Do not bulk-redirect public help URLs into Slack-only destinations unless every intended reader already has Slack access.

Migration methods compared

Method Content Fidelity Variable/Snippet Resolution Hierarchy Handling Media Re-upload Suitable Article Volume
Manual copy-paste Low Manual Manual Manual < 20 articles
ZIP export → manual conversion Low–Medium ❌ Not included in ZIP Manual Partial 20–50 articles, text-heavy
DIY API script Medium–High ✅ Custom script required ✅ Custom mapping ✅ Custom 50–500 articles
Managed migration Highest ✅ Full resolution ✅ Structured mapping ✅ Automated 500+ articles or multi-project
Info

Multi-project moves multiply the work. Because Document360 API tokens are project-scoped, a migration spanning multiple projects requires separate tokens, separate rate-limit budgets, and separate variable/snippet lookups for each project. A 3-project migration is not 3× a single-project migration in complexity — cross-project deduplication, unified state tracking, and merged channel architecture add additional coordination overhead.

When Slack Canvas is the wrong destination

Be honest about the trade-offs. Moving Document360 to Slack Canvas is the wrong call if:

  • Your knowledge base serves external customers or partners who don't have Slack accounts
  • You rely on search analytics (top queries, failed searches) to drive content strategy
  • You need SEO-indexed documentation that drives organic traffic
  • Your content uses deep category hierarchies (4+ levels in more than 20% of branches) that would become unnavigable in canvas format
  • You need article versioning workflows (draft → review → publish) with audit trails
  • Your team is on Slack Free — standalone canvases are unavailable entirely

Slack Canvas is a good destination when the docs are truly internal, channel-centric, and meant to live beside the conversations and workflows that use them. The clearest signal that Canvas is right: your readers are already in Slack all day and currently navigate to an external URL to find content that answers questions about their Slack-based work.

If any external readership exists, consider keeping Document360 for public content and using Slack Canvas only for internal operational docs — or evaluate a different target like Notion or Confluence.

Making the move without losing content or access

This migration is tractable for small, internal-only knowledge bases. For anything larger — multiple projects, hundreds of articles, deep hierarchies, unresolved variables and snippets — the edge cases compound fast. The audience change is permanent and the content hazards are specific enough that a test run on a subset of 10–20 articles across at least two category depths is non-negotiable before committing to a full migration. Validate the test run by checking access as three different user types: an internal Slack member, a Slack guest, and a user with no Slack account.

Plan the work in seven passes:

  1. Audience classification — determine who loses access and whether that's acceptable
  2. Slack plan verification — confirm your plan supports standalone canvases before designing the architecture
  3. API extraction — fetch category tree (with order fields), filter to published articles, store raw content
  4. Variable and snippet expansion — pre-fetch lookup tables, resolve all merge codes
  5. Markdown conversion — strip unsupported HTML, enforce heading depth, respect table cell limits
  6. Media re-upload and link rewriting — download from Document360 CDN, re-upload to Slack, rewrite URLs
  7. Access validation and URL cutover — test permissions, decide on redirect or 410 strategy for public URLs

At ClonePartner, we handle complex Document360 extractions including multi-project token coordination, variable resolution, and hierarchy flattening. If you'd rather scope this with someone who has done it before, book a 30-minute call below.

Frequently Asked Questions

Can I migrate a public Document360 knowledge base to Slack Canvas without losing external access?
No. Slack Canvas is gated by workspace membership. Any reader without a Slack account in your workspace — external customers, partners, anonymous visitors — loses access entirely. There is no public URL or reader SSO equivalent in Slack Canvas.
What happens to Document360 variables and snippets during migration?
Variables and snippets are excluded from Document360's ZIP export and may appear as unresolved tokens in API-fetched article bodies. You must pre-fetch all variables and snippets via the API, then find-and-replace every merge code and expand snippet references inline before converting content to canvas markdown.
Does Slack Canvas support the same heading levels as Document360?
No. Slack Canvas supports h1 through h3 only. Document360 categories can nest up to six levels deep. You need to flatten the hierarchy — either collapsing levels 4–6 into bold text or lists, or splitting content across multiple channels and canvas tabs.
What is the Document360 API rate limit for migration?
Professional and Business plans allow 60 requests per minute per API token. Enterprise plans allow 100 requests per minute. Tokens are project-scoped, so multi-project migrations require separate tokens with independent rate-limit budgets. The bulk export API is capped at 2 calls per day.
What happens to Document360 redirect rules after cancellation?
Document360 redirect rules live inside the platform. Once you cancel your subscription, the custom domain and all redirect rules stop working. You need to set up redirects at the DNS or proxy level before decommissioning Document360 if you want to avoid 404s on previously indexed URLs.

More from our Blog