Zentoko

Migration guides.

Field-mapping guides for moving Zentoko data into the most common destinations. The export ZIP is structured JSON. These are recipes for translating that JSON into the import format each tool expects.

Don't see your destination tool? Email info@zentoko.com and we'll add a guide within 48 hours.

Newsletter subscribers

records.newsletterSubscribers[]

Each subscriber row carries email, optional firstName, status, source channel, UTM attribution, and subscribedAt. Most destinations import a CSV with email + name; Zentoko's structured JSON is a superset.

Mailchimp
  1. Audience → Add contacts → Import contacts → Upload a file.
  2. Map: email → Email Address, firstName → First Name, status → mark UNSUBSCRIBED rows as Unsubscribed.
  3. Optional: utmSource → 'source' tag, utmCampaign → 'campaign' tag.
Beehiiv
  1. Audience → Subscribers → Imports → Import CSV.
  2. Map: email → email, firstName → first_name.
  3. Beehiiv doesn't support arbitrary tags on import. UTMs become custom fields once imported.
ConvertKit
  1. Grow → Subscribers → + Add subscribers → Bulk import.
  2. Map: email → Email Address, firstName → First Name.
  3. Use a single tag like "zentoko-import-2026-05" so you can identify the migrated cohort later.
Substack
  1. Settings → Imports → Import subscribers from a CSV.
  2. Substack only consumes email addresses; firstName/UTM data is dropped on import.
  3. Take a screenshot of the JSON before import in case you want to reconstruct first names later.

Blog posts

records.blogPosts[]

Each post has title, slug, content (markdown), contentHtml, featuredImage URL, tags, publishedAt, status, and SEO metadata. The content field is canonical markdown, which most destinations accept that directly.

Ghost
  1. Settings → Labs → Import content (Ghost JSON format).
  2. Run the conversion script in our reference repo (or write a 30-line Node script): map title → title, slug → slug, content → mobiledoc, featuredImage → feature_image, tags → tags[].
  3. Status: Zentoko's PUBLISHED maps to Ghost's published, DRAFT to draft.
WordPress
  1. Tools → Import → install "WP All Import" plugin.
  2. Map content → post_content (use the markdown plugin, or convert to HTML using contentHtml field instead).
  3. Map featuredImage → _thumbnail_id (WP All Import handles URL-to-attachment conversion).
Substack
  1. No bulk import. Use the API (substack.com/api/v1/posts) or paste each post manually.
  2. For each post: copy contentHtml into the Substack rich-text editor (it preserves formatting).
Webflow
  1. Project → CMS → Import items via CSV.
  2. Flatten the JSON: one row per blog post, columns title / slug / content / featuredImage / publishedAt.

Contact form submissions

records.contactSubmissions[]

Threaded inbox of every contact-form submission. Each row has name, email, organization, message, status (NEW/READ/RESPONDED/SPAM/ARCHIVED), sourceUrl, createdAt.

HubSpot
  1. Contacts → Import → File from computer.
  2. Map email → Email, name → First name + Last name (split on space), organization → Company.
  3. Custom property: import status as a HubSpot enumeration field for follow-up filtering.
Pipedrive
  1. Tools → Import data → Person + organization.
  2. Map email → Email, name → Name, organization → Org name.
  3. Each submission can become a Person + linked Activity (the message body). Use Pipedrive's Activity import in the same flow.
Plain Email Inbox
  1. Filter records.contactSubmissions to status='NEW' or 'READ' (the not-yet-responded ones).
  2. For each, send yourself an email with the body inline. The Reply-To is already correct in the JSON.

Social posts (queued + published)

records.posts[]

Every Post row Zentoko ever generated for the brand: caption, mediaUrls, scheduledAt, publishedAt, platform (via PostPlatform child rows). Useful for archive, less useful for re-import (each platform's API differs).

Buffer
  1. No bulk import via UI; use Buffer's API (publish.buffer.com/api/v2/queue/create).
  2. For each post: POST { text: caption, media: { picture: mediaUrls[0] }, scheduled_at: scheduledAt }.
  3. Free-tier limit is 10 queued posts per profile, so plan staggered import.
Hootsuite
  1. Hootsuite has Bulk Composer (CSV import for scheduled posts).
  2. Convert: text → caption, scheduledAt → scheduled time (ISO 8601), media URL → media URL.
  3. Hootsuite enforces 30-minute spacing, so adjust scheduledAt accordingly.
Sprout Social
  1. Compose → Bulk Schedule → upload CSV.
  2. Map: caption → Message, scheduledAt → Scheduled For (YYYY-MM-DD HH:MM), platform → Network.
Just archive (no re-import)
  1. Most users don't re-import past social posts. They're ephemeral.
  2. The export is enough for record-keeping. Save the JSON, walk away.

Generated images, videos, music beds

assetManifest[]

Every S3-hosted asset the brand owns, with a 7-day signed URL pointing directly at the file. After 7 days, request a fresh export to re-sign.

Local backup
  1. Bash: jq -r '.assetManifest[] | .url' brand-export.json | xargs -n 1 -P 4 wget -q
  2. PowerShell: Get-Content brand-export.json | ConvertFrom-Json | Select -Expand assetManifest | ForEach-Object { Invoke-WebRequest $_.url -OutFile (Split-Path $_.s3Key -Leaf) }
  3. Both download in parallel. Plan for the total size first. Character-pose poses + music beds + media assets can total 1-10 GB for an active brand.
Cloudflare R2 / S3 / DigitalOcean Spaces
  1. Treat the manifest as an aws-cli sync source: download to local, then re-upload with `aws s3 cp --recursive` to your destination bucket.
  2. Preserve the relative path structure for clean URLs in your new tool.
Just keep the URLs
  1. If your destination tool can ingest URLs directly, paste them in. The 7-day window is enough for a one-shot import.

Brand DNA (voice, pillars, audience)

brand.dna + brand.voiceStyle + brand.visualStyle

The strategic foundation Zentoko built for you. JSON shape is documented in the export's README.md.

Notion / Confluence
  1. Paste the markdown rendering of brand.dna (use the README.md generated as part of the export).
  2. Most teams turn this into a shared Brand Bible page after migration.
Any AI tool's system prompt
  1. JSON.stringify(brand.dna) makes a solid system-prompt prefix for ChatGPT / Claude / Gemini.
  2. Paste at the top of every conversation about the brand to maintain voice consistency.

Stuck?

Email info@zentoko.com with a screenshot of your destination tool's import dialog and a paste of the JSON section you're trying to map. We'll respond with a working translation script within 24 hours, and we'll add it to this page so the next person doesn't have to ask.

← Back to offboarding policy