Testing FHIR Bulk Data Export with Postman
This tutorial walks you through setting up Postman to test FHIR Bulk Data Export APIs using OAuth 2.0 client credentials flow in the Preview environment. You'll learn the complete bulk export workflow including initiating exports, polling for completion, and downloading result files.
Important: This tutorial uses the Preview environment with test data. Do not use these techniques with production environments containing real patient health information.
Prerequisites
- Postman installed
- Request access to a CareConnect tenant in the Preview environment for testing
- Register your application as a System Access App with CareConnect, which will provide:
- Client ID
- Client Secret
- Tenant ID
- Basic understanding of FHIR, OAuth 2.0, and asynchronous processing concepts
- Completion of the System Access tutorial is recommended
Bulk Data Export requires system-level access with specific bulk data scopes. Your CareConnect app registration must include bulk data export permissions to access the $export operations.
Overview
Bulk Data Export enables secure, asynchronous export of large FHIR datasets using the FHIR Bulk Data Access Implementation Guide. This tutorial covers:
- Setting up a Postman environment with bulk data variables
- Creating a collection with OAuth 2.0 client credentials authorization
- The complete bulk export workflow:
- CapabilityStatement validation
- Group discovery and selection
- Export initiation
- Status polling
- File download
- Troubleshooting common bulk export issues
Step 1: Create a Postman Environment
Creating the Environment
- Open Postman
- Click the Environments tab in the left sidebar
- Click Create Environment
- Name your environment (e.g., "FHIR Bulk Export - Dev")
Adding Environment Variables
Add the following variables to your environment:
| Variable Name | Type | Initial Value | Current Value |
|---|---|---|---|
tenant_id | default | your-tenant-id | your-tenant-id |
base_url | default | https://fhirtest.netsmartcloud.com/provider/system-access/v2 | https://fhirtest.netsmartcloud.com/provider/system-access/v2 |
auth_base_url | default | https://fhirtest.netsmartcloud.com/auth | https://fhirtest.netsmartcloud.com/auth |
client_id | default | your-client-id | your-client-id |
bulk_data_scope | default | system/*.rs | system/*.rs |
group_id | default | (optional - can use specific Group ID in URL instead) |
Replace your-tenant-id with your actual tenant ID from your CareConnect app registration.
Adding Secrets
For client secret authentication:
- In your environment, add a new variable
- Set Variable Name to
client_secret - Set Type to secret
- Enter your client secret from your CareConnect app registration
CareConnect also supports private key JWT authentication, but Postman does not natively support this method. Private key JWT also requires your public key to be registered with CareConnect or accessible via a JWKS URI. If your app registration uses private key JWT:
- Register a separate application with client secret authentication for Postman testing
- For production private key JWT, ensure your JWKS URI is publicly accessible
Save and Select Environment
- Select Save
- Select your environment from the dropdown in the top-right corner
Step 2: Create a Collection with OAuth 2.0 Authorization
Creating the Collection
- Select Collections in the left sidebar
- Select Create Collection
- Name it "FHIR Bulk Data Export"
- Add a description: "Collection for testing FHIR Bulk Data Export APIs with asynchronous workflow"
Adding Collection Variables
Add variables for temporary URLs generated during the export workflow:
- In your collection, select the Variables tab
- Add the following variables:
| Variable Name | Initial Value | Current Value |
|---|---|---|
export_status_url | ||
export_output_url |
- Select Save
Configuring OAuth 2.0 Authorization
- In your collection, select the Authorization tab
- Set Type to OAuth 2.0
- Configure the following settings:
| Field | Value |
|---|---|
| Token Name | CareConnect Bulk Export Token |
| Grant Type | Client Credentials |
| Access Token URL | {{auth_base_url}}/:tenant_id/oauth2/v1/token |
| Client ID | {{client_id}} |
| Client Secret | {{client_secret}} |
| Scope | {{bulk_data_scope}} |
| Client Authentication | Send as Basic Auth header |
Step 3: Create API Requests
Request 1: CapabilityStatement
Verify the server supports bulk data export operations.
- In your collection, select Add request
- Name: "Get CapabilityStatement"
- Method: GET
- URL:
{{base_url}}/:tenant_id/metadata - Authorization tab: Set Type to No Auth
- Params tab:
- Path Variables: Set
tenant_idto your tenant ID or{{tenant_id}}to use environment variable
- Path Variables: Set
- Select Save
Test the request:
- Select Send
- Look for
$exportoperations in the CapabilityStatement - Verify Group resource supports
$exportoperation
Request 2: Get Access Token
Before making authenticated requests, obtain an access token:
- Go to your collection's Authorization tab
- Select Get New Access Token
- Postman will exchange your client credentials for an access token
- Select Use Token to apply it to your collection
Request 3: Group Search
Find available Groups for export.
- Add a new request: "Group Search"
- Method: GET
- URL:
{{base_url}}/:tenant_id/Group - Authorization tab: Set Type to Inherit auth from parent
- Params tab:
- Path Variables: Set
tenant_idto your tenant ID or{{tenant_id}}to use environment variable - Query Params: Add query parameters:
- Key:
_count, Value:10
- Key:
- Path Variables: Set
- Select Save
Test the request:
- Select Send
- Look for Groups in the response
- Copy a Group ID from
entry[].resource.idfor use in the export request's path parameter - Optionally update your
group_idenvironment variable for reuse
Request 4: Initiate Group Export
Start the bulk export process for a specific Group. The Bulk Data Export specification supports both GET and POST methods:
- GET Request
- POST Request
- Add a new request: "Initiate Group Export (GET)"
- Method: GET
- URL:
{{base_url}}/:tenant_id/Group/:group_id/$export - Authorization tab: Set Type to Inherit auth from parent
- Headers tab: Add required headers:
- Key:
Accept, Value:application/fhir+json - Key:
Prefer, Value:respond-async
- Key:
- Params tab:
- Path Variables:
- Set
tenant_idto your tenant ID or{{tenant_id}}to use environment variable - Set
group_idto a specific Group ID or{{group_id}}to use environment variable
- Set
- Query Params (optional):
- Key:
_type, Value:Patient,Observation,Condition(specify resource types) - Key:
_since, Value:2023-01-01T00:00:00Z(export data since date) - Key:
_outputFormat, Value:application/fhir+ndjson(orndjsonorapplication/ndjson)
- Key:
- Path Variables:
- Select Save
- Add a new request: "Initiate Group Export (POST)"
- Method: POST
- URL:
{{base_url}}/:tenant_id/Group/:group_id/$export - Authorization tab: Set Type to Inherit auth from parent
- Headers tab: Add required headers:
- Key:
Accept, Value:application/fhir+json - Key:
Prefer, Value:respond-async - Key:
Content-Type, Value:application/fhir+json
- Key:
- Params tab:
- Path Variables:
- Set
tenant_idto your tenant ID or{{tenant_id}}to use environment variable - Set
group_idto a specific Group ID or{{group_id}}to use environment variable
- Set
- Path Variables:
- Body tab: Select raw and JSON, then add (optional):
{
"resourceType": "Parameters",
"parameter": [
{
"name": "_type",
"valueString": "Patient,Observation,Condition"
},
{
"name": "_since",
"valueInstant": "2023-01-01T00:00:00Z"
},
{
"name": "_outputFormat",
"valueString": "application/fhir+ndjson"
}
]
}
- Select Save
Test the request:
- In the Params tab under Path Variables, set
group_idto either:- A specific Group ID (e.g.,
group-123) {{group_id}}to use your environment variable
- A specific Group ID (e.g.,
- Select Send
- Expect a 202 Accepted response
- Copy the
Content-Locationheader value - Update your
export_status_urlcollection variable with this URL
_type: Comma-separated list of resource types to export (optional)_since: Only export resources modified since this date (optional)_outputFormat: Format for exported files (optional, defaults toapplication/fhir+ndjson)- Supported formats:
application/fhir+ndjsonorndjson
- Supported formats:
_typeFilter: Apply search parameters to specific resource types (optional)
Request 5: Check Export Status
Poll the export status until completion.
- Add a new request: "Check Export Status"
- Method: GET
- URL:
{{export_status_url}} - Authorization tab: Set Type to Inherit auth from parent
- Select Save
Test the request:
- Ensure
export_status_urlcollection variable is set - Select Send
- In Progress: Expect 202 Accepted with
X-ProgressandRetry-Afterheaders - Complete: Expect 200 OK with export manifest
- Error: Expect 4xx/5xx with error details
- Use the
Retry-Afterheader value to determine when to poll again (recommended wait time in seconds) - If no
Retry-Afterheader is present, wait 1-2 minutes between polls - Large exports may take 10-30 minutes or longer
- Check the
X-Progressheader for status and completion percentage
Request 6: Download Export Files
Download the exported NDJSON files.
- Add a new request: "Download Export File"
- Method: GET
- URL:
{{export_output_url}} - Authorization tab: Set Type to Inherit auth from parent
- Select Save
Setup for file download:
- When export completes (status 200), copy a file URL from the
outputarray - Update your
export_output_urlcollection variable - The response will be NDJSON format (newline-delimited JSON)
Request 7: Cancel/Delete Export (Optional)
Cancel an in-progress export or clean up a completed export job.
- Add a new request: "Cancel/Delete Export"
- Method: DELETE
- URL:
{{export_status_url}} - Authorization tab: Set Type to Inherit auth from parent
- Select Save
Test the request:
- Cancel in-progress export: Use when you need to terminate an active export
- Clean up completed export: Use after downloading files to tell the server it can delete the export data
- Expect 202 Accepted response for cancellation or cleanup
- The export job and associated files will be removed from the server
Step 4: Complete Bulk Export Workflow
Recommended Workflow Order
- Get CapabilityStatement - Verify bulk export support
- Obtain access token - Complete client credentials flow
- Search for Groups - Find available Groups for export
- Update group_id variable - Set the Group ID to export
- Initiate Group Export - Start the export process
- Update export_status_url - Save the status polling URL
- Poll Export Status - Check status until completion
- Download Export Files - Retrieve the exported data
Export Status Responses
In Progress (202 Accepted):
HTTP/1.1 202 Accepted
X-Progress: Running (45% complete)
Retry-After: 120
(empty response body)
Other X-Progress examples:
X-Progress: Queued (0% complete)- Export is queued but not yet startedX-Progress: Running (25% complete)- Export is actively processingX-Progress: Finalizing (98% complete)- Export is in final stages (>=95%)
Complete (200 OK):
{
"transactionTime": "2024-01-15T10:30:00Z",
"request": "https://fhirtest.netsmartcloud.com/provider/system-access/v2/tenant123/Group/group456/$export",
"requiresAccessToken": true,
"output": [
{
"type": "Patient",
"url": "https://fhirtest.netsmartcloud.com/bulk-export/files/patients.ndjson"
},
{
"type": "Observation",
"url": "https://fhirtest.netsmartcloud.com/bulk-export/files/observations.ndjson"
}
],
"error": []
}
Error (4xx/5xx):
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "processing",
"diagnostics": "Export failed due to insufficient permissions"
}
]
}
Troubleshooting Common Issues
Authentication Issues
Problem: "Invalid scope" error during token request
- Solution: Verify your app registration includes bulk data export scopes
- Try
system/*.rsor specific resource scopes likesystem/Patient.rs - Ensure you're using system-level scopes, not patient-level
Problem: 403 Forbidden on export initiation
- Solution: Verify your access token has bulk export permissions
- Check if your app registration supports the
$exportoperation - Confirm the Group ID exists and is accessible
Problem: "Invalid client" error with private key JWT apps
- Solution: Postman doesn't support private key JWT authentication
- Private key JWT requires public key registration or accessible JWKS URI
- Register a separate application with client secret authentication for Postman testing
Problem: "HAPI-0333: Access denied by rule: Request is not authorized for this Tenant" error
- Solution: This error can occur due to tenant configuration OR insufficient authorization:
- Tenant Issues: Verify your
tenant_idpath variable is set correctly in each request - Tenant Issues: Ensure the tenant ID matches your CareConnect app registration
- Tenant Issues: Check that you're using the correct tenant ID for your environment (Preview vs Production)
- Authorization Issues: Verify your access token has the required scopes for the resource or operation
- Authorization Issues: Confirm your app registration includes permissions for the specific FHIR resources and operations
- Authorization Issues: Check that your requested scopes were actually granted during the authorization process
- Tenant Issues: Verify your
Export Process Issues
Problem: 404 Not Found on Group export
- Solution: Verify the Group ID exists using Group search
- Check that the Group resource supports
$exportoperation - Ensure your
group_idenvironment variable is set correctly
Problem: Export stuck in "In Progress" status
- Solution: Large exports can take 30+ minutes but should show incrementing percentages
- Check
X-Progressheader - percentage should increase over time even for long exports - If percentage remains static for extended periods, verify server hasn't encountered processing errors
- Consider using
_typeparameter to limit resource types
Problem: Empty export results
- Solution: Verify the Group contains members
- Check if
_sinceparameter is excluding all data - Confirm the Group has associated resources to export
File Download Issues
Problem: 401 Unauthorized on file download
- Solution: Ensure your access token is still valid
- Some servers require fresh tokens for file downloads
- Check if
requiresAccessTokenis true in export manifest
Problem: Large file download timeouts
- Solution: Increase Postman timeout settings
- Consider downloading files programmatically for large datasets
- Use streaming download for files over 100MB
Network and Performance Issues
Problem: Slow export processing
- Solution: Use
_typeparameter to limit resource types - Add
_sinceparameter to export only recent data - Consider smaller Group sizes for faster processing
Problem: Rate limiting errors
- Solution: Reduce polling frequency to every 2-3 minutes
- Implement exponential backoff for status checks
- Avoid concurrent export requests
Best Practices
Export Optimization
- Use selective exports: Specify
_typeparameter to export only needed resources - Incremental exports: Use
_sinceparameter for regular data synchronization - Monitor progress: Check
X-Progressheader to estimate completion time - Batch processing: Process downloaded NDJSON files in chunks
Security
- Secure file handling: Downloaded files contain PHI - handle securely
- Token management: Refresh tokens before they expire during long exports
- Access logging: Monitor who initiates and downloads bulk exports
- Data retention: Delete downloaded files after processing per your data governance policies
Performance
- Optimal polling: Use
Retry-Afterheader value for polling timing, fallback to 1-2 minutes if not present - Concurrent limits: Avoid multiple simultaneous exports per tenant
- Resource selection: Export only necessary resource types to reduce processing time
- Network considerations: Large files may require stable, high-bandwidth connections
Next Steps
Once you've mastered bulk data export, consider:
- System-level Export: Test
$exportat the system level for all data - Patient-level Export: Test
Patient/$exportfor patient-specific exports - Advanced Filtering: Use
_typeFilterfor complex export criteria - Automated Workflows: Script the complete export process for regular data synchronization
- Error Handling: Implement robust error handling and retry logic
- Data Processing: Build pipelines to process exported NDJSON files