Automating Qtest test case sync: API upserts vs CSV vs Jira integration
Choose how to automate Qtest test case sync at scale. Compare REST API upserts, CSV import and native Jira integration on fidelity, auditability and maintenance, with a concrete idempotent upsert pattern and validation steps.
08 Jul 2026, 06:04 UTC

Problem: keep Qtest test cases in sync without UI automation
Engineering teams need bulk test case creation and updates in Qtest that preserve requirement traceability, audit history, and project permissions, while treating Jira as source of truth. The useful takeaway is to use REST API upserts keyed by a stable external ID rather than CSV imports or relying solely on native Jira sync when you need custom logic and auditability.
Decision constraints
This guide assumes Qtest Cloud or a recent on-prem release with REST API enabled and a service account with project-level access. The constraints are: no UI automation, preserve links to requirements, keep history entries, stay within API rate limits and permission scopes, and avoid fragile selectors.
- Data fidelity: custom fields, steps, and requirement links must survive sync.
- Auditability: changes should be attributable to a service account and visible in project history.
- Idempotency: re-running the job should not duplicate test cases.
- Operational safety: dry-run first, batch with backoff, config-driven project and module IDs.
Options compared
| Option | When it fits | Control | Audit/history | Maintenance |
|---|---|---|---|---|
| REST API bulk create/update | Ongoing sync, custom logic, non-Jira sources | Field-level, custom fields, requirement links | Preserved, attributed to service account | Code for token, pagination, retry |
| CSV import via UI | One-off migration | Limited to import template | Can overwrite metadata, links lost | Manual steps, not sustainable |
| Native Jira integration sync | Pure Jira test case fields, standard mapping | Limited to configured field mapping | Depends on integration settings | Low code, couples model to integration |
Trade-offs
API gives highest fidelity and automation. It requires token management, pagination handling, and retry logic for rate limits. It supports an external ID custom field for idempotent upserts, which is essential for safe re-runs.
CSV import is simplest for an initial load but is not sustainable. It creates manual steps, can overwrite metadata, and does not reliably maintain requirement traceability links.
Native Jira integration reduces code and is low maintenance for mapped fields, but it couples the data model to integration settings and cannot handle custom attributes, conditional logic, or sources outside Jira.
Recommended pattern: idempotent API upserts with external ID
Use a service account API key for authentication. Read source test definitions with a stable external ID, map them to Qtest test case attributes including custom fields and requirement links, and upsert by external ID.
Configuration
Keep project and module IDs as configuration, not hard-coded. Resolve custom field IDs and requirement linking at runtime per project to avoid cross-project errors.
Example request shape run from a CI runner or local dev machine with service account permissions to create/update test cases and link requirements in the target project:
curl -X POST '{{QTEST_BASE_URL}}/api/v3/projects/{{PROJECT_ID}}/test-cases' \
-H 'Authorization: Bearer {{API_KEY}}' \
-H 'Content-Type: application/json' \
-d '{
"externalId": "{{SOURCE_TEST_KEY}}",
"name": "{{TEST_NAME}}",
"moduleId": {{MODULE_ID}},
"customFields": [{"id": {{CUSTOM_FIELD_ID}}, "value": "{{VALUE}}"}],
"requirementIds": [{{REQ_ID}}]
}'Required permissions: service account with project scope for test case create/update and requirement link. Meaningful placeholders: QTEST_BASE_URL, API_KEY, PROJECT_ID, MODULE_ID, CUSTOM_FIELD_ID. Risks: wrong project scope creates cases in the wrong project; missing custom field mapping causes validation failures; excessive batch size triggers rate limiting.
Perform a dry-run validation first, then commit in batches with backoff for rate limits. Store the external ID in a Qtest custom field and use it to find existing cases before create or update.
Validation before production
Create a sandbox project. Run sync for a small representative set and inspect test case details, custom fields, and requirement links in the UI. Compare counts and field values against source. Review project audit logs to confirm changes are attributed to the service account and history is preserved.
Limitations and checks
API endpoints, authentication schemes and rate limits are version-sensitive between Qtest Cloud and on-prem releases. Verify current limits in Admin settings before bulk jobs. Custom field IDs and requirement linking are project-specific.
Bulk operations create many history entries; test in a non-production project to assess performance impact. Permission scopes for service accounts may differ from user accounts; confirm create/update/link permissions for test cases and requirements.
Practical checks: open Qtest Admin > Integrations and confirm API access is enabled and a service account key can be created with appropriate project scopes. Run a small dry-run sync and inspect mapping correctness. Check API response codes and error payloads for rate limiting and validation failures, and adjust batch size and retry logic accordingly.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.