Forward FHIR data to your own cloud storage after every successful sync. With a destination configured, Flexpa writes each patient's synced resources to your Amazon S3 bucket — so you can build a data lake, run analytics, or load records into your own systems without polling the FHIR API.
Today destinations support Amazon S3. Delivery is push-based: there's nothing to poll, and writes happen automatically as part of each sync.
Configure destinations in Portal under Destinations.
Destinations are configured separately for test and live modes. A sync only delivers to a destination whose mode matches the authorization.
The external ID is shown only once, when you create the destination. Copy it into your trust policy's sts:ExternalId condition before closing the dialog. If you lose it, delete the destination and create a new one.
sts:ExternalId
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::919310032435:role/flexpa-customer-data-delivery" }, "Action": "sts:AssumeRole", "Condition": { "StringEquals": { "sts:ExternalId": "<external-id-from-portal>" } } } ] }
The exact Flexpa role ARN and your external ID are shown in Portal when you create the destination — copy them from there rather than from this page.
Flexpa never stores long-lived credentials for your AWS account. Each delivery uses a short-lived, cross-account AWS STS AssumeRole into a role you control and can revoke at any time.
flexpa-customer-data-delivery
flexpa/
Objects are written with server-side encryption. By default Flexpa uses SSE-S3 (AES256). To use your own KMS key, provide its ARN when creating the destination and grant the role kms:GenerateDataKey on that key — both the role's IAM policy and the key's resource policy must allow it.
AES256
kms:GenerateDataKey
{ "Effect": "Allow", "Action": ["kms:GenerateDataKey", "kms:DescribeKey"], "Resource": "arn:aws:kms:REGION:ACCOUNT_ID:key/KEY_ID" }
After each successful sync, Flexpa writes a single newline-delimited JSON (NDJSON) object containing the patient's loaded FHIR resources — one resource per line. The resource set matches what $everything returns for that authorization, including resources derived from claims. Objects are written with content type application/fhir+ndjson.
$everything
application/fhir+ndjson
Keys follow a fixed, predictable layout so you can build downstream tooling against it:
flexpa/{externalId}/{consentId}/{patientAuthorizationId}/{timestamp}-{syncJobId}.ndjson
Your application's user identifier, passed through the Consent SDK. This is the primary way to join delivered objects back to your own users.
The consent ID for the session. A consent may produce multiple patient authorizations.
The patient authorization that produced this delivery.
ISO-8601 UTC timestamp of the delivery, with colons and dots normalized to -.
-
The sync job that produced the data.
Every successful sync writes a new object — the initial connection and each subsequent refresh for MULTIPLE usage authorizations. Objects are never overwritten; the timestamp and syncJobId keep each key unique. Pair destinations with webhooks to be notified the moment a sync completes.
timestamp
syncJobId
{"resourceType":"Patient","id":"...","name":[]} {"resourceType":"Coverage","id":"...","status":"active"} {"resourceType":"ExplanationOfBenefit","id":"...","status":"active"} {"resourceType":"Encounter","id":"...","class":{}}
import { createInterface } from 'node:readline'; // `stream` is the S3 object body for await (const line of createInterface({ input: stream })) { if (!line) continue; const resource = JSON.parse(line); // handle resource by resource.resourceType }