How to Export Data from SurveySparrow Ticket Management
Three ways to export SurveySparrow ticket data — UI export, filtered CSV, and REST API v3 — plus rate limits, portability gaps, and practical migration strategies.
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 SurveySparrow Ticket Management
TL;DR: SurveySparrow's UI exports (Excel/JSON and CSV) cover ticket metadata only. Full portability — comments, attachments, contacts, and field definitions — requires the REST API (v3) at a tight 120 calls/hour, 1,000 calls/day rate limit. A 5,000-ticket extraction with comments takes roughly 5–6 days at maximum daily throughput, longer with backoff delays. These rate limit figures were obtained through SurveySparrow support confirmation and developer documentation — no public rate limit table exists.
Last verified: July 2025. SurveySparrow is actively developed. API behavior, rate limits, and UI paths may change. Verify against developers.surveysparrow.com before building extraction scripts.
SurveySparrow Ticket Management gives you three ways to get ticket data out: a UI-based export (Settings → Export Data) that outputs Excel or JSON, a CSV export from the ticket list view that mirrors your current filters and columns, and the REST API (v3) for programmatic extraction of tickets, comments, contacts, and field definitions. None of these methods give you everything in a single action.
The UI exports cover ticket metadata — subject, status, priority, assignee, requester, custom fields. Comments, attachments, and audit history require the API. If you're planning a migration, compliance archive, or warehouse ingestion, plan for a multi-step extraction.
This guide covers each method, maps out the API endpoints and their limits, shows actual API response shapes, identifies what you can't get out, and gives you a practical extraction plan for migration-ready exports.
Naming note: SurveySparrow's ticketing module appears as Ticket Management in their settings and help center, and as SparrowDesk on pricing pages and some integrations. They're the same system. The API endpoints use /v3/tickets.
SurveySparrow Ticket Management Data Model
Before you export anything, understand what's stored and how it connects. SurveySparrow's ticketing is a feedback-first system — meaning tickets are primarily generated from survey responses, NPS detractor scores, CSAT submissions, or form completions, and the data model reflects this origin. Unlike traditional helpdesks where tickets are created directly by agents or customers, every SurveySparrow ticket carries a provenance link back to a survey or review source. This affects migration: fields like template_id, submission_id, and source carry meaning that has no equivalent in conventional helpdesks like Zendesk or Freshdesk. (support.surveysparrow.com)
The core objects you'll encounter during extraction:
| Object | Key Fields | API Endpoint |
|---|---|---|
| Tickets | id, subject, description, description_html, priority, status, template_id, custom_fields, source, agent, team, requester, created_at, updated_at, first_response_due, resolution_due | GET /v3/tickets |
| Ticket Comments | Comment body, author, timestamps, attachment metadata/URLs, private flag | GET /v3/tickets/{id}/comments |
| Contacts | Contact id, email, name, properties | GET /v3/contacts |
| Ticket Fields | id, name, internal_name, type, options, is_default, mandatory | GET /v3/ticket-fields |
| Ticket Templates | Template definitions controlling which fields appear per team | GET /v3/templates |
| Teams | Team id, name, members | GET /v3/teams |
| Users | User/agent id, name, email, role | GET /v3/users |
A few things to know about this data model:
- Comments are separate from the ticket body. The ticket
descriptionis the initial content. All subsequent replies and internal notes live in the Ticket Comments object and require per-ticket API calls. - Custom fields support text (single-line and multiline), dropdown, date, and nested (multi-level dependent dropdowns) types. Custom fields have stable internal names even if display labels change later. (support.surveysparrow.com)
- Ticket Templates control which fields are visible per team — two teams may have different custom field configurations on their tickets.
- Parent-child ticket relationships exist. The create/update ticket API accepts
parent_ticket_idandchild_ticket_ids, though these fields may not appear in the GET response. Verify relationship extraction in your own workspace before assuming fidelity during migration. (support.surveysparrow.com)
What the API Response Actually Looks Like
Before writing extraction code, understand the actual JSON shape returned by the tickets endpoint. Here's an annotated example of a single ticket object from GET /v3/tickets:
{
"data": [
{
"id": 10482,
"subject": "Refund not processed after 7 days",
"description": "I submitted a refund request on June 3rd and haven't heard back.",
"description_html": "<p>I submitted a refund request on June 3rd and haven't heard back.</p>",
"priority": {
"id": 2,
"name": "High"
},
"status": {
"id": 3,
"name": "Open"
},
"source": {
"id": 1,
"name": "Email"
},
"template_id": 114,
"requester": {
"id": 8821,
"email": "customer@example.com",
"name": "Jane Doe"
},
"agent": {
"id": 42,
"email": "support@yourcompany.com",
"name": "Alex Kim"
},
"team": {
"id": 7,
"name": "Billing Support"
},
"custom_fields": {
"cf_order_number": "ORD-98234",
"cf_refund_amount": "49.99",
"cf_escalation_tier": {
"id": 3,
"name": "Tier 2"
}
},
"created_at": "2025-06-03T14:22:10Z",
"updated_at": "2025-06-05T09:15:44Z",
"first_response_due": "2025-06-03T18:00:00Z",
"resolution_due": "2025-06-05T14:00:00Z"
}
],
"has_next_page": true,
"next_page": 2
}Key structural observations:
priority,status,source, andagentare all objects with id + name, not flat strings. Your extraction code must handle nested objects, not just scalar values.custom_fieldsusescf_prefixed internal names as keys. Dropdown custom fields return an object ({id, name}); text fields return a string. Nested dropdown fields return a nested object. This inconsistency in thecustom_fieldsblock is the most common transformation failure point — code that assumes all custom fields are strings will silently drop dropdown values.has_next_pageis the pagination signal. Whenfalse, stop incrementing pages.agentreturnsnullfor unassigned tickets. Handle null safely.
Here's what the comments endpoint returns for GET /v3/tickets/{id}/comments:
{
"data": [
{
"id": 5591,
"body": "I've checked the order and the refund was initiated. Please allow 3–5 business days.",
"body_html": "<p>I've checked the order and the refund was initiated. Please allow 3–5 business days.</p>",
"private": false,
"author": {
"id": 42,
"name": "Alex Kim",
"email": "support@yourcompany.com",
"type": "agent"
},
"attachments": [
{
"id": 882,
"file_name": "refund_confirmation.pdf",
"file_url": "https://cdn.surveysparrow.com/attachments/882/refund_confirmation.pdf",
"file_size": 45210,
"content_type": "application/pdf"
}
],
"created_at": "2025-06-04T10:33:00Z"
}
],
"has_next_page": false
}Key structural observations for comments:
private: falsemeans customer-visible reply;private: truemeans internal note. You must call the endpoint twice (once per value) to get both.attachmentsis an array that may be empty ([]) or absent. Don't assume its presence.file_urlreturns a direct CDN URL. These URLs may expire or require authentication headers — download the binary immediately during extraction, don't store URLs for later retrieval.author.typedistinguishes agent-authored from contact-authored comments.
Method 1: UI Export (Settings → Export Data)
The simplest path. Navigate to Settings → Ticket Management → Export Data. (support.surveysparrow.com)
What it does:
- Exports ticket data in Excel (xlsx) or JSON format
- Lets you select which field categories to include: Ticket fields, Assignee details, and Requester details
- Within each category, you pick individual fields
How to use it:
- Log into SurveySparrow and click the Settings icon
- Under Ticket Management, click Export Data
- Choose your format (Excel or JSON)
- Select the fields you need across all three categories
- Click Export
What this export does NOT include: Ticket comments, conversation threads, attachments, and audit history are absent. You get the ticket record — subject, description, status, priority, custom fields, assignee info, requester info — but not the back-and-forth communication. For migration purposes, this is a significant gap.
When to use it: Quick reporting, audits, or getting a flat snapshot of ticket metadata. Not sufficient for a full migration where you need conversation history.
Method 2: CSV Export from Ticket List View
This is a separate export path, accessed directly from the ticket list — not from Settings. (support.surveysparrow.com)
How to use it:
- Navigate to Tickets → ticket list view
- Apply any filters you need (status, priority, date range, team, etc.)
- Adjust columns to show the fields you want exported
- Click the three-dot icon in the top right corner
- Click Export CSV
Key behavior: The exported CSV reflects your current view — applied filters, visible columns, and sort order. Only data matching your filter criteria is included. If you want everything, clear all filters first.
The UI's filtering surface is actually broader than what the API offers. In Ticket View, you can filter by Ticket, Survey, Contact, and Rating/Review criteria — including survey type, response properties, contact details, platform, and rating. The /v3/tickets API endpoint only supports filters for requester, assignee, team, priority, status, dates, and trash state. This creates a real portability gap: if your team works in filtered views segmented by survey type or review platform, you cannot replicate those exact filter criteria programmatically. (support.surveysparrow.com)
When the data exceeds the platform's downloadable limit, SurveySparrow automatically splits the export into multiple files. The exact row threshold isn't documented.
When to use it: Targeted exports with specific filters, spot-checks, or exporting a filtered subset. Like the Settings export, this won't include comments or attachments.
Method 3: REST API (v3) — Full Extraction
The API is the only way to get a complete export that includes tickets and their conversation history. If you're migrating to another helpdesk, this is the required path.
Authentication
SurveySparrow uses OAuth 2.0 for API authentication. Generate an access token through Settings → Apps & Integrations by creating a private app.
curl --request GET \
--url 'https://api.surveysparrow.com/v3/tickets' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN'Data center matters. Your API base URL depends on your account's data center region. The default is api.surveysparrow.com, but regional accounts use different URLs. Confirm your base URL with SurveySparrow support before writing extraction scripts. (developers.surveysparrow.com)
API Rate Limits
This is where SurveySparrow gets restrictive compared to platforms like Zendesk (700 requests/minute on Enterprise) or Freshdesk (1,000 requests/hour on Growth, 9,000/hour on Enterprise).
The documented rate limits are 120 API calls per hour and 1,000 API calls per day. SurveySparrow does not publish a public rate limit table broken down by plan tier. These figures come from their developer documentation and support confirmation. Enterprise accounts may have higher ceilings, and the pricing page lists an Additional API Calls add-on, so verify your allocation before scheduling a large extraction. (surveysparrow.com)
What a 429 response looks like:
{
"error": {
"code": 429,
"message": "Rate limit exceeded. Please try again later."
}
}The 429 response does not include a Retry-After header in current API behavior. Use a fixed backoff interval of at least 60 seconds, then implement exponential backoff on consecutive 429s.
What those limits mean for extraction at scale:
- Tickets endpoint: Max 100 records per request. For 5,000 tickets, that's 50 requests for ticket records.
- Comments: A separate API call per ticket — no bulk "get all comments" endpoint exists. For 5,000 tickets, that's 5,000+ requests minimum (more if you call both
private=falseandprivate=trueseparately: up to 10,000 calls). - At 1,000 calls/day: Extracting 5,000 tickets with comments takes 5–10 days depending on whether you make one or two comment calls per ticket.
| Account Size | Ticket Requests | Comment Requests (×2) | Total API Calls | Days at 1,000/day |
|---|---|---|---|---|
| 500 tickets | ~5 | ~1,000 | ~1,005 | ~1 day |
| 2,000 tickets | ~20 | ~4,000 | ~4,020 | ~4 days |
| 5,000 tickets | ~50 | ~10,000 | ~10,050 | ~10 days |
| 10,000 tickets | ~100 | ~20,000 | ~20,100 | ~20 days |
The hourly cap is the real bottleneck. Even if your daily limit is 1,000, you can only burn 120 per hour. Your extraction script needs proper backoff and scheduling — don't just hammer the API and eat 429 errors. At 120/hour with a 30-second inter-call delay (2 calls/minute = 120/hour), you're already at the ceiling.
Key Extraction Endpoints
Schema and lookup objects (extract these first):
GET /v3/ticket-fields
GET /v3/templates
GET /v3/teams?type=TICKET
GET /v3/users
GET /v3/contact_propertiesExport schema before ticket data. Custom field dropdown options update on existing tickets when admins change them, so capturing the schema first prevents drift between field definitions and field values. The GET /v3/ticket-fields response includes each field's internal_name, type, and options array (for dropdown fields). Use internal_name — not the display label — as your stable key for field mapping. (developers.surveysparrow.com)
Tickets (active and trashed):
GET /v3/tickets?limit=100&page=1 # active tickets
GET /v3/tickets?limit=100&page=1&trash=true # trashed ticketsQuery parameters for filtering:
requester_id— filter by contact IDassignee_id— filter by agent user IDteam_id— filter by teampriority— filter by priority levelstatus— filter by statuscreated_date.gte/created_date.lte— date range (ISO 8601)updated_date.gte/updated_date.lte— updated date rangetrash—truereturns trashed tickets,false(default) returns active
Pagination uses page and limit (max 100). The response includes a has_next_page boolean — keep incrementing page until it returns false. (developers.surveysparrow.com)
Trashed tickets are hidden by default. GET /v3/tickets returns only active tickets unless you pass trash=true. If you need deleted tickets for compliance or audit purposes, run a second extraction pass with this parameter.
Ticket comments (per ticket):
GET /v3/tickets/{id}/comments?private=false&limit=100&page=1 # public replies
GET /v3/tickets/{id}/comments?private=true&limit=100&page=1 # internal notesThis is a separate call per ticket — there is no bulk "get all comments across all tickets" endpoint. The private parameter controls visibility. You must call both private=false and private=true to get the complete thread. Skip either and you'll lose public replies or internal notes. For high-volume accounts, consider making only one call with both values if the API supports it — check documentation for any updates to this behavior. (developers.surveysparrow.com)
What happens when a ticket has no comments: The endpoint returns {"data": [], "has_next_page": false}. Handle empty arrays gracefully — don't treat an empty data array as an error.
Contacts:
GET /v3/contacts?limit=50&page=1You need contacts to resolve requester information and match emails during migration. Contacts paginate at a max of 50 per request, not 100. (developers.surveysparrow.com)
Source context (when provenance matters):
GET /v3/responses?survey_id={survey_id}&limit=200&page=1If tickets originated from surveys or reviews, export the source records too. Responses paginate at max 200 per request. For review-driven tickets, also pull reputation platform and review objects. (developers.surveysparrow.com)
Page-Size Caps by Endpoint
| Endpoint | Max per Request |
|---|---|
| Tickets, comments, ticket fields, teams | 100 |
| Contacts, users, reputation reviews | 50 |
| Responses | 200 |
API Extraction Script Pattern
A practical extraction flow in Python:
import requests
import time
import json
BASE_URL = "https://api.surveysparrow.com/v3"
HEADERS = {"Authorization": "Bearer YOUR_TOKEN"}
RATE_DELAY = 31 # seconds between calls to stay under 120/hr (~116/hr with overhead)
def get_all_tickets(progress_file="progress.json"):
"""Extract all tickets with resumability."""
tickets = []
page = 1
# Load progress if resuming
try:
with open(progress_file) as f:
progress = json.load(f)
page = progress.get("last_page", 1)
tickets = progress.get("tickets", [])
except FileNotFoundError:
pass
while True:
resp = requests.get(
f"{BASE_URL}/tickets",
headers=HEADERS,
params={"limit": 100, "page": page}
)
if resp.status_code == 429:
print(f"Rate limited. Waiting 90 seconds...")
time.sleep(90) # Start with 90s; double on consecutive 429s
continue
resp.raise_for_status()
data = resp.json()
tickets.extend(data["data"])
# Save progress after every page
with open(progress_file, "w") as f:
json.dump({"last_page": page, "tickets": tickets}, f)
if not data.get("has_next_page", False):
break
page += 1
time.sleep(RATE_DELAY)
return tickets
def get_ticket_comments(ticket_id):
"""Get both public replies and internal notes for a single ticket."""
comments = []
for private in [False, True]:
page = 1
while True:
resp = requests.get(
f"{BASE_URL}/tickets/{ticket_id}/comments",
headers=HEADERS,
params={"private": str(private).lower(),
"limit": 100, "page": page}
)
if resp.status_code == 429:
time.sleep(90)
continue
resp.raise_for_status()
data = resp.json()
comments.extend(data.get("data", []))
if not data.get("has_next_page", False):
break
page += 1
time.sleep(RATE_DELAY)
return comments
def download_attachment(attachment, output_dir="attachments"):
"""Download attachment binary from CDN URL immediately — URLs may expire."""
import os
os.makedirs(output_dir, exist_ok=True)
file_path = f"{output_dir}/{attachment['id']}_{attachment['file_name']}"
if os.path.exists(file_path):
return file_path # Skip already downloaded
response = requests.get(attachment["file_url"], headers=HEADERS)
with open(file_path, "wb") as f:
f.write(response.content)
return file_path
# --- Main extraction ---
tickets = get_all_tickets()
# Track which ticket IDs have been comment-extracted
extracted_ids = set()
try:
with open("comment_progress.json") as f:
extracted_ids = set(json.load(f))
except FileNotFoundError:
pass
for ticket in tickets:
tid = ticket["id"]
if tid in extracted_ids:
continue
comments = get_ticket_comments(tid)
# Download attachments immediately — don't store URLs only
for comment in comments:
for attachment in comment.get("attachments", []):
attachment["_local_path"] = download_attachment(attachment)
ticket["_comments"] = comments
extracted_ids.add(tid)
# Save progress
with open("comment_progress.json", "w") as f:
json.dump(list(extracted_ids), f)
time.sleep(RATE_DELAY)
# Save raw JSON — transform separately
with open("surveysparrow_export.json", "w") as f:
json.dump(tickets, f, indent=2)Save raw API responses. Don't transform data during extraction. Save the raw JSON first, then build your transformation layer separately. If you need to re-map fields for a different target system later, you won't need to re-extract from SurveySparrow.
Data You Can't Export (Portability Gaps)
Every platform has blind spots. Here's what's hard or impossible to get out of SurveySparrow Ticket Management:
- Attachment binaries: The API returns attachment URLs within comment payloads, but CDN URLs may be signed or time-limited. Download the binary files during extraction — don't store the URL string for later retrieval. Supported file types on ingest: pdf, png, jpeg, mp3, csv, wav at 15 MB max per file. (developers.surveysparrow.com)
- Inline images: Images pasted into the rich text editor are hosted on SurveySparrow's CDN and embedded as HTML
<img>tags indescription_htmlandbody_htmlfields. Your script must parse the HTML body, extractsrcattributes, download the images, and rewrite the HTML to point to your new hosting environment. A regex likere.findall(r'src="(https://cdn\.surveysparrow\.com [^"]+)"', html)will capture them. - SLA policies: You can see
first_response_dueandresolution_duetimestamps on tickets, but the SLA rules that generated those timestamps — breach conditions, escalation paths, business hours definitions — aren't exposed via API. - Workflow and automation rules: No API endpoint exists to export ticket workflow configurations. Document these manually before migrating.
- Ticket audit logs: There's no changelog endpoint showing field-level changes over time (who changed status from Open to Resolved, when, from what value). You get current state only.
- Survey context linkage: The API may include a
submission_idorsurvey_idon the ticket, but unless your target platform supports custom objects, you'll lose the direct link between ticket and survey response. Best practice: extract the survey response data and inject it as the first internal note of the migrated ticket. - Agent mapping for deleted users: If an agent's SurveySparrow account was deleted, the API returns
"agent": nullfor that ticket. Maintain a mapping table of historical agent IDs to emails (collected before deletion) to preserve accurate ownership on closed tickets. - Custom field history: Custom fields store current value only. If a dropdown option was renamed or removed, historical tickets show the current schema, not the value at time of creation.
The Transformation Problem: Where Migrations Actually Break
Getting data out is straightforward compared to transforming it for a target system. Here's what the transformation layer must handle for common migration targets:
Custom field type mismatches:
SurveySparrow's custom_fields block returns mixed types — strings for text fields, {id, name} objects for dropdowns, and nested {id, name, child: {id, name}} objects for hierarchical fields. A Zendesk custom field expects a single scalar value. The transformation must:
- Detect the field type from the ticket-fields schema
- Extract the
namestring from dropdown objects - Flatten nested dropdowns to a delimited string (e.g.,
"Tier 2 > Hardware")
Status and priority mapping:
SurveySparrow statuses are workspace-configurable. You cannot assume status.name: "Open" maps to any particular status in the target. Build an explicit mapping table:
STATUS_MAP = {
"Open": "open",
"In Progress": "pending",
"Resolved": "solved",
"Closed": "closed",
# Add your custom statuses here
}Comment ordering and authorship:
SurveySparrow comments have a created_at timestamp but no guaranteed sequence integer. Sort by created_at before writing to the target. author.type distinguishes agent ("agent") from customer ("contact") — most helpdesks require this distinction to set reply direction correctly.
Requester identity:
The requester object returns {id, email, name}. When the contact email matches an existing customer in the target system, associate the ticket to that contact. When it doesn't, create the contact first. Running contacts extraction before ticket import prevents foreign key failures.
Edge Cases That Break Migrations
A few SurveySparrow behaviors that are easy to miss:
- Review-generated tickets have weak requester identity. Review-created tickets use a placeholder requester email rather than the reviewer's real email. Reputation data syncs every 12 hours. If identity matters, export the review objects separately and account for the lag. (support.surveysparrow.com)
- UI filters don't match API filters. A filtered CSV from the ticket view can represent survey or review criteria that the ticket API doesn't expose. Teams often assume an API export will mirror the UI view — it won't. If you need to replicate a UI-filtered export programmatically, you must post-filter the full API export in your own code. (support.surveysparrow.com)
- Parent-child relationship fields may not round-trip. The create-ticket API accepts
parent_ticket_idandchild_ticket_ids, but the documented GET schemas don't clearly list those fields. Validate relationship extraction in your workspace before promising fidelity. (support.surveysparrow.com) - Batch creation isn't a full-history round-trip.
/v3/tickets/batchaccepts JSON ticket bodies (a limitation to plan for if you are migrating JSON data back into SurveySparrow) but the documented payload has no attachment or threaded-comment fields. Useful for loading shell tickets, not complete histories. (developers.surveysparrow.com) - Ticket subject caps at 200 characters on create. If you need to round-trip data back into SurveySparrow, longer subjects need truncation. (developers.surveysparrow.com)
- Null agent on unassigned tickets.
"agent": nullis a valid API response for unassigned tickets. Code that accessesticket ["agent"]["email"]without null checking will crash mid-extraction. - Empty comment arrays. Tickets with no replies return
{"data": [], "has_next_page": false}— not an error. Don't interpret an empty data array as a failed request.
Export Strategy by Use Case
Quick audit or reporting
Use the Settings → Export Data UI. Pick Excel format, select all fields, and you'll have a flat file in minutes.
Migration to another helpdesk
You need the API path. The UI exports don't include comments, and comments are the actual support conversations — the most important data in a migration. Plan extraction around the rate limits. For accounts over 2,000 tickets, start extraction at least a week before your planned migration cutover, accounting for comment API calls, backoff delays, and transformation time.
Recommended extraction order:
GET /v3/ticket-fields— schema firstGET /v3/users,GET /v3/teams— lookup tablesGET /v3/contacts— requester identityGET /v3/tickets(active, thentrash=true) — ticket records- Per-ticket comment extraction — the long pole
- Attachment binary downloads — concurrent with step 5
Target-specific guides:
- SurveySparrow to HappyFox Migration Guide
- SurveySparrow to Front Migration Guide
- SurveySparrow to Zendesk Migration Guide
- SurveySparrow to Missive Migration Guide
Filtered subset export
Use the ticket list view CSV export. Apply your filters, confirm the columns, and export. Fastest path for targeted data pulls. Note: filters available in the UI (survey type, review platform, contact properties) cannot be replicated exactly via the API.
Ongoing data sync
Combine webhooks for real-time event capture with periodic API polling for reconciliation. This works when running SurveySparrow in parallel with another system during a transition period.
Field Mapping Reference for Migrations
When exporting for migration, map SurveySparrow's fields to your target helpdesk schema:
| SurveySparrow Field | API Type | Common Target Field | Notes |
|---|---|---|---|
subject |
string | Subject/Title | Max 200 characters in SurveySparrow |
description |
string | Body (plain text) | Initial ticket content only |
description_html |
string | Body (HTML) | Preserves formatting; may contain inline images requiring CDN migration |
priority.name |
string (nested) | Priority | Map explicitly to target's priority levels |
status.name |
string (nested) | Status | Map explicitly; workspace-configurable |
requester.email |
string (nested) | Requester/Customer email | Primary contact identifier |
agent.email |
string (nested) | Assignee | May be null for unassigned; map to target agent accounts |
team.name |
string (nested) | Group/Team | May not have a 1:1 match |
custom_fields.cf_* |
mixed (string or object) | Custom fields | Requires type-aware mapping; dropdowns are {id, name} objects |
created_at |
ISO 8601 | Created date | — |
template_id |
integer | Category/Type | Resolve via GET /v3/templates |
source.name |
string (nested) | Channel/Source | Email, form, survey, etc. |
Run the Ticket Fields endpoint first. GET /v3/ticket-fields returns every custom field definition, including dropdown options and nested field hierarchies. Build your field mapping from this response — don't infer field types from sample ticket data, because a ticket with no value for a dropdown field won't tell you that field is a dropdown.
Practical Rate Limit Tactics
The 120 calls/hour limit is tight. Here's what works:
- Extract tickets first, then comments. Get all ticket records in one pass (relatively few API calls), save them, then start per-ticket comment extraction as a separate phase. This gives you a checkpoint — if the comment extraction crashes, you don't re-extract tickets.
- Segment by date range. If you have 10,000 tickets spanning 3 years, extract quarter-by-quarter using
created_date.gteandcreated_date.lte. This gives you natural checkpoints for resumability. - Implement exponential backoff. When you hit a 429, wait 90 seconds. If the next call also 429s, wait 180 seconds, then 360. Reset the delay after a successful response.
- Track progress externally. Write extracted ticket IDs to a separate progress file after each successful API call. If your script crashes at ticket 3,247, resume from where you left off — don't restart from zero.
- Run extraction overnight. Your daily cap resets — start heavy extraction runs at the beginning of your rate limit window to maximize the day's allocation.
- Use date-range segmentation for parallel extraction. If you have multiple API credentials (multiple private apps), you can divide the ticket date range across credentials. Each credential has its own rate limit bucket.
For accounts over 5,000 tickets, the comment extraction alone can take 10+ days at the 1,000 calls/day limit (10,000 comment calls ÷ 1,000/day). Factor this into your migration timeline.
Third-Party Tools
If scripting isn't practical:
- Airbyte has a SurveySparrow source connector that handles pagination and rate limiting. Verify that the connector covers the ticketing endpoints — many SurveySparrow connectors focus on survey responses, not tickets. The connector uses the same REST API, so the same rate limits apply. Check the connector's schema documentation for which objects it pulls before committing.
- Zapier can trigger on ticket events and push data to Sheets, Airtable, or other targets. Practical for ongoing sync but inefficient for bulk historical export — it processes events individually, not in bulk.
- Webhooks: SurveySparrow supports outgoing webhooks that fire on ticket events. Not useful for historical data, but worth setting up before migration to capture tickets created during the transition window.
No mainstream migration tool currently lists SurveySparrow Ticket Management as a fully supported connector. Help Desk Migration's public platform list places SparrowDesk under planned/upcoming integrations. (help-desk-migration.com) Expect custom extraction work rather than a commodity connector.
When to Build vs. When to Get Help
Self-serve extraction works well for accounts under 2,000 tickets with simple flat custom fields and no attachment migration requirement. Complexity increases when:
| Condition | Complexity Driver |
|---|---|
| 5,000+ tickets | Rate limits extend extraction to 10+ days; progress tracking becomes critical |
| Comments required | Every ticket needs 2 additional API calls; majority of total API budget |
| Attachments required | Binary download + CDN URL handling + file re-hosting in target |
| Nested dropdown custom fields | Type-aware extraction and flattening before target import |
| Deleted agent history | Null-agent handling; external ID mapping table required |
| Zero-downtime cutover | Webhook setup + delta extraction to catch tickets created during migration window |
| Custom target import format | Strict validation schemas require transformation testing before bulk load |
The extraction phase — getting data out of SurveySparrow — is mechanical and deterministic given the rate limits. The transformation phase — converting SurveySparrow's feedback-first schema to a conventional helpdesk schema — is where field type mismatches, missing requester records, and null-agent edge cases cause load failures.
For more on flat-file approaches, read Using CSVs for SaaS Data Migrations. For cutover planning, see Zero-Downtime Help Desk Data Migration.
Frequently Asked Questions
- How do I export tickets from SurveySparrow?
- Three ways: Settings → Ticket Management → Export Data for Excel (xlsx) or JSON, the ticket list view three-dot menu for CSV, or the REST API v3 at GET /v3/tickets for full programmatic extraction including comments.
- Does SurveySparrow ticket export include comments and conversation history?
- No. Both UI-based exports (Settings export and CSV from list view) only include ticket metadata — subject, status, priority, custom fields, assignee, and requester. To export comments and conversation history, you must use the REST API's per-ticket comments endpoint at GET /v3/tickets/{id}/comments.
- What are SurveySparrow's API rate limits?
- The documented limits are 120 API calls per hour and 1,000 calls per day. These vary by plan tier, with enterprise accounts potentially having higher ceilings. Exceeding the limit returns a 429 status code. Check your plan's allocation and the Additional API Calls add-on on the pricing page.
- How do I export private notes from SurveySparrow tickets?
- Use the comments API endpoint with the private parameter. Call GET /v3/tickets/{id}/comments with private=false for public replies and private=true for internal notes. You must run both calls to get the complete thread.
- How long does a full SurveySparrow ticket export take via API?
- It depends on volume. At 1,000 API calls per day, 500 tickets with comments takes under a day, 5,000 tickets takes about 5 days, and 10,000 tickets takes roughly 10 days. The 120 calls/hour hourly cap is the real bottleneck.


