Fitnescity Health Developers
Public API documentation

Use Full API Integration—the default approach—to keep diagnostic testing search, customer identity, consent when required, ordering, questionnaires, scheduling, and results in your product. Start in Staging (Sandbox) for API Partner testing before switching hosts and credentials for live traffic.

Default test host
https://api-staging.engineeringfitnescity.com
Request access
Full API Integration

Build the complete scheduling experience in your product.

Full API Integration is the primary path for applications that own customer discovery, identity, consent, ordering, questionnaires, appointment preferences, communications, and results. Follow the sequence below and use the API Reference for complete request and response schemas.

Know your integration configuration

During onboarding, Fitnescity Health provides your initial configuration by provisioning one required customer-consent option and one physician-order option. These two decisions are independent. Follow only those configured branches. Do not infer configuration from API key names, scopes, trial requests, or select a different option per request.

As an optional check, call GET /v1/integration-configuration to confirm the current configuration at any time. Use its public mode values for newly created workflows; existing resources retain the workflow under which they were created.

Complete the selected consent branch before order creation. The selected physician-order branch begins after scheduling and determines whether you monitor Fitnescity Health, finalize a structured session, or upload an API Partner-provided PDF.

Customer consent

Fitnescity Health consent API

Fetch and render the consent bundle, create and finalize the consent session, then use the returned grant.id as consent_grant_id where specified.

Existing identity, consent, and order scopes

Outcome: A reusable consent_grant_id for prescreening and order creation.

API Partner-provided consent PDF

Create consent evidence for the customer and test type with the exact API Partner-provided PDF (PDF-only, no larger than 20 MiB). From your API Partner backend or a server-side proxy, upload those exact bytes with every returned required header and checksum; browser code must not issue the S3 PUT. The contract trusts the bytes and does not content-inspect or normalize them. Complete the upload, poll until status=accepted, then use the evidence id as partner_consent_evidence_id on an order.

read:consent_evidence and write:consent_evidence

Outcome: An accepted partner_consent_evidence_id for prescreening and order creation.

Physician order

Fitnescity Health physician-order service

Submit no physician-order evidence. After scheduling, monitor physician_order_status and appointment.form_available while Fitnescity Health completes the physician-order workflow.

Existing appointment scopes

Outcome: physician_order_status progress followed by appointment.form_available.

Structured physician-order API

After scheduling, fetch the structured bundle, create and render the immutable session in response order, collect the required physician approval, finalize with every frozen hash, then poll the session until its artifact is available.

read:physician_order_evidence and write:physician_order_evidence

Outcome: A finalized structured session whose artifact becomes available through the signed-form flow.

API Partner-provided physician-order PDF

After scheduling, create appointment-scoped physician-order evidence with the exact API Partner-provided PDF (PDF-only, no larger than 20 MiB). From your API Partner backend or a server-side proxy, upload those exact bytes with every returned required header and checksum; browser code must not issue the S3 PUT. The contract trusts the bytes and does not content-inspect or normalize them. Complete the upload, poll until status=accepted, then complete and use the physician evidence.

read:physician_order_evidence and write:physician_order_evidence

Outcome: Accepted appointment-scoped physician-order evidence.

Supported configuration combinations

All six combinations are supported. Consent completes before order creation, and the physician-order branch begins after scheduling.

Consent optionFitnescity Health physician-order serviceStructured physician-order APIAPI Partner-provided physician-order PDF
Fitnescity Health consent APISupportedSupportedSupported
API Partner-provided consent PDFSupportedSupportedSupported
At a glance

Full API Integration is the primary documentation flow. Your application owns every customer-facing step and uses Fitnescity Health APIs from discovery through scheduling, communications, and results.

Discovery
Locations, tests, and availability
Customer identity
Reusable customer identity
Customer consent
Collected via API or supplied as PDF evidence, as provisioned
Orders and questionnaires
Order creation and questionnaire submission
Scheduling and tracking
Appointment request, confirmation, physician-order document, and results

End-to-end flow

  1. 1. Discover locations, products, and availability
    GET /v1/locations → GET /v1/locations/{catalogId}/offerings/{offeringId}/products → GET /v1/locations/{catalogId}/offerings/{offeringId}/schedule

    Search by coordinates, carry catalog_id and offering_id into the selected offering, inspect product pricing and is_prescreening_required, and let the customer choose a primary appointment time plus one to three alternate availabilities from live schedule data. Each available_time is a full ISO-8601 datetime with the test location numeric offset, not always UTC; preserve it exactly. available_date is the calendar date at the test location.

  2. 2. Create or update the customer identity
    POST /v1/api-first/identities

    Send a stable external_customer_id and the customer profile. Store data.customer_identity_id from the response and reuse it for customer-consent evidence or reusable consent, applicable Calcium Score prescreening, and orders for that customer.

  3. 3. Establish the provisioned customer consent
    Fitnescity Health consent API: consent bundle → session → finalize
    API Partner-provided consent PDF: POST /v1/api-first/consent-evidence → server-side S3 upload → complete → poll

    Customer consent is required through exactly one provisioned branch. For the Fitnescity Health consent API, render and finalize the reusable consent and store grant.id. For an API Partner-provided consent PDF, use read:consent_evidence and write:consent_evidence, create PDF-only evidence no larger than 20 MiB, have your API Partner backend or server-side proxy upload the exact bytes with every required_headers value and checksum, complete the upload, poll until status=accepted, then use the evidence id as partner_consent_evidence_id before creating the order.

  4. 4. Complete Calcium Score prescreening when required
    GET /v1/tests/{testType}/prescreen-form → POST /v1/tests/{testType}/prescreen-form/submissions

    When is_prescreening_required is true, submit customer_identity_id and prescreen.pcp_consent=true plus exactly the provisioned consent source: consent_grant_id or an accepted partner_consent_evidence_id. When it is false, skip both prescreen calls. A successful prescreen returns the order_id used to confirm the order.

  5. 5. Create the order
    POST /v1/orders

    Send customer_identity_id or external_customer_id and the required customer profile. Supply exactly the provisioned consent source: consent_grant_id for the Fitnescity Health consent API or an accepted partner_consent_evidence_id for an API Partner-provided consent PDF. Store the returned order and appointment identifiers.

  6. 6. Complete the appointment questionnaire
    GET /v1/tests/{testType}/scheduling-questionnaire → GET/POST /v1/appointments/{appointmentId}/scheduling-questionnaire

    Use the test-type route to preview the current questionnaire. After order creation, fetch the appointment-scoped definition and submit its questionnaire_definition_id and content_hash with answers and acknowledgements keyed by the returned item ids. Successful submissions are finalized synchronously with outcome.status accepted, blocked, or physician_review_required; outcome.code is nullable and forward-compatible.

  7. 7. Request scheduling
    POST /v1/appointments/{appointmentId}/schedule

    Send selected_appointment_date and one to three alternate_availabilities as the full ISO-8601 datetimes and numeric offsets returned by schedule availability. They are not always UTC. This is a request-then-confirm flow: pending_confirmation means the request was accepted and is awaiting confirmation, not that the appointment is confirmed.

  8. 8. Establish the provisioned physician order
    Fitnescity Health physician-order service: monitor the appointment
    Structured physician-order API: bundle → session → finalize → poll
    API Partner-provided physician-order PDF: POST /v1/api-first/appointments/{appointmentId}/physician-order-evidence → server-side S3 upload → complete → poll

    After scheduling, follow exactly the provisioned physician-order branch. For the Fitnescity Health physician-order service, submit no physician evidence and monitor physician_order_status plus appointment.form_available. For the Structured physician-order API, create, render, and finalize the frozen session, then poll for its artifact. For an API Partner-provided physician-order PDF, upload appointment-scoped evidence with read:physician_order_evidence and write:physician_order_evidence and wait for status=accepted.

  9. 9. Track confirmation, forms, communications, and results
    GET /v1/appointments and GET /v1/appointments/{appointmentId}/check-in-link
    GET /v1/appointments/{appointmentId}/signed-form

    Read appointment status and physician_order_status through appointment endpoints or webhooks. After the appointment is confirmed, request the opaque check-in link server-side and place it in API Partner-owned email or SMS. The view-only page shows the customer, appointment time, test, facility/location, and appointment ID; the link expires six hours after appointment start, is not included in appointment resources or webhooks, and must not be logged or parsed. Request a new link after rescheduling; cancellation, refund, and no-show invalidate it. Subscribe to appointment.form_available; when it arrives, call the signed-form endpoint to obtain a temporary download URL. Use the shared email and text/SMS communication model and poll GET /v1/results for completed results.

Fitnescity Health consent API only

Render consent exactly as returned

Fetch GET /v1/api-first/consent-bundles/{testType} and render each item in content.decisions using its returned label, detail link, detail format, and detail content. Do not rewrite the supplied customer-facing text.

Pin the returned template version and content hash when creating the consent session. Send them as consent_template_version_id and content_hash, then submit a decision map keyed by the ids returned in the bundle.

If the customer restarts an open consent session, call POST /v1/api-first/consent-sessions/{sessionId}/abandon before creating a replacement session.

Submit the pinned questionnaire

After order creation, fetch the appointment-scoped questionnaire. Submit its questionnaire_definition_id and content_hash; do not substitute a newer test-type definition.

Questionnaire acknowledgements may return copy_format: "html" and formatted content in copy. Sanitize that HTML with an allowlist before rendering it. Submit boolean maps keyed by the returned ids, such as {scheduling_terms: true}; do not submit the copy itself.

A successful submission is finalized synchronously; it does not return a pending submission that finalizes later. The final outcome.status is accepted, blocked, or physician_review_required. outcome.code is nullable and forward-compatible, so accept unknown future non-null codes and branch primarily on status.

Current non-null examples are CALST_PREGNANCY_INELIGIBLE, CALST_UNDER_40_INELIGIBLE, CALST_OVER_75_INELIGIBLE, DEXA_PREGNANCY_INELIGIBLE, DEXA_RECENT_BARIUM_INELIGIBLE, DEXA_UNDER_16_INELIGIBLE, VO2_UNDER_16_INELIGIBLE, and VO2_TWO_OR_MORE_RISK_ANSWERS. These examples may expand without a version change; do not implement a closed outcome-code enum.

The same Idempotency-Key and same payload replays the original response. The same Idempotency-Key with a different payload returns IDEMPOTENCY_CONFLICT. A new Idempotency-Key cannot replace an immutable finalized submission and returns QUESTIONNAIRE_ALREADY_SUBMITTED.

Fitnescity Health consent API only

Consent signature metadata

POST /v1/api-first/consent-sessions/{sessionId}/finalize requires signer_role: "self", the customer-entered typed_name, electronic_signature_attestation: true, customer_ip, and customer_user_agent.

Capture the originating IPv4 or IPv6 address and User-Agent from the customer-facing request to your product. Do not send your API Partner's server IP. Missing or invalid values return HTTP 400.

API Partner-provided PDF lifecycle

This upload lifecycle applies only to the API Partner-provided consent PDF and API Partner-provided physician-order PDF branches. Use it for PDF evidence; it does not apply to API-rendered sessions.

  1. 1. Calculate the document byte length, lowercase hexadecimal SHA-256, and base64 SHA-256 before creating evidence. API Partner evidence is PDF-only and limited to 20 MiB. Declare the file name, content type, byte length, and hash. The exact API Partner-provided PDF bytes are contract-trusted: contents are not content-inspected or normalized.
  2. 2. Retain data.id and the returned upload session. From your API Partner backend or a server-side proxy, PUT the exact bytes to data.upload_session.url and include every required_headers entry exactly, including x-amz-checksum-sha256. The API gateway does not receive the document bytes, and browser code must not issue this S3 PUT. Upload the exact bytes used for the declared checksum; do not inspect, transform, or normalize them.
  3. 3. If the server-side PUT returns 403 or 410, retain the evidence ID and POST the matching /upload-sessions endpoint with a stable idempotency key to obtain a replacement, then retry the PUT. Do not create another evidence record.
  4. 4. Call the matching upload-session completion endpoint with the same lowercase hexadecimal sha256. Then GET the evidence resource until data.status=accepted. Never attach evidence that is still awaiting upload or processing. If completion returns 429 or 503, retry the same completion request with the same evidence ID, upload-session ID, hash, and stable idempotency key. If completion reports an expired upload session, try the replacement-session flow and read the evidence state. When its status is abandoned, start a new evidence record with a new create idempotency key instead of retrying the terminal record.

Structured physician-order API

After scheduling, fetch GET /v1/api-first/appointments/{appointmentId}/physician-order-bundle and save its template, content, context, and API Partner attestation metadata. Create the immutable presentation with POST /v1/api-first/appointments/{appointmentId}/physician-order-sessions.

  1. 1. Render every presentation section, row, statement, and required acknowledgement verbatim and in response order. You may style the surrounding interface, but do not rewrite, omit, reorder, or reconstruct the physician-facing content.
  2. 2. Capture both required physician acknowledgements: order_acknowledgement and electronic_signature_attestation. The returned partner_attestation is API Partner-system certification metadata; it is not another physician checkbox.
  3. 3. Finalize with POST /v1/api-first/physician-order-sessions/{sessionId}/finalize, echoing the frozen template_version_id, content_hash, context_hash, presentation_hash, and the exact partner_attestation version and text hash.
  4. 4. Respect the 202 Accepted, Location, and Retry-After response. Poll GET /v1/api-first/physician-order-sessions/{sessionId} until the artifact is available, then retrieve GET /v1/appointments/{appointmentId}/signed-form.
  5. 5. If provider or order data changes, create a replacement using replaces_session_id, or abandon the open session with POST /v1/api-first/physician-order-sessions/{sessionId}/abandon. Do not edit a frozen session or fall back to the PDF or Fitnescity Health physician-order service branch.

This branch uses read:physician_order_evidence and write:physician_order_evidence and requires explicit onboarding enablement and certification.

Scheduling and form availability

A successful schedule request returns pending_confirmation. Continue reading the appointment or consuming appointment webhooks until its status becomes confirmed.

When physician_order_status is pending, continue monitoring the appointment. When appointment.form_available arrives, call GET /v1/appointments/{appointmentId}/signed-form to obtain the temporary form URL. If the form is not ready, handle PHYSICIAN_ORDER_PENDING and retry only as directed by the response.

When the key is provisioned for an API Partner-provided physician-order PDF, create and finish the appointment-scoped physician-order evidence lifecycle after scheduling and wait for its evidence status=accepted. When it uses the Fitnescity Health physician-order service, do not call physician-order evidence endpoints.

Appointment lifecycle updates can be received through webhooks or retrieved by polling appointment reads. The shared communications model covers appointment emails and text/SMS notifications, and completed results are available through GET /v1/results.

Idempotency and recovery

Use one stable Idempotency-Key for each logical write. After a timeout or connection loss, retry the exact same Idempotency-Key and payload. Reusing a key with a different payload returns IDEMPOTENCY_CONFLICT.

If the original request is still being processed, the API returns 202 Accepted with data.code=IDEMPOTENCY_IN_PROGRESS, data.retry_after_seconds, and the Retry-After header. Wait, then retry the same request.

HTTP/1.1 202 Accepted
Retry-After: 7

{
  "code": 202,
  "data": {
    "status": "in_progress",
    "code": "IDEMPOTENCY_IN_PROGRESS",
    "retry_after_seconds": 7
  },
  "error": null
}

Actionable errors

Full API Integration failures use the standard error envelope. Branch on the stable machine-readable value in error.details.code, not the human-readable message. The 202 outcome above places its identifier in data.code.

  • CONSENT_GRANT_REQUIRED

    This API key is provisioned for the Fitnescity Health consent API. Finalize reusable consent and send the returned grant.id as consent_grant_id on the original logical request.

  • CUSTOMER_CONSENT_NOT_REQUIRED

    Do not retry the reusable-consent request. This API key is not provisioned for the Fitnescity Health consent API; use the provisioned API Partner-provided consent PDF lifecycle.

  • CONSENT_SESSION_OPEN

    Resume the open session or abandon it before starting a replacement.

  • QUESTIONNAIRE_VERSION_MISMATCH

    Fetch the appointment-scoped definition again and submit its id and content hash.

  • QUESTIONNAIRE_VALIDATION_FAILED

    Correct the answers or acknowledgements identified in the validation details.

  • QUESTIONNAIRE_ALREADY_SUBMITTED

    The appointment already has an immutable finalized submission. A new Idempotency-Key cannot replace it; continue with the original result or contact support if the appointment itself must be corrected.

  • SLOT_UNAVAILABLE

    Refresh availability and ask the customer to select another time.

  • IDEMPOTENCY_CONFLICT

    Use the original payload with that key, or use a new key for a new logical request.

Prescreen rendering guidance

Treat GET /v1/tests/{testType}/prescreen-form as a render contract for prescreen-required tests. The goal is to let your app render the correct form without reverse-engineering labels or grouping from validation rules. Use the returned copy as the source for recommended labels, section titles, categories, consent language, and the primary CTA. The pcp_consent field is independent of reusable consent managed by Fitnescity Health.

  • Render fields and sections in the returned array order.
  • Use copy.sections for labels and section headings, copy.consent.label for the checkbox text, and submit_button_text for the primary CTA.
  • For control=date_parts, render separate month, day, and year inputs but submit dob in MM/DD/YYYY format.
  • For control=boolean_radio, render the returned options in the provided order.
  • Display the returned copy verbatim unless you have an approved reason to override the wording.
Example Form Definition Response
{
  "code": 200,
  "data": {
    "required_fields": [
      "dob",
      "family_history_cardiovascular_disease",
      "high_cholesterol_or_hypertension",
      "diabetes",
      "bmi_higher_than_25",
      "sedentary_lifestyle",
      "smoker",
      "symptoms_heart_disease",
      "pregnant",
      "diagnosed_heart_disease",
      "pcp_name",
      "pcp_phone",
      "pcp_consent"
    ],
    "copy": {
      "sections": [
        {
          "id": "dob",
          "title": null,
          "fields": [
            {
              "name": "dob",
              "label": "What is your date of birth?",
              "control": "date_parts",
              "required": true
            }
          ]
        },
        {
          "id": "risk_factors",
          "title": "Risk Factors",
          "fields": [
            {
              "name": "family_history_cardiovascular_disease",
              "label": "Does heart disease run in your family?",
              "control": "boolean_radio",
              "options": ["Yes", "No"]
            }
          ]
        },
        {
          "id": "symptoms",
          "title": "Symptoms & Medical History"
        }
      ],
      "consent": {
        "field": "pcp_consent",
        "label": "By providing my Primary Care Physician's information..."
      },
      "submit_button_text": "Answer all questions to continue"
    }
  },
  "error": null
}

Build the sequence from your selected modules

Set $BASE and $API_KEY for your environment. Always persist data.customer_identity_id as $CUSTOMER_IDENTITY_ID. Run the shared start, your one consent module, the shared order and scheduling module, and your one physician-order module.

Open API reference

Shared start: discovery and identity

curl -X GET "$BASE/v1/locations?lat=40.7128&lng=-74.0060&test_types=DEXA,RMR&page=1&page_size=5" \
  -H "x-api-key: $API_KEY"
curl -X GET "$BASE/v1/locations/$CATALOG_ID/offerings/$OFFERING_ID/products" \
  -H "x-api-key: $API_KEY"
curl -X GET "$BASE/v1/locations/$CATALOG_ID/offerings/$OFFERING_ID/schedule" \
  -H "x-api-key: $API_KEY"
# POST /v1/api-first/identities
curl -X POST "$BASE/v1/api-first/identities" \
  -H "x-api-key: $API_KEY" \
  -H "Idempotency-Key: identity-member-001" \
  -H "Content-Type: application/json" \
  -d '{"external_customer_id":"member-001","first_name":"Avery","last_name":"Jordan","email":"avery.jordan@example.com","phone":"+12125551234","date_of_birth":"1975-01-01","sex":"female","address":{"address_line_1":"350 5th Ave","city":"New York","state":"NY","postal_code":"10001"}}'

Consent module: Fitnescity Health consent API

curl -X GET "$BASE/v1/api-first/consent-bundles/$TEST_TYPE" \
  -H "x-api-key: $API_KEY"
# POST /v1/api-first/consent-sessions
curl -X POST "$BASE/v1/api-first/consent-sessions" \
  -H "x-api-key: $API_KEY" \
  -H "Idempotency-Key: consent-session-member-001-calst" \
  -H "Content-Type: application/json" \
  -d "{\"customer_identity_id\":\"$CUSTOMER_IDENTITY_ID\",\"canonical_test_type\":\"CALST\",\"consent_template_version_id\":\"$CONSENT_TEMPLATE_VERSION_ID\",\"content_hash\":\"$CONSENT_CONTENT_HASH\"}"
curl -X POST "$BASE/v1/api-first/consent-sessions/$SESSION_ID/finalize" \
  -H "x-api-key: $API_KEY" \
  -H "Idempotency-Key: consent-finalize-$SESSION_ID" \
  -H "Content-Type: application/json" \
  -d '{"typed_name":"Avery Jordan","signer_role":"self","electronic_signature_attestation":true,"decisions":{"testing_consent":true,"hipaa_authorization":true,"data_use":true,"arbitration":true},"customer_ip":"203.0.113.10","customer_user_agent":"Mozilla/5.0"}'

Consent module: API Partner-provided consent PDF

# Requires read:consent_evidence and write:consent_evidence
curl -X POST "$BASE/v1/api-first/consent-evidence" \
  -H "x-api-key: $API_KEY" \
  -H "Idempotency-Key: consent-evidence-member-001-calst" \
  -H "Content-Type: application/json" \
  -d "{\"customer_identity_id\":\"$CUSTOMER_IDENTITY_ID\",\"canonical_test_type\":\"CALST\",\"signer_name\":\"Avery Jordan\",\"signed_at\":\"2026-09-08T14:00:00Z\",\"document\":{\"file_name\":\"consent.pdf\",\"content_type\":\"application/pdf\",\"content_length\":248731,\"sha256\":\"$EVIDENCE_SHA256_HEX\"}}"
# From your API Partner backend or server-side proxy: save data.id, data.upload_session.id, data.upload_session.url, and every returned required_headers value.
# Never issue this S3 PUT from browser code.
curl -X PUT "$EVIDENCE_UPLOAD_URL" \
  -H "Content-Type: application/pdf" \
  -H "x-amz-checksum-sha256: $EVIDENCE_CHECKSUM_BASE64" \
  -H "x-amz-tagging: $EVIDENCE_TAGGING" \
  --upload-file "$EVIDENCE_FILE"
curl -X POST "$BASE/v1/api-first/consent-evidence/$PARTNER_CONSENT_EVIDENCE_ID/upload-sessions/$EVIDENCE_UPLOAD_SESSION_ID/complete" \
  -H "x-api-key: $API_KEY" \
  -H "Idempotency-Key: complete-consent-evidence-$PARTNER_CONSENT_EVIDENCE_ID" \
  -H "Content-Type: application/json" \
  -d "{\"sha256\":\"$EVIDENCE_SHA256_HEX\"}"
# Poll until data.status=accepted before using the evidence on an order.
curl -X GET "$BASE/v1/api-first/consent-evidence/$PARTNER_CONSENT_EVIDENCE_ID" \
  -H "x-api-key: $API_KEY"

Shared order, questionnaire, and scheduling

Choose the prescreen and order payload that carries your consent branch's identifier; run discovery, identity, questionnaire, and scheduling only once.

curl -X GET "$BASE/v1/tests/$TEST_TYPE/prescreen-form" \
  -H "x-api-key: $API_KEY"
curl -X POST "$BASE/v1/tests/$TEST_TYPE/prescreen-form/submissions" \
  -H "x-api-key: $API_KEY" \
  -H "Idempotency-Key: prescreen-$EXTERNAL_CUSTOMER_ID" \
  -H "Content-Type: application/json" \
  -d "{\"catalog_id\":\"$CATALOG_ID\",\"offering_id\":\"$OFFERING_ID\",\"product_id\":\"$PRODUCT_ID\",\"test_id\":\"$TEST_ID\",\"customer_identity_id\":\"$CUSTOMER_IDENTITY_ID\",\"customer\":{\"first_name\":\"Avery\",\"last_name\":\"Jordan\",\"email\":\"avery.jordan@example.com\",\"phone_number\":\"+12125551234\",\"date_of_birth\":\"1975-01-01\",\"sex\":\"female\",\"height\":70,\"weight\":165,\"address\":{\"address_line_1\":\"350 5th Ave\",\"city\":\"New York\",\"state\":\"NY\",\"postal_code\":\"10001\"}},\"partner_consent_evidence_id\":\"$PARTNER_CONSENT_EVIDENCE_ID\",\"prescreen\":{\"dob\":\"01/01/1975\",\"family_history_cardiovascular_disease\":true,\"high_cholesterol_or_hypertension\":false,\"diabetes\":false,\"bmi_higher_than_25\":false,\"sedentary_lifestyle\":false,\"smoker\":false,\"symptoms_heart_disease\":false,\"pregnant\":false,\"diagnosed_heart_disease\":false,\"pcp_name\":\"Dr Smith\",\"pcp_phone\":\"2125551234\",\"pcp_consent\":true}}"
curl -X POST "$BASE/v1/tests/$TEST_TYPE/prescreen-form/submissions" \
  -H "x-api-key: $API_KEY" \
  -H "Idempotency-Key: prescreen-$EXTERNAL_CUSTOMER_ID" \
  -H "Content-Type: application/json" \
  -d "{\"catalog_id\":\"$CATALOG_ID\",\"offering_id\":\"$OFFERING_ID\",\"product_id\":\"$PRODUCT_ID\",\"test_id\":\"$TEST_ID\",\"customer_identity_id\":\"$CUSTOMER_IDENTITY_ID\",\"customer\":{\"first_name\":\"Avery\",\"last_name\":\"Jordan\",\"email\":\"avery.jordan@example.com\",\"phone_number\":\"+12125551234\",\"date_of_birth\":\"1975-01-01\",\"sex\":\"female\",\"height\":70,\"weight\":165,\"address\":{\"address_line_1\":\"350 5th Ave\",\"city\":\"New York\",\"state\":\"NY\",\"postal_code\":\"10001\"}},\"consent_grant_id\":\"$CONSENT_GRANT_ID\",\"prescreen\":{\"dob\":\"01/01/1975\",\"family_history_cardiovascular_disease\":true,\"high_cholesterol_or_hypertension\":false,\"diabetes\":false,\"bmi_higher_than_25\":false,\"sedentary_lifestyle\":false,\"smoker\":false,\"symptoms_heart_disease\":false,\"pregnant\":false,\"diagnosed_heart_disease\":false,\"pcp_name\":\"Dr Smith\",\"pcp_phone\":\"2125551234\",\"pcp_consent\":true}}"
# Save data.order_id from the successful Calcium Score prescreen response:
# export PRESCREEN_ORDER_ID="<data.order_id>"
# Products with is_prescreening_required=false skip the prescreen calls and omit order_id.
curl -X POST "$BASE/v1/orders" \
  -H "x-api-key: $API_KEY" \
  -H "Idempotency-Key: order-member-001-calst" \
  -H "Content-Type: application/json" \
  -d "{\"catalog_id\":\"$CATALOG_ID\",\"offering_id\":\"$OFFERING_ID\",\"product_id\":\"$PRODUCT_ID\",\"test_id\":\"$TEST_ID\",\"customer_identity_id\":\"$CUSTOMER_IDENTITY_ID\",\"customer\":{\"first_name\":\"Avery\",\"last_name\":\"Jordan\",\"email\":\"avery.jordan@example.com\",\"phone_number\":\"+12125551234\",\"date_of_birth\":\"1975-01-01\",\"sex\":\"female\",\"height\":70,\"weight\":165,\"address\":{\"address_line_1\":\"350 5th Ave\",\"city\":\"New York\",\"state\":\"NY\",\"postal_code\":\"10001\"}},\"partner_consent_evidence_id\":\"$PARTNER_CONSENT_EVIDENCE_ID\",\"external_payment_reference\":\"partner-pay-001\",\"order_id\":\"$PRESCREEN_ORDER_ID\"}"
curl -X POST "$BASE/v1/orders" \
  -H "x-api-key: $API_KEY" \
  -H "Idempotency-Key: order-member-001-calst" \
  -H "Content-Type: application/json" \
  -d "{\"catalog_id\":\"$CATALOG_ID\",\"offering_id\":\"$OFFERING_ID\",\"product_id\":\"$PRODUCT_ID\",\"test_id\":\"$TEST_ID\",\"customer_identity_id\":\"$CUSTOMER_IDENTITY_ID\",\"customer\":{\"first_name\":\"Avery\",\"last_name\":\"Jordan\",\"email\":\"avery.jordan@example.com\",\"phone_number\":\"+12125551234\",\"date_of_birth\":\"1975-01-01\",\"sex\":\"female\",\"height\":70,\"weight\":165,\"address\":{\"address_line_1\":\"350 5th Ave\",\"city\":\"New York\",\"state\":\"NY\",\"postal_code\":\"10001\"}},\"consent_grant_id\":\"$CONSENT_GRANT_ID\",\"external_payment_reference\":\"partner-pay-001\",\"order_id\":\"$PRESCREEN_ORDER_ID\"}"
curl -X GET "$BASE/v1/appointments/$APPOINTMENT_ID/scheduling-questionnaire" \
  -H "x-api-key: $API_KEY"
curl -X POST "$BASE/v1/appointments/$APPOINTMENT_ID/scheduling-questionnaire" \
  -H "x-api-key: $API_KEY" \
  -H "Idempotency-Key: questionnaire-$APPOINTMENT_ID" \
  -H "Content-Type: application/json" \
  -d '{"questionnaire_definition_id":"$QUESTIONNAIRE_DEFINITION_ID","content_hash":"$QUESTIONNAIRE_CONTENT_HASH","answers":{"pregnancy_notice":true},"acknowledgements":{"scheduling_terms":true}}'
curl -X POST "$BASE/v1/appointments/$APPOINTMENT_ID/schedule" \
  -H "x-api-key: $API_KEY" \
  -H "Idempotency-Key: schedule-$APPOINTMENT_ID" \
  -H "Content-Type: application/json" \
  -d '{"selected_appointment_date":"2026-09-10T10:00:00-04:00","alternate_availabilities":["2026-09-11T09:00:00-04:00"]}'
# Only after an appointment read or webhook reports status=confirmed. Keep this request on your server.
curl -X GET "$BASE/v1/appointments/$APPOINTMENT_ID/check-in-link" \
  -H "x-api-key: $API_KEY"
curl -X GET "$BASE/v1/appointments?order_id=$ORDER_ID&limit=25" \
  -H "x-api-key: $API_KEY"
curl -X GET "$BASE/v1/appointments/$APPOINTMENT_ID/signed-form" \
  -H "x-api-key: $API_KEY"
curl -X GET "$BASE/v1/results?order_id=$ORDER_ID&limit=25&offset=0" \
  -H "x-api-key: $API_KEY"

Physician module: Fitnescity Health physician-order service

# Submit no physician evidence for the Fitnescity Health physician-order service. Monitor the appointment instead.
curl -X GET "$BASE/v1/appointments?order_id=$ORDER_ID&limit=25" \
  -H "x-api-key: $API_KEY"
# After appointment.form_available, retrieve the signed physician-order form.
curl -X GET "$BASE/v1/appointments/$APPOINTMENT_ID/signed-form" \
  -H "x-api-key: $API_KEY"

Physician module: Structured physician-order API

# Requires read:physician_order_evidence and write:physician_order_evidence.
# Save data.template.id, data.template.content_hash, data.context_hash, and the exact data.partner_attestation version and text_hash.
curl -X GET "$BASE/v1/api-first/appointments/$APPOINTMENT_ID/physician-order-bundle" \
  -H "x-api-key: $API_KEY"
# The returned session is frozen. Render every presentation section, row, statement, and required acknowledgement verbatim and in response order.
curl -X POST "$BASE/v1/api-first/appointments/$APPOINTMENT_ID/physician-order-sessions" \
  -H "x-api-key: $API_KEY" \
  -H "Idempotency-Key: physician-order-session-$APPOINTMENT_ID" \
  -H "Content-Type: application/json" \
  -d '{"template_version_id":"$PHYSICIAN_ORDER_TEMPLATE_VERSION_ID","content_hash":"$PHYSICIAN_ORDER_CONTENT_HASH","context_hash":"$PHYSICIAN_ORDER_CONTEXT_HASH","order_date":"2026-09-18","physician":{"full_name":"Dr. Ada Lovelace","credentials":"MD","npi":"1234567893","license_state":"NY","license_number":"NY-12345","ordering_entity":"Example Medical Group","contact":{"type":"provider","address":{"address_line_1":"123 Madison Ave","city":"New York","state":"NY","postal_code":"10016"},"phone":"+1-212-555-0100","fax":"+1-212-555-0101"}},"approval_method":"electronic_signature","workflow_type":"partner_electronic"}'
# Echo every frozen hash and the exact partner_attestation metadata pinned in the session. The two booleans are the required physician acknowledgements.
curl -X POST "$BASE/v1/api-first/physician-order-sessions/$PHYSICIAN_ORDER_SESSION_ID/finalize" \
  -H "x-api-key: $API_KEY" \
  -H "Idempotency-Key: finalize-physician-order-$PHYSICIAN_ORDER_SESSION_ID" \
  -H "Content-Type: application/json" \
  -d '{"template_version_id":"$PHYSICIAN_ORDER_TEMPLATE_VERSION_ID","content_hash":"$PHYSICIAN_ORDER_CONTENT_HASH","context_hash":"$PHYSICIAN_ORDER_CONTEXT_HASH","presentation_hash":"$PHYSICIAN_ORDER_PRESENTATION_HASH","approval":{"approved_at":"2026-09-18T14:00:00Z","order_acknowledgement":true,"electronic_signature_attestation":true,"typed_name":"Dr. Ada Lovelace","ip_address":"203.0.113.10","user_agent":"Mozilla/5.0","device_metadata":{"platform":"web"},"session_reference":"$PHYSICIAN_ORDER_SESSION_ID","external_reference_id":"partner-approval-001"},"partner_attestation":{"accepted":true,"version":"$PARTNER_ATTESTATION_VERSION","text_hash":"$PARTNER_ATTESTATION_TEXT_HASH"}}'
# Finalize returns 202 Accepted with Location and Retry-After. Poll that session resource until data.artifact is available.
curl -X GET "$BASE/v1/api-first/physician-order-sessions/$PHYSICIAN_ORDER_SESSION_ID" \
  -H "x-api-key: $API_KEY"
# If provider or order data changes, abandon an open session or create a replacement with replaces_session_id. Never edit a frozen session.
curl -X POST "$BASE/v1/api-first/physician-order-sessions/$PHYSICIAN_ORDER_SESSION_ID/abandon" \
  -H "x-api-key: $API_KEY" \
  -H "Idempotency-Key: abandon-physician-order-$PHYSICIAN_ORDER_SESSION_ID" \
  -H "Content-Type: application/json" \
  -d '{"reason":"Provider or order data changed before approval."}'
# After appointment.form_available, retrieve the rendered signed form.
curl -X GET "$BASE/v1/appointments/$APPOINTMENT_ID/signed-form" \
  -H "x-api-key: $API_KEY"

Physician module: API Partner-provided physician-order PDF

# Requires read:physician_order_evidence and write:physician_order_evidence
curl -X POST "$BASE/v1/api-first/appointments/$APPOINTMENT_ID/physician-order-evidence" \
  -H "x-api-key: $API_KEY" \
  -H "Idempotency-Key: physician-evidence-$APPOINTMENT_ID" \
  -H "Content-Type: application/json" \
  -d '{"physician_full_name":"Dr. Example","npi":"1234567893","order_date":"2026-09-08","document":{"file_name":"physician-order.pdf","content_type":"application/pdf","content_length":248731,"sha256":"$EVIDENCE_SHA256_HEX"}}'
# From your API Partner backend or server-side proxy: save data.id, data.upload_session.id, data.upload_session.url, and every returned required_headers value.
# Never issue this S3 PUT from browser code.
curl -X PUT "$EVIDENCE_UPLOAD_URL" \
  -H "Content-Type: application/pdf" \
  -H "x-amz-checksum-sha256: $EVIDENCE_CHECKSUM_BASE64" \
  -H "x-amz-tagging: $EVIDENCE_TAGGING" \
  --upload-file "$EVIDENCE_FILE"
curl -X POST "$BASE/v1/api-first/physician-order-evidence/$PHYSICIAN_ORDER_EVIDENCE_ID/upload-sessions/$EVIDENCE_UPLOAD_SESSION_ID/complete" \
  -H "x-api-key: $API_KEY" \
  -H "Idempotency-Key: complete-physician-evidence-$PHYSICIAN_ORDER_EVIDENCE_ID" \
  -H "Content-Type: application/json" \
  -d '{"sha256":"$EVIDENCE_SHA256_HEX"}'
# Poll until data.status=accepted.
curl -X GET "$BASE/v1/api-first/physician-order-evidence/$PHYSICIAN_ORDER_EVIDENCE_ID" \
  -H "x-api-key: $API_KEY"