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

Salesforce Knowledge to Slack Canvas: API Limits & Data Mapping

Salesforce Knowledge to Slack Canvas has no native path despite shared ownership. Data category visibility, versioning, merge fields, and API rate limits make this a complex migration.

Raajshekhar Rajan Raajshekhar Rajan · · 17 min read
Salesforce Knowledge to Slack Canvas: API Limits & Data Mapping
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

Salesforce Knowledge to Slack Canvas: API Limits & Data Mapping

There is no native migration path from Salesforce Knowledge to Slack Canvas. Salesforce acquired Slack in 2021 for $27.7 billion, and as of late 2026, ships an official Quip → Slack Canvas conversion path — but no built-in connector bridges Knowledge articles to canvases. (help.salesforce.com) Every article must be extracted via the Salesforce API, transformed to markdown, and loaded through the Slack Canvas API, with a manual redesign of your entire visibility model in between.

The hard part is not the content. It is mapping data category visibility to Slack channel membership, because the two access models have nothing in common.

If you are exploring Slack canvases as a destination for other document types, our Quip to Slack Canvases migration guide covers Salesforce's official in-product conversion flow. For broader knowledge base migration planning, start with our migration checklist.

Required OAuth scopes and API credentials

Before writing a single line of migration code, you need credentials on both sides. This is the most common first blocker.

Salesforce side — Connected App setup:

Your Salesforce Connected App requires the following OAuth scopes:

Scope Purpose
api General REST API and SOQL access
bulk_api Bulk API 2.0 query jobs
content ContentVersion binary download via the Files REST endpoint
full Required if extracting via Tooling or Metadata API for field schema

The integration user running extraction queries must have a profile or permission set that grants:

  • View All Data (or equivalent field-level read access on Knowledge__kav)
  • Manage Categories (to read the full DataCategoryGroup taxonomy, not just categories visible to their role)
  • Download Attachments on the content objects

If the extraction user cannot see all categories, the DataCategorySelection query returns only the categories accessible to that user's role — and your mapping file is silently incomplete from the start.

Slack side — required OAuth scopes:

Scope API method(s) covered
canvases:write canvases.create, canvases.edit, canvases.access.set
canvases:read canvases.sections.lookup
files:write files.getUploadURLExternal, files.completeUploadExternal
channels:manage Creating and configuring private channels for access mapping
groups:write Managing private channel membership
users:read Resolving user IDs for canvases.access.set by-user sharing

Install your Slack app at the workspace level (not user token). User tokens expire and are not appropriate for batch migration jobs running over hours.

Why data category visibility is the hardest part

Data categories in Salesforce Knowledge are hierarchical labels organized into DataCategoryGroups that control both article classification and article visibility. An article tagged with categories from multiple groups is visible to a user only if that user has access to at least one category in every group applied to the article. Visibility is configured through three mechanisms — roles, permission sets, and profiles — and Salesforce evaluates them with a logical OR within each group. (help.salesforce.com)

Salesforce enforces specific structural limits on categories: up to 5 category groups with 3 active at a time by default, 5 hierarchy levels per group, 100 categories per group, and up to 8 categories from one group on an article. The API surface reflects this model: Knowledge__DataCategorySelection exposes article categorization, and the REST data-category resources return only the categories visible to the current user. (help.salesforce.com)

Slack Canvas has no equivalent concept. Canvas access is controlled by channel membership and explicit sharing. The canvases.access.set API method accepts either channel_ids or user_ids — never both in the same call — with a maximum of 20 IDs per call. It rejects DM and MPDM channel IDs entirely. If you share a canvas in a public channel, Slack warns that the canvas can become visible across the workspace or Enterprise org even when general access is otherwise limited. (api.slack.com)

This means a category visibility rule like "agents with the EMEA role can see articles tagged Geography > Europe AND Product > Enterprise" has no direct expression in Slack. You must redesign that rule as a channel: create a #kb-emea-enterprise channel, populate it with the right members, and share the canvas there. If a category combination maps to more than 20 channels, your script must paginate the canvases.access.set requests to avoid HTTP 400 errors.

One naming trap worth flagging: Salesforce audience channels (Internal App, Customer, Partner, Public Knowledge Base) are publication targets. Slack channels are access containers. Same word, different model. (developer.salesforce.com)

Effective audience — a derived concept used throughout this guide — means the set of users who can access a specific article given its category tags and the org's role/profile/permission-set visibility configuration. You must compute this explicitly; Salesforce does not expose it as a single query result.

To extract an article's categories, your SOQL query must traverse the DataCategorySelection relationship:

SELECT Id, Title,
       (SELECT DataCategoryName, DataCategoryGroupName FROM DataCategorySelections)
FROM Knowledge__kav
WHERE PublishStatus = 'Online'
Salesforce Knowledge concept Slack Canvas reality Migration action
Data category tree No equivalent ACL tree Build an explicit channel map
Role/profile/permission-set visibility Channel membership or invited users Maintain entitlements outside Slack, then apply sharing
Internal/Customer/Partner/Public audience channels Public/private channels plus invited users Reduce scope to internal Slack use cases first
Category-group intersection (AND logic) No intersection logic Collapse intersection to a single purpose-built channel

How to build the category-to-channel map

  1. Export your DataCategoryGroup hierarchy via the Metadata API or Setup UI. List every category group and its child categories.
  2. Export role/profile/permission-set visibility assignments for each category group. This tells you which users can see which category combinations.
  3. Identify the effective audience for each article by cross-referencing its category tags against the visibility rules. Articles tagged across multiple groups will have audiences defined by the intersection of group-level visibility rules.
  4. Design Slack channels that mirror those audiences. In practice, most orgs can collapse hundreds of category combinations into 10–30 channels — but this is a human judgment call, not an automated mapping.
  5. Batch the canvases.access.set calls. With a 20-channel-ID limit per call, sharing a canvas to 50 channels requires three API calls per canvas. Budget accordingly.
Tip

Treat the category redesign as a separate deliverable. Build a matrix with columns for record type, data category path, old audience channel, new Slack channel(s), exception users, and owner. If that sheet is wrong, the migration is wrong.

Standalone canvases vs. channel canvases

Slack allows only one channel canvas per channel, and access to that canvas is tied to channel membership. For article libraries, the more workable pattern is standalone canvases with default access set to Invite only, then shared into the specific private channels that replace each category slice. Standalone canvases require a paid Slack plan. (api.slack.com)

What happens to article versioning?

Salesforce Knowledge maintains a full publishing lifecycle per article. Each Knowledge__kav record (the article version object) carries one of three statuses: Draft, Online (published), or Archived. Every time a published article is edited, a new draft version is created with a distinct version number and its own record ID. The draft does not replace the published version until it goes through an approval workflow. The system stores up to ten versions by default, plus any versions attached to cases.

A Slack canvas has one current body and no version model accessible via the API. There is no draft state, no archive state, and no programmatic version history. The canvases.edit method overwrites content in place. Slack does expose revision history in the product UI, and admins can allow restoration of prior revisions — but the API model is centered on a single current body. (slack.com)

Only the published (Online) version of each article should be migrated. Draft articles are incomplete by definition. Articles pending approval — those that have been submitted to a workflow but not yet approved — are also not Online and should be treated as drafts. If you have a regulatory or audit requirement to preserve version history, export it to a separate archive (a database, S3 bucket, or CSV export from the Knowledge Audit Trail) before migrating the published content to Canvas. Canvases cannot satisfy a version-history compliance requirement.

SELECT Id, KnowledgeArticleId, Title, UrlName, ArticleNumber,
       PublishStatus, VersionNumber, Language
FROM Knowledge__kav
WHERE PublishStatus = 'Online'
  AND Language = 'en_US'

Keep the original KnowledgeArticleId, article number, and old URL in your migration ledger so you can trace every canvas back to its source record.

Multilingual Knowledge articles

The Language = 'en_US' filter above is illustrative. Most enterprise Knowledge instances contain articles in multiple locales — Salesforce supports translations stored as separate Knowledge__kav records with the same KnowledgeArticleId but different Language values.

Your migration must decide: migrate one locale per canvas, or consolidate translations into a single canvas with language sections. The API supports either, but the access model implications differ:

  • One canvas per locale: Simpler content structure, but doubles or triples canvas count and canvases.access.set calls. Channel membership must be replicated per locale.
  • Consolidated canvas: Reduces canvas sprawl, but requires section-level language labeling and makes content harder to maintain post-migration.

To enumerate all language variants for your Knowledge instance:

SELECT Language, COUNT(Id) articleCount
FROM Knowledge__kav
WHERE PublishStatus = 'Online'
GROUP BY Language
ORDER BY COUNT(Id) DESC

Run this before designing your channel map. If you have 12 locales and 800 articles, you potentially face 9,600 canvases under a one-per-locale model — which changes your throughput math significantly.

Rich text fields, merge fields, and markdown conversion

Knowledge article bodies are stored in rich text fields on the Knowledge__kav object. These fields contain HTML — but not clean, portable HTML. Two problems arise during migration.

Salesforce merge fields. Rich text fields can contain merge field syntax like {!Account.Name} or {!Case.CaseNumber} that resolve dynamically inside the Salesforce org. Outside the org, they resolve to nothing. If you migrate them as-is, they appear as broken bracketed text inside your canvases. Your migration script must detect these patterns (regex for \{!.*?\} works as a starting point) and either:

  • Replace them with static placeholder text (e.g., [Account Name])
  • Strip them entirely
  • Flag the article for manual review

Slack Canvas markdown limitations. The Canvas API accepts content as a document_content object with type: "markdown". Supported formatting includes headings, bold, italic, links, code blocks, blockquotes, and lists — but not arbitrary HTML. Tables, colored text, custom CSS, embedded Visualforce components, and Block Kit elements will not survive. You need an HTML-to-markdown conversion step, and you should expect lossy output for any article that uses advanced formatting. (help.salesforce.com)

Canvas content size limit. The document_content object in a canvases.create or canvases.edit call is subject to a maximum payload size of approximately 1 MiB per request, based on observed API behavior (Slack does not publish this limit prominently in their public documentation). Most Knowledge articles fall well under this limit, but long-form troubleshooting guides with embedded images can approach it. Monitor response sizes during development and implement a split-or-truncate step for any article body that exceeds 900 KB after conversion.

Knowledge search synonym groups and promoted search terms defined in your Salesforce org are lost in this migration. There is no Slack Canvas equivalent. If findability within Slack is a post-migration concern, document your synonym groups before migrating and plan to configure equivalent terms in whatever enterprise search layer indexes your workspace.

The overall conversion pipeline:

extract HTML
→ sanitize unsupported markup
→ resolve or remove Salesforce-specific tokens
→ download media and files
→ upload media to Slack
→ rewrite internal article links
→ convert to Slack markdown
→ split or truncate if body approaches 1 MiB
→ create canvas with the final body

Section-level structure. The canvases.sections.lookup API method allows you to retrieve section IDs within an existing canvas, which is required if you later need to update individual sections via canvases.edit rather than replacing the entire body. For initial load, create canvases with the full content in the canvases.create call. For large articles that require post-migration updates, store section IDs from canvases.sections.lookup responses in your migration ledger alongside the canvas ID.

Create canvases with the bulk of the content in the initial canvases.create call when possible. Because canvases.edit supports only one operation per call, section-by-section patching is slower and harder to retry cleanly.

Custom article types mean per-tenant field mapping

Field mapping is per-tenant because Salesforce Knowledge does not have a universal article schema across orgs. In Lightning Knowledge, article structure lives on Knowledge__kav and is differentiated with record types. In Salesforce Classic, custom article types created separate objects like FAQ__kav or Procedure__kav. Lightning record types replaced these custom article types, so modern orgs converge on one object but still keep locally defined record types, layouts, and custom fields. (developer.salesforce.com)

One org might store article bodies in a field called Article_Body__c. Another uses Resolution__c and Symptom__c as separate rich text fields. A third has Steps_to_Reproduce__c, Root_Cause__c, and Workaround__c — each needing to be concatenated into a single canvas body.

Before writing migration code, you must:

  1. Run a DESCRIBE call on Knowledge__kav to enumerate all custom fields
  2. Identify which fields contain article content vs. metadata
  3. Decide how to flatten multiple rich text fields into a single markdown document
  4. Handle org-specific custom fields that carry structured data (picklists, lookups, formulas)

A workable canvas template:

  • Canvas title: article title
  • Header metadata: record type, owner, last review date, legacy article number
  • Body sections: summary, steps, details, resolution, notes
  • Footer: source article ID, old URL, redirect target, migration timestamp

How to migrate Knowledge article attachments

Salesforce Knowledge articles store attachments as ContentVersion records linked through the ContentDocumentLink junction object. To extract them, query ContentDocumentLink where LinkedEntityId matches the article's KnowledgeArticleId, then fetch the VersionData blob from the corresponding ContentVersion record. Note that SOQL on ContentDocumentLink requires filtering on Id, ContentDocumentId, or LinkedEntityId. (developer.salesforce.com)

You cannot copy image URLs from the Salesforce HTML body and paste them into Slack. Those URLs are authenticated endpoints tied to active Salesforce sessions. Anyone not logged into Salesforce will see broken images.

Uploading to Slack requires the newer external upload sequence. Slack deprecated files.upload and sunset it on November 12, 2025. The current flow: (docs.slack.dev)

  1. Query relationships: Query ContentDocumentLink for each article to retrieve associated ContentVersion IDs.
  2. Download binary data: Download the file payload via the Salesforce REST API (/sfc/servlet.shepherd/version/download/<ContentVersionId>).
  3. Request Slack upload URL: Call files.getUploadURLExternal with the filename and byte length.
  4. POST the binary to the returned upload URL.
  5. Complete upload: Call files.completeUploadExternal to finalize the file in Slack.
  6. Rewrite HTML tags: Parse the Salesforce article body, locate the original <img> tags, and replace src attributes with the new Slack file URLs.

One important caveat: you cannot reliably embed a Slack-hosted file directly into a canvas body via the API. Canvas markdown supports images via URL, but Slack's internal file URLs are not stable external links. The realistic approach is to attach files to the same channel where the canvas lives and reference them with a link in the canvas content.

For a deeper dive on attachment migration patterns, see our guide on migrating images, attachments, and embeds without broken links.

Article URLs change — plan for redirects

Salesforce Knowledge article URLs differ between Classic and Lightning. In Lightning, the URL contains the Knowledge Article Version ID. In Classic, it uses the Knowledge Article ID. Public-facing articles served through Experience Cloud or Salesforce Sites use yet another URL pattern based on UrlName.

Slack canvases have no public URL. They are accessible only within the Slack workspace to users who have been granted access. This creates three problems:

  • External links break. Any URLs indexed by search engines, bookmarked by customers, or embedded in case records will return 404s once you deprecate Knowledge.
  • You need 301 redirects if the Knowledge articles were publicly accessible. Because Slack Canvas cannot host redirects, you must stand up an external redirect gateway — a Cloudflare Worker, Nginx reverse proxy, or similar — to intercept requests to legacy Salesforce URLs and forward them to wherever the canonical content now lives.
  • Internal Salesforce links (between articles, or from Cases to attached articles) will not resolve in Slack. You need a lookup table so macros, bookmarks, chatbot answers, and case templates can find the new canvas.

If your Knowledge base serves both internal agents and external customers, Canvas only covers the internal use case. The external-facing content needs a different destination entirely.

API throughput: Bulk API and Slack rate limits

The real throughput constraint is the combination of Salesforce query limits and Slack's per-method rate tiers.

Salesforce side:

  • Bulk API 2.0 is recommended for operations over 2,000 records. Bulk API 2.0 query jobs do not consume batches from the rolling 15,000-batch daily allocation — they have their own daily ceilings, including 10,000 query jobs and 1 TB of query result storage per 24-hour window. Classic Bulk API PK chunking does count toward the batch limit. (developer.salesforce.com)
  • The typical bottleneck is attachment downloads, which are individual REST API calls per ContentVersion record and count against your org's daily API call allocation.

Slack side:

Operation API method Rate tier Effective throughput
Create canvas canvases.create Tier 2 ~20/min
Set access canvases.access.set Tier 3 ~50/min
Edit content canvases.edit Tier 3 ~50/min
Lookup sections canvases.sections.lookup Tier 3 ~50/min
Upload file (step 1) files.getUploadURLExternal Tier 4 ~100/min
Upload file (step 2) files.completeUploadExternal Tier 4 ~100/min

Runtime estimate — explicit assumptions:

For a Knowledge base with 500 articles, average body size 15 KB, 0.4 attachments per article (200 total files), 5% retry rate, running sequentially with exponential backoff:

  • Canvas creation: 500 articles ÷ 20/min = 25 minutes minimum
  • Access setting (assume avg 3 channels per article, 1 call each): 500 calls ÷ 50/min = 10 minutes
  • Attachment upload (200 files × 2 calls each): 400 calls ÷ 100/min = 4 minutes
  • Retries at 5% add ~10% to total runtime
  • Total API runtime: approximately 45–60 minutes for 500 articles at these parameters

Scale linearly: 5,000 articles with the same profile = 7–10 hours of API runtime, not counting development, testing, the category-to-channel mapping work, or content transformation time. If your article count is in the thousands and includes multilingual variants, plan for a multi-day migration window.

Your migration script must implement exponential backoff and retry logic to handle HTTP 429 Too Many Requests responses.

Idempotency and restart safety

Migration scripts fail. A run that processes 300 of 500 articles before hitting an unhandled error must be resumable without duplicating canvases or corrupting access grants.

Minimum viable migration ledger — write to a database or CSV after each successful API call:

Column Value Purpose
knowledge_article_id Salesforce KnowledgeArticleId Source record identifier
knowledge_version_id Knowledge__kav Id Specific version extracted
canvas_id Slack canvas ID from canvases.create response Resume target
access_set Boolean Skip canvases.access.set if already completed
attachments_uploaded JSON array of ContentVersion IDs Skip re-upload
status pending / complete / failed Filter on restart

On restart, filter WHERE status != 'complete' and skip any article where canvas_id is already populated — use canvases.edit to update content rather than creating a duplicate. Check access_set before re-issuing canvases.access.set calls, since Slack does not deduplicate access grants idempotently across repeated calls.

Do not call canvases.create twice for the same article. There is no unique-constraint enforcement on canvas creation. Two calls produce two canvases with no linkage between them.

Step-by-step migration approach

1. Audit and export

  • Query all Knowledge__kav records where PublishStatus = 'Online'
  • Run the locale distribution query to enumerate all language variants requiring migration decisions
  • Export DataCategorySelection records to capture category tags per article
  • Export ContentDocumentLink and ContentVersion records for attachments
  • Run DESCRIBE on Knowledge__kav to enumerate custom fields
  • Inventory record types, languages, audience channels, and article counts
  • Export Knowledge search synonym groups and promoted search terms for reference

2. Design the channel map

  • Analyze category-group combinations and current visibility rules
  • Map each effective audience to a Slack channel (create channels as needed)
  • Validate that channel membership matches the intended audience
  • Document exception users and ownership in the mapping matrix
  • Confirm Slack app has channels:manage and groups:write scopes needed to create and populate channels programmatically

3. Transform content

  • Convert rich text HTML to Slack-compatible markdown
  • Strip or replace Salesforce merge fields
  • Concatenate multi-field article bodies into a single markdown document
  • Rewrite internal article links using the migration ledger lookup table
  • Validate output is under the ~1 MiB canvas content threshold

4. Load into Slack

  • Initialize migration ledger before first API call
  • Create canvases via canvases.create with title and initial content; write canvas_id to ledger immediately
  • Upload attachments via files.getUploadURLExternal + files.completeUploadExternal; record each uploaded file ID
  • Set access via canvases.access.set, batching channel_ids in groups of 20
  • Implement exponential backoff for 429 responses
  • Mark each row complete in the ledger only after all steps succeed

5. Validate and redirect

  • Spot-check content fidelity across article types and record types
  • Verify access controls by testing with users from different audience segments
  • Set up 301 redirects for any publicly-accessible article URLs
  • Archive or tombstone the original Knowledge articles

When Slack Canvas is the wrong destination

Warning

If your Salesforce Knowledge instance uses data categories primarily for agent-facing article visibility — where different support tiers see different articles based on role hierarchy — Slack Canvas is a poor target. Canvas was designed for collaborative documents, not gated knowledge delivery.

Slack Canvas lacks:

  • Cross-canvas search — no unified search API that queries canvas content the way Salesforce Knowledge search works
  • Analytics — no view counts, article ratings, or deflection metrics
  • Approval workflows — no draft/review/publish cycle
  • Public access — canvases are workspace-internal only
  • Version history via API — no rollback, no audit trail
  • Search synonym management — no equivalent to Salesforce Knowledge promoted search terms

Feature comparison against alternative destinations:

Capability Slack Canvas Notion Confluence Guru
Role-based access control Channel membership only Workspace permissions + page-level Space/page permissions Card groups + permissions
Draft/review/publish workflow None Manual Native Native (verification workflow)
Public-facing content No Yes (public pages) Yes (public spaces) No
API version history No No (page history in UI only) Yes Yes
Full-text search across all content Workspace search only Yes Yes Yes
Analytics / view counts No No Yes (premium) Yes

Migration makes sense when:

  • You are moving lightweight internal reference docs (onboarding guides, process docs, runbooks) that do not need gated visibility
  • Your team already lives in Slack and needs content where they work
  • The Knowledge articles are a subset, not the entire knowledge base

Migration is a poor fit for:

  • Agent KBs with category-based entitlements
  • Customer-facing or SEO-sensitive help content
  • Partner/community knowledge with external audience rules
  • Content that depends on draft/review/archive workflows
  • Large attachment-heavy libraries with stable public URLs
  • Multilingual knowledge bases where locale management is operationally significant

Decision rule: If the primary consumer of your Knowledge articles is external (customers, partners, public web) or if the visibility model requires more than 30 distinct access groups, route the content to Confluence, Notion, or a dedicated knowledge base platform instead of Canvas. Reserve Canvas for the internal, collaborative, low-access-complexity subset.

Frequently Asked Questions

Is there a native Salesforce Knowledge to Slack Canvas migration tool?
No. Despite both products being owned by Salesforce, there is no built-in connector, export tool, or admin feature to move Knowledge articles into Slack Canvas. Salesforce ships an official Quip → Canvas conversion path, but nothing for Knowledge. You must extract articles via the Salesforce API, transform the content to markdown, and create canvases through the Slack Canvas API.
How do Salesforce Knowledge data categories map to Slack Canvas permissions?
They do not map directly. Knowledge uses DataCategoryGroups with role/profile/permission-set visibility evaluated with a logical OR. Canvas access is controlled by channel membership or explicit user sharing via canvases.access.set, which accepts a maximum of 20 channel IDs or 20 user IDs per call. You must redesign category visibility rules as Slack channels.
Does Slack Canvas support article versioning like Salesforce Knowledge?
No. Salesforce Knowledge maintains draft, published, and archived versions per article, each with its own record ID. A Slack canvas has one current body with no version model accessible via the API. Only the published (Online) version of each article should be migrated.
What happens to Salesforce merge fields when moved to Slack?
Merge fields like {!Account.Name} resolve to nothing outside the Salesforce org. They appear as broken bracketed text in canvases. Your migration script must detect these patterns and either replace them with static placeholder text, strip them, or flag the article for manual review.
How long does a Salesforce Knowledge to Slack Canvas migration take?
For 500 articles and 200 attachments, the API runtime alone takes 2–4 hours due to Slack's Tier 2 rate limit on canvases.create (~20 per minute). The category-to-channel mapping and per-tenant field mapping work can add days or weeks of planning before any code runs.

More from our Blog