How to Export Data from Groove: Methods, API Limits & Portability
Complete guide to exporting data from GrooveHQ. Covers the built-in JSON export, REST API v1, GraphQL v2, KB extraction, rate limits, and portability gaps.
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
How to Export Data from Groove: Methods, API Limits & Portability
Groove gives you three paths to get data out: a built-in JSON export for conversations, the REST API v1 (deprecated but functional), and the GraphQL API v2 (actively developed). There is no native CSV export, no "download everything" button that covers all object types, and no bulk knowledge base export from the admin UI. If you need tickets plus KB articles plus customer records plus attachments, you are combining at least two of these methods — and working around rate limits on both.
This guide covers every extraction method with real technical constraints, walks through what data you can and cannot get out, and flags the gaps that silently break migrations.
Verified against: Groove REST API v1 docs (doc.groovehq.com), Groove GraphQL API v2 docs (developer.groovehq.com), and Groove help center documentation as of mid-2026.
Branding note: On June 2, 2026, Groove moved under the Groove Classic name inside the Helply master brand. Existing accounts, data, and yourcompany.groovehq.com logins remain in place, so the export methods in this guide still apply. (helply.com)
If you are planning to move this data into another helpdesk, see our migration-specific guides: Groove to Zendesk or Groove to Zammad.
What Data Can You Export from Groove?
Groove's data model is flat compared to platforms like Zendesk or Freshdesk — it centers on individual customers rather than organizations, and most configuration objects (rules, canned responses, reporting) have no API surface at all. Here is what exists and how each object type can be extracted:
| Data Object | Built-in Export | REST API v1 | GraphQL API v2 |
|---|---|---|---|
| Conversations/Tickets | ✅ Full JSON | ✅ GET /v1/tickets |
✅ Conversations query |
| Messages (replies + notes) | ✅ Included in export | ✅ GET /v1/tickets/:id/messages |
✅ Nested in conversations |
| Customers | ❌ Not separate | ✅ GET /v1/customers |
✅ Contacts query |
| Agents | ❌ Not included | ✅ GET /v1/agents |
✅ Agents query |
| Mailboxes | ❌ Not included | ✅ GET /v1/mailboxes |
✅ Mailboxes query |
| Tags/Labels | ✅ On each ticket | ✅ On ticket objects | ✅ Tags query |
| Attachments | ✅ URLs only | ✅ GET /v1/attachments |
✅ Via messages |
| Groups | ❌ Not included | ✅ GET /v1/groups |
✅ Teams query |
| Folders | ❌ Not included | ✅ GET /v1/folders |
✅ Folders query |
| Knowledge Base articles | ❌ No bulk export | ✅ GET /v1/kb/:id/articles |
✅ KB Articles query |
| KB Categories | ❌ No bulk export | ✅ GET /v1/kb/:id/categories |
✅ KB Categories query |
| Custom Fields | ✅ On conversations | ✅ On ticket objects | ✅ customFieldValues |
| Instant Replies | ❌ | ❌ | ❌ |
| Rules/Automations | ❌ | ❌ | ❌ |
| Reports/Analytics | ❌ | ❌ | ❌ |
Not exportable: Instant Replies (canned responses), automation rules, round-robin configurations, CSAT survey results, and reporting data have no export or API surface. Screenshot or manually document these before deactivating your account.
Method 1: Groove's Built-in Conversation Export
The fastest way to get ticket history out of Groove is the built-in export available to account Owners and Admins.
How to request the export
- Go to Settings → Company → More → Exports
- Click Request Export
- Wait for the email notification (or watch the status on the settings page)
- Download the GZIP file from the same settings page
What you get
The export produces a GZIP-compressed JSON file following Groove's v1 Tickets API "full" conversations format. It includes ticket metadata (status, assignee, tags, custom fields), all messages in each conversation thread, and customer contact information embedded in each ticket. (help.groovehq.com)
Constraints
- JSON only — no CSV option
- Conversations only — customers, agents, mailboxes, groups, folders, and KB articles are not included as separate exports
- One export at a time — you cannot queue multiple export requests
- Processing time varies — Groove processes exports in a FIFO queue shared across all customers; small accounts take minutes, large accounts can take up to 72 hours (help.groovehq.com)
- Short-lived download links — URLs are generated on Amazon S3 and expire quickly; they cannot be shared
- No date filtering — you get everything or nothing; there is no way to export a specific date range
Request your export early. If processing takes 72 hours, you do not want that delay falling in the middle of your cutover window.
When the built-in export is enough
If all you need is an archive of conversation history — for compliance, backup, or a quick migration to a platform that can ingest Groove's JSON format — the built-in export works. It is zero-code and captures ticket threads with full message bodies.
If you need customers as a standalone dataset, KB articles, agent metadata, or granular control over what you extract, you need the API.
Method 2: REST API v1
Groove's REST API v1 is officially deprecated — the docs show a banner stating it is no longer in active development and recommending GraphQL. But it remains functional and is the more documented, more battle-tested extraction surface for complete data pulls.
Authentication
All requests require a Bearer token in the Authorization header. Generate this token from your Groove account settings.
curl -i https://api.groovehq.com/v1/tickets \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"Key endpoints for data extraction
| Endpoint | Purpose | Pagination |
|---|---|---|
GET /v1/tickets |
List all conversations | Page-based, max 50/page |
GET /v1/tickets/:number |
Single ticket detail | N/A |
GET /v1/tickets/:number/messages |
Messages in a ticket | Page-based, max 50/page |
GET /v1/customers |
List all customers | Page-based |
GET /v1/customers/:email |
Single customer by email | N/A |
GET /v1/agents |
List all agents | Not paginated |
GET /v1/mailboxes |
List all mailboxes | Not paginated |
GET /v1/groups |
List all groups | Not paginated |
GET /v1/folders |
List all folders | Not paginated |
GET /v1/attachments?message=:id |
Attachments for a message | Per-message |
GET /v1/kb/:kb_id/articles |
KB articles | Page-based |
GET /v1/kb/:kb_id/categories |
KB categories | Page-based |
GET /v1/tickets/count |
Ticket counts by folder | N/A |
Ticket listing supports filters like assignee, customer, state, and folder — useful for mailbox-by-mailbox or owner-by-owner extraction instead of a single giant dump. (doc.groovehq.com)
Pagination
The REST API uses page-based pagination with page and per_page parameters. Maximum per_page for tickets and messages is 50. The response includes a meta.pagination object:
"meta": {
"pagination": {
"current_page": 1,
"total_pages": 23,
"total_count": 23,
"next_page": "https://api.groovehq.com/v1/tickets?page=2"
}
}For a full extraction, iterate through every page of tickets, then for each ticket fetch messages separately via GET /v1/tickets/:number/messages. This is inherently chatty — a 5,000-ticket account with an average of 6 messages per ticket requires at least 5,100 API calls (100 ticket pages + ~5,000 message fetches assuming single-page threads). At 200 calls/minute on the Standard plan, that minimum call count alone takes over 25 minutes — before accounting for retries, attachment fetches, or customer lookups.
Structural quirk: The ticket listing endpoint uses HATEOAS-style links rather than embedding related objects. You get URLs to the assignee, customer, and messages — not the actual data inline. A "full" extraction means following those links, which multiplies API calls significantly beyond the minimum estimate above.
Rate limits
Groove's published API rate limits are plan-based: 200 calls per minute on Standard, 400 on Plus, and 800 on Pro. (help.groovehq.com) The API returns HTTP 429 (Too Many Requests) when you exceed them.
Practical guidance:
- Implement exponential backoff with jitter on 429 responses
- Log every 429 and its
Retry-Afterheader (when present) to calibrate your throttle - Do not run extraction scripts during peak business hours — you share the rate limit pool with your live support team
- On Standard (200 calls/min), a complete extraction of a 10,000-ticket account with 6 messages per ticket and no attachment fetches requires roughly 10,200 calls minimum — about 51 minutes of pure API time at sustained throughput, longer with backoff
The summary field trap: The ticket listing endpoint returns a summary field that is intentionally truncated. If you need the full message body, you must fetch messages separately via the messages endpoint — the full content is in the body field of each message object. Do not build a migration off the summary. (doc.groovehq.com)
Sample extraction script
import requests
import time
import json
BASE_URL = "https://api.groovehq.com/v1"
HEADERS = {"Authorization": "Bearer YOUR_TOKEN"}
def fetch_paginated(endpoint, key):
"""Fetch all pages from a paginated Groove endpoint."""
results = []
page = 1
while True:
resp = requests.get(
f"{BASE_URL}/{endpoint}",
headers=HEADERS,
params={"page": page, "per_page": 50}
)
if resp.status_code == 429:
wait = int(resp.headers.get("Retry-After", 60))
time.sleep(wait)
continue
resp.raise_for_status()
data = resp.json()
results.extend(data.get(key, []))
pagination = data.get("meta", {}).get("pagination", {})
if page >= pagination.get("total_pages", 1):
break
page += 1
time.sleep(0.5) # Conservative throttle
return results
# Fetch core data
tickets = fetch_paginated("tickets", "tickets")
customers = fetch_paginated("customers", "customers")
# Fetch messages per ticket
for ticket in tickets:
ticket["messages"] = fetch_paginated(
f"tickets/{ticket['number']}/messages", "messages"
)This is a starting point, not production code. Add proper error handling, logging, checkpoint/resume logic (so you do not restart from scratch on failure), and attachment downloading for any real extraction. Without checkpoint/resume, a network failure at ticket 4,800 of 5,000 sends you back to zero.
Method 3: GraphQL API v2
Groove's GraphQL API v2 is the officially recommended API. It operates on a single endpoint — https://api.groovehq.com/v2/graphql — and uses the same Bearer token authentication.
curl https://api.groovehq.com/v2/graphql \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"query":"query { __typename }"}'Advantages over REST v1
- Fewer round trips: Fetch a conversation with its messages, customer, assignee, and tags in a single query instead of 3–4 REST calls — eliminating the HATEOAS link-following overhead
- Field selection: Request only the fields you need, reducing payload size
- Strongly typed schema: Introspect the schema to discover all available types and fields
- Rich filtering: The conversations query supports filters like
channelId,contactEmail,folderId,keywords,states,tagNames, and before/after created or updated timestamps (developer.groovehq.com)
Pagination
Groove's GraphQL uses cursor-based pagination (Relay-style). Request a first count and get a pageInfo object with hasNextPage and endCursor. Pass endCursor as the after argument to page forward. Unlike REST's page numbers, cursor pagination is stable under concurrent writes — if a new ticket is created mid-extraction, you will not skip or double-count pages.
query ConversationsPage($after: String) {
conversations(first: 50, after: $after) {
edges {
node {
id
number
subject
state
createdAt
assignee { email name }
contact { email name }
tags { edges { node { name } } }
messages(first: 100) {
edges {
node {
body
createdAt
note
author {
... on Agent { email }
... on Customer { email }
}
attachments { url filename }
}
}
}
}
}
pageInfo {
hasNextPage
endCursor
}
}
}Note that note (the boolean distinguishing public replies from private agent notes) is included in the message node above — map this field explicitly. Losing the public/private distinction breaks agent workflows in any target helpdesk.
For full thread fidelity, Groove's GraphQL docs recommend querying the events connection on a conversation when you need messages, ratings, state changes, and related activity alongside each other. That is more powerful but also more complex than walking REST endpoints for bulk export. (developer.groovehq.com)
What's still missing in GraphQL
Groove's developer docs note that the GraphQL API is still being built out. Based on current documentation:
- The docs warn that Inbox and Knowledge Base APIs are still being built, so coverage gaps compared to REST v1 are possible (developer.groovehq.com)
- Instant Replies, automation rules, and reporting data are not exposed in either API
- Webhooks are only configurable through REST v1 (
POST /v1/webhooks)
GraphQL does expose export records with states like REQUESTED, QUEUED, EXPORTING, COMPLETED, and FAILED — useful for monitoring if you are building against the schema. (developer.groovehq.com)
The REST v1 vs. GraphQL v2 state model mismatch
This is the most dangerous discrepancy between the two APIs for migration engineers. REST API v1 ticket states include pending. GraphQL v2's ConversationState enum includes SNOOZED, DELETED, and TRASH — but not PENDING.
If you extract historical ticket states from REST and apply that vocabulary to a GraphQL-based import or transformation layer, tickets with pending state will fail validation or silently default to open. Validate your state mapping against live account data from both APIs before writing any transformation code. Do not assume the APIs share a state vocabulary.
REST v1 vs. GraphQL v2: Which Should You Use?
| Factor | REST API v1 | GraphQL API v2 |
|---|---|---|
| Status | Deprecated (still works) | Actively developed |
| Documentation | More examples, battle-tested | Growing, some gaps |
| Request efficiency | Chatty — HATEOAS links require following each relation | Efficient — nested queries fetch relations inline |
| Pagination | Page-based (max 50/page), unstable under concurrent writes | Cursor-based (Relay), stable under concurrent writes |
| KB access | Full CRUD | Available, Groove warns of ongoing gaps |
| Webhook management | Yes (POST /v1/webhooks) |
No |
| State vocabulary | Includes pending |
Includes SNOOZED, DELETED, TRASH — no PENDING |
| Community tooling | More ready-made tools | Fewer options |
| Long-term viability | Could be removed eventually | Recommended path |
Recommendation by use case:
- One-time archive or migration, team comfortable with REST: Use v1. Better-documented coverage, battle-tested, and the HATEOAS overhead is tolerable for a single run.
- Ongoing sync or integration: Invest in GraphQL v2. Cursor pagination is more robust, and nested queries cut total API calls significantly.
- Large accounts (10,000+ tickets): GraphQL's ability to fetch a conversation with messages and metadata in one query can reduce extraction time by 60–70% compared to REST's per-ticket message fetches — assuming GraphQL covers all the object types you need, which must be verified before committing.
- KB-heavy accounts: Verify GraphQL KB coverage against REST v1 before switching. Groove's own docs flag this as incomplete.
Exporting Knowledge Base Articles
Groove's knowledge base has no bulk export feature in the admin UI. You have two API paths and one support-assisted option.
REST API v1
- List all knowledge bases:
GET /v1/kb - For each KB, list categories:
GET /v1/kb/:kb_id/categories - For each KB, retrieve articles:
GET /v1/kb/:kb_id/articles - Each article object includes
title,body(HTML),slug,state,tags,category_id,meta_description, and timestamps
Article and category search endpoints support keyword=* to pull everything and unpaginated=true — but Groove caps that mode at 100 results. Larger KBs need real pagination. (doc.groovehq.com)
If your KB is multilingual, include the translations endpoints. Groove documents translations by RFC 5646 locale code. (doc.groovehq.com)
Groove support can also assist with KB exports in CSV format on request. (help.groovehq.com)
GraphQL API v2
Query KB articles through the GraphQL endpoint with cursor-based pagination. This lets you pull article content, categories, and metadata in fewer requests — but note the API coverage caveat above; Groove's own docs flag KB as an area still being built out.
Edge cases
Embedded images: KB article bodies may contain image references hosted on Groove's CDN or S3. Download these images separately and rewrite the src attributes in the HTML body — they will not resolve after account deactivation. This applies to both API paths and is easy to miss when validating an export on a still-active account.
Protected KBs: The public KB API returns 404 Not Found when the knowledge base is password-protected or IP-restricted. If your export script gets 404s on KB endpoints, check access controls before assuming the KB is empty. Use admin-authenticated endpoints or temporarily lift restrictions during extraction. (doc.groovehq.com)
KB unpaginated=true cap: If you use unpaginated=true as a shortcut, results are capped at 100. A KB with 150 articles will silently return only 100 with no error or pagination metadata indicating truncation. Paginate explicitly for any KB over 100 articles.
Data You Cannot Export
Some Groove data has no export path through any method:
- Instant Replies / Canned Responses: No API endpoint in REST v1 or GraphQL v2. Screenshot each reply or manually copy the template text before canceling your account.
- Rules / Automations: No API endpoint. Document each rule's trigger, conditions, and actions by hand. You will rebuild these in your target platform — and the rebuild is non-trivial since rule logic is platform-specific.
- Round-robin assignment configurations: Not exportable. Note the assignment logic from Settings → Ticketing before deactivating.
- CSAT survey results: Not available through the API. Export from Groove's reports UI if the option is available to your plan, or screenshot the data.
- Report data: Not API-accessible. Take manual exports or screenshots from the reporting dashboard. Historical metrics cannot be reconstructed from ticket data alone.
Before requesting any export, audit your Groove account. Document active integrations, Instant Reply templates, and automation rules. This data will not be in your JSON export or API pulls, and you cannot retrieve it after account closure.
Handling Attachments
Both the built-in export and the APIs return URLs to attachments, not the files themselves. These URLs point to Amazon S3 and may become inaccessible after account closure.
Your extraction process must:
- Iterate through every message and identify attachment URLs
- Download the binary files during extraction — before account cancellation
- Map each file to its parent ticket and message ID in your local storage structure
Groove enforces a 20 MB file size limit per attachment and caps uploads at 25 attachments per message. Those are upload limits, but they are useful boundary checks when planning a re-import into a target system with stricter rules. (groovehq.com)
Do not cancel your Groove subscription before downloading all attachments. The URLs in your JSON export and API responses require the files to still be hosted. Download everything first, verify file counts against message-level attachment metadata, then cancel.
API Limits and Edge Cases That Break Exports
- Built-in export: Single-request FIFO jobs. Large accounts can take up to 72 hours. (help.groovehq.com)
- REST pagination cap: Tickets, messages, and customers top out at
per_page=50, creating heavy API traffic for large accounts. (doc.groovehq.com) - Plan-based rate limits: 200 calls/min on Standard, 400 on Plus, 800 on Pro. (help.groovehq.com)
- API call volume math: A 5,000-ticket account with 6 messages/ticket requires at minimum 5,100 REST API calls (100 ticket pages + 5,000 message fetches). Add customer lookups, attachment checks, and KB extraction and the real number is 2–3× higher.
- State model mismatch between APIs: REST includes
pending; GraphQL includesSNOOZED,DELETED,TRASHbut notPENDING. Validate state mapping against real account data before transforming historical records. summaryis truncated. Use message bodies from the messages endpoint, not summary previews. (doc.groovehq.com)- KB
unpaginated=truecaps at 100 results with no error or truncation signal. Paginate anything larger. (doc.groovehq.com) - Protected KBs return 404 from public search endpoints by design — not an empty result set. (doc.groovehq.com)
- HATEOAS overhead on REST v1: Every ticket listing response returns URLs to related objects, not the objects themselves. Following those links for assignee, customer, and messages turns one page fetch into 150+ calls for a 50-ticket page with full relations.
- Cursor stability advantage in GraphQL: REST page-based pagination can skip or duplicate records if tickets are created or updated during a long extraction. Cursor-based pagination in GraphQL does not have this problem, making it more reliable for large accounts where extraction takes hours.
Making a Groove Export Portable
Data portability means your export no longer depends on Groove's UI or an active account. For most teams, that means normalizing extracted data into stable entity files and storing binaries separately.
A clean portable directory structure:
groove-export/
conversations.jsonl
messages.jsonl
customers.jsonl
attachments/
mailboxes.json
folders.json
agents.json
groups.json
kb/
knowledge_bases.json
categories.jsonl
articles.jsonl
settings.json
translations/
manifest.jsonPreserve Groove IDs, ticket numbers, customer identifiers, mailbox/folder IDs, author type, the note boolean (public reply vs. private note — losing this distinction breaks agent workflows in any target helpdesk), timestamps, tags, custom field values, attachment metadata, and raw HTML bodies.
manifest.json should record extraction timestamp, Groove account ID, total counts per entity type, API version used (REST v1 or GraphQL v2), and a checksum per file. This gives you an audit trail if counts don't match during import validation.
If your target system only accepts CSV, flatten threads deliberately instead of stuffing an entire conversation into one cell. Using CSVs for SaaS Data Migrations covers the trade-offs.
Validation
Compare multiple totals, not just one. Groove's list endpoints return pagination totals, and tickets/count gives counts grouped by folder and optionally filtered by mailbox. That combination catches partial exports far better than eyeballing the size of a ZIP file. Cross-reference your extracted ticket count against tickets/count totals per folder — if numbers diverge by more than a rounding artifact, something failed silently. (doc.groovehq.com)
Transformation for relational helpdesks
If you are moving to Zendesk, Zammad, or a similar system, Groove's flat data model requires non-trivial transformation:
The "missing organization" problem: Groove's data model is customer-centric — it does not have an organization or company layer. Zendesk and Zammad both group users by Organization, and tickets are associated with organizations through user membership. To reconstruct this structure, you typically analyze customer email domains (e.g., grouping all @acmecorp.com addresses) and programmatically create organizations in the target system, linking users before importing tickets. This logic must be built — it does not come from Groove's export. Accounts with individual consumers rather than B2B customers may not need this, but B2B support operations almost always do.
State mapping: Groove's ticket states must map to your target system's exact status values. Get this wrong and all imported tickets default to "Open," destroying historical reporting. Map every Groove state explicitly — and account for the REST vs. GraphQL vocabulary divergence if your extraction used both APIs.
The note boolean: Groove messages have a note boolean (true = private agent note, false = public reply). Zendesk calls this public (the inverse). Zammad uses ticket article internal flag. Invert and rename this field correctly — if you lose it, all private notes become public-facing replies in your target system.
Custom fields: If your Groove account uses conversation-level custom fields, inspect them via the API's customFieldValues before assuming the default export captures everything you need. (help.groovehq.com) Custom fields do not have a universal import format — you will define equivalent fields in the target system first, then map by semantic meaning, not field ID.
HTML body handling: Groove stores message bodies as HTML. If your target system expects markdown (Zammad, for example, can use both), convert HTML to markdown during transformation rather than importing raw HTML and letting the target render it inconsistently.
Delta Sync and Cutover Planning
Migrations are not instantaneous. If extraction and loading takes three days, your team is still working in Groove during that window. You need a strategy for capturing changes made after your initial extraction snapshot.
API polling approach: After the initial extraction, run a final script querying for tickets with updatedAt after your cutoff date. Extract only new or modified tickets and push them to the target system. Note: filter on updatedAt, not createdAt — you need to catch existing tickets that received a new reply or state change during the migration window, not just new tickets created after your snapshot.
Webhook approach: Groove documents webhook events for ticket lifecycle changes, customer replies, notes, and agent replies. Set up webhooks before starting extraction to capture changes in real time until cutover is complete. Webhooks are configured through the REST v1 API (POST /v1/webhooks) or the Groove UI. (doc.groovehq.com)
Practical cutover sequence:
- Complete initial full extraction (all tickets, customers, KB, attachments)
- Load into target system in staging mode
- Validate counts and sample records
- Run delta extraction covering the extraction window
- Load delta records
- Switch DNS/routing to new helpdesk
- Verify with a few live test tickets
Common Pitfalls
-
Forgetting to download attachments. Attachment URLs point to S3 and become inaccessible after account deletion. Download every binary during extraction and verify file counts against attachment metadata before canceling.
-
Relying on the
summaryfield. The summary is intentionally truncated. Always fetch the full message body from thebodyfield in the messages endpoint response. -
Not extracting customers separately. The built-in export embeds customer info in each ticket but does not produce a clean customer list. For deduplication, CRM import, or organization mapping, pull customers explicitly via
GET /v1/customers. -
Ignoring KB articles. The built-in export does not include knowledge base content. Export it separately through the API before closing your account. KB embedded images must also be downloaded — they will not resolve after account deactivation.
-
Missing the
noteflag on messages. Groove distinguishes between public replies and private notes via thenoteboolean. Map this field correctly and invert/rename it for target platforms that use the opposite convention (e.g., Zendesk'spublicfield). Losing the public/private distinction exposes private agent notes to customers. -
Running extraction against a live account without throttling. The rate limit is shared with your support team. An unthrottled extraction script at 200 calls/min on Standard plan will cause 429 errors for agents during peak hours. Run heavy extractions during off-hours.
-
Ignoring the REST vs. GraphQL state mismatch. REST includes
pending; GraphQL includesSNOOZED,DELETED,TRASHbut notPENDING. If you mix APIs or transform data without accounting for this, tickets silently land in the wrong state. Validate against real account data before writing transformation code. -
Using
unpaginated=truefor large KBs. This parameter caps results at 100 with no truncation signal. A KB with 200 articles appears to fully export at 100 records. Paginate explicitly. -
No checkpoint/resume logic in extraction scripts. A network failure or rate limit cascade at ticket 4,800 of 5,000 restarts extraction from zero. Build checkpoint files that record the last successfully processed ticket number or cursor position.
-
Skipping the organization mapping step for B2B accounts. Groove has no organization layer. Zendesk and Zammad do. Without explicit organization creation and user linking before ticket import, all tickets arrive as orphaned from any company context.
Pre-Extraction Checklist
Before running any export or API script:
- Audit tags: Delete unused tags. Do not migrate garbage data.
- Identify spam: Decide whether to import spam tickets or filter them out during extraction.
- Document non-exportable data: Screenshot Instant Replies, automation rules, round-robin configs, and CSAT results.
- Test rate limits: Run a small extraction of ~1,000 tickets to calculate actual processing time and refine backoff logic before committing to a full run.
- Provision attachment storage: Set up an S3 bucket or equivalent to temporarily store downloaded attachments. Estimate storage: multiply average attachment size by
total_messages × average_attachments_per_message. - Check KB access controls: If your KB is password-protected or IP-restricted, the public API returns 404. Use admin endpoints or adjust restrictions before extraction.
- Inspect custom fields: Check if your account uses conversation-level custom fields and verify they appear in API responses before assuming the default export is complete.
- Verify state vocabulary: Pull a sample of tickets from both REST and GraphQL and compare state values. Document any discrepancies before writing transformation code.
- Plan checkpoint/resume: Decide on your checkpointing strategy before starting a large extraction — not after a failure.
How Long Does a Full Groove Export Take?
| Account Size | Built-in Export | REST API v1 (Standard plan, 200 calls/min) | GraphQL v2 |
|---|---|---|---|
| < 1,000 tickets | Minutes to hours | 30–60 min | 15–30 min |
| 1,000–10,000 tickets | Hours | 2–6 hours | 1–3 hours |
| 10,000+ tickets | Up to 72 hours | 8–24 hours | 4–12 hours |
These estimates assume conservative throttling, average 6 messages per ticket, minimal attachments, and no extraction failures requiring restarts. REST v1 timing assumes Standard plan rate limits (200 calls/min). On Pro (800 calls/min), REST times compress by roughly 4×. GraphQL timing assumes nested message queries reduce per-ticket round trips to 1–2 vs. REST's 2–3.
Actual times depend on messages per ticket, attachment counts, KB size, and how aggressively you approach rate limits without triggering 429 cascades.
When the Easy Export Stops Being Enough
Groove's built-in export handles archiving and simple backups. The complexity compounds when:
- You have 10,000+ tickets and need selective extraction (by mailbox, date range, or agent)
- You need KB articles, customer records, and conversations as a unified, deduplicated dataset
- Your target platform requires data transformations (timestamp normalization, HTML-to-markdown conversion, attachment re-hosting)
- You need zero-downtime cutover with delta sync for tickets created during migration
- You are hitting rate limits that stretch extraction across days
- You have B2B customers and need to reconstruct the organization layer before importing
At this point, you are doing ETL engineering, not clicking an export button. Build a staging environment, map fields to your target schema field-by-field (including edge cases like the note boolean inversion), test with a subset of 50–100 tickets including attachments, and verify attachment integrity and count before running a full migration.
For target-specific guidance, see Groove to Zendesk Migration or Groove to Zammad Migration.
Frequently Asked Questions
- How do I export all my data from Groove?
- Use the built-in export (Settings → Company → More → Exports) for conversation history as GZIP-compressed JSON. For customers, agents, KB articles, and other objects, use the REST API v1 or GraphQL API v2. There is no single button that exports everything.
- Does Groove support CSV export?
- No. Groove's built-in export produces GZIP-compressed JSON only, following the v1 Tickets API format. For KB articles, Groove support can assist with a CSV export. If you need CSV for ticket data, you must extract via the API and convert the JSON yourself.
- What are Groove's API rate limits?
- Groove's published API rate limits are plan-based: 200 calls per minute on Standard, 400 on Plus, and 800 on Pro. The API returns HTTP 429 when exceeded. Implement exponential backoff with jitter and avoid running extraction scripts during peak support hours.
- Can I export Groove knowledge base articles?
- Not through the admin UI. There is no bulk KB export. Use the REST API (GET /v1/kb/:id/articles) or GraphQL API to retrieve articles programmatically, including HTML body, categories, tags, and metadata. Groove support can also assist with a CSV export of KB content.
- Should I use Groove's REST API or GraphQL API for data export?
- REST v1 is deprecated but well-documented and has more complete coverage today. GraphQL v2 is actively developed and more efficient for large exports due to nested queries, but Groove's docs warn that Inbox and KB APIs are still being built. For a full, reliable extraction, REST v1 is the safer starting point.


