Flexpa
Developer PortalGet SandboxTry it yourself

All docs

Introduction

  • API Keys
  • Modes

Quickstart setup

  • Environment variables
  • Running
  • Your first consent

How it works

  • Consent flow
  • Retrieving records
  • Advanced

Next steps

    Quickstart

    #Introduction

    Build a working Flexpa integration using the Quickstart app.

    You'll need API keys from the Developer Portal. Flexpa operates in Test and Live modes—we'll start in Test mode.

    #API Keys

    • Publishable Key

      A client-side key that is okay to share

    • Secret Key

      A server-side key that you must keep private

    The OAuth PKCE flow used in this quickstart only requires your Publishable Key.

    #Modes

    • Test

      Test credentials and synthetic data

    • Live

      Launch your integration with real patient data

    Flexpa Quickstart

    Try it yourself

    Go through a Patient Access API flow yourself! See exactly what patients will see

    Try it yourself →

    #Quickstart setup

    Make sure you have Node.js and npm installed before following along.

    Let's start by cloning the Quickstart repository from GitHub.

    The repository includes a .env.example file. You will copy this template file and use it as a starting point for your own .env file.

    Clone and copy template

    # Clone the repository
    git clone https://github.com/flexpa/quickstart.git
    cd quickstart
    
    # Copy the environment variables template
    cp .env.example .env
    

    #Environment variables

    Open .env in a text editor.

    Add your Publishable Key for Test mode from the Developer Portal → API Keys.

    The redirect URI is where users return after authorization. For local development, use http://localhost:3000/callback. Register this URI in the Developer Portal.

    You'll also need to generate a random secret for session signing. Your own app will have its own authentication.

    Update the .env file

    NEXT_PUBLIC_FLEXPA_PUBLISHABLE_KEY=pk_test_...
    NEXT_PUBLIC_REDIRECT_URI=http://localhost:3000/callback
    

    Generate a random session key

    # Generate a random secret key and add it to the .env file
    echo "SESSION_SECRET=$(openssl rand -base64 32)" >> .env
    

    #Running

    The Flexpa Quickstart is a Node.js app built with Next.js.

    To get it started, install dependencies with npm install and start the app with npm run dev.

    The application will be running at http://localhost:3000.

    Quickstart landing page

    Install dependencies

    # Install dependencies
    npm install
    
    # Start the development server
    npm run dev
    
    # Go to http://localhost:3000
    

    #Your first consent

    A Patient Authorization represents consent to share healthcare records. Each authorization links a person, your application, and their healthcare records.

    Flexpa supports a 3-in-1 network for patient access to health insurance payers, healthcare providers, and national TEFCA networks.

    Now that you have Quickstart running, click Launch Consent to start the OAuth flow. You'll be redirected to Flexpa where you can select a health plan.

    Select Foo Medical and log in with the test credentials:

    Test credentials

    # Username
    patient10@flexpa.com
    
    # Password
    examplepatient
    

    Foo Medical is a fake sandbox we use to test the integration and it provides synthetic records. Learn more about test mode.

    After completing consent, you'll be redirected back to Quickstart. You have created your first Patient Authorization! You can now make API calls by using the buttons in Quickstart. In the next section, we'll explain what actually happened and how Quickstart works.

    Flexpa consent flow in action

    #How it works

    Quickstart demonstrates the OAuth 2.0 PKCE flow:

    1. Authorization - Redirect users to Flexpa for consent
    2. Code Exchange - Exchange the authorization code for an access token
    3. API Calls - Use the access token to query FHIR resources
    OAuth PKCE authorization flow

    #Consent flow

    The OAuth 2.0 PKCE (Proof Key for Code Exchange) flow securely authorizes your application without exposing secrets on the client.

    The Quickstart uses a Next.js server action to handle PKCE generation server-side:

    Building the authorization URL

    'use server'
    
    import FlexpaClient from '@flexpa/node-sdk'
    import { setCodeVerifier } from './session'
    
    export async function startOAuthFlow() {
      // Generate PKCE credentials on the server
      const codeVerifier = FlexpaClient.generateCodeVerifier()
      const codeChallenge = FlexpaClient.generateCodeChallenge(codeVerifier)
    
      // Store codeVerifier securely in server-side session
      await setCodeVerifier(codeVerifier)
    
      // Build the authorization URL
      const authUrl = FlexpaClient.buildAuthorizationUrl({
        publishableKey: process.env.NEXT_PUBLIC_FLEXPA_PUBLISHABLE_KEY,
        redirectUri: process.env.NEXT_PUBLIC_REDIRECT_URI,
        codeChallenge,
        externalId: crypto.randomUUID(),
      })
    
      return authUrl
    }
    

    After a patient completes their consent on Flexpa, they are redirected back to your redirectUri with an authorization code parameter.

    Your callback handler should:

    1. Extract the code from the URL query parameters
    2. Retrieve the stored code_verifier
    3. Exchange them for an access token

    Exchanging the code for an access token

    import FlexpaClient from '@flexpa/node-sdk'
    
    // Get the authorization code from the callback URL
    const code = new URL(request.url).searchParams.get('code')
    
    // Retrieve the code verifier you stored earlier
    const codeVerifier = await getStoredCodeVerifier()
    
    // Exchange for access token
    const client = await FlexpaClient.fromAuthorizationCode(
      code,
      codeVerifier,
      process.env.NEXT_PUBLIC_REDIRECT_URI,
      process.env.NEXT_PUBLIC_FLEXPA_PUBLISHABLE_KEY
    )
    
    // Store the access token securely
    const accessToken = client.getAccessToken()
    

    The access_token grants access to a Patient Authorization's records. Store it securely—you'll need it for all FHIR API requests.

    #Retrieving records

    Now that we've covered the OAuth flow, let's explore how to make API calls.

    As an example, let's take a look at some of the requests made on the dashboard at http://localhost:3000/dashboard.

    The first request, $everything, is to /fhir/Patient/$PATIENT_ID/$everything - which retrieves all of the available data for a patient. The request uses the access_token like all consented records requests.

    In this code we see how the Quickstart makes this call using Node SDK but you can make it with any HTTP client:

    src/app/api/fhir/Patient/$everything/route.ts

    import { NextResponse } from 'next/server'
    import FlexpaClient from '@flexpa/node-sdk'
    import { getSession } from '@/lib/session';
    
    export async function GET() {
      const session = await getSession();
    
      if (!session?.accessToken) {
        return NextResponse.json(
          { error: 'Unauthorized' },
          { status: 401 }
        )
      }
    
      const client = FlexpaClient.fromBearerToken(session.accessToken);
      const everything = await client.$everything();
    
      return NextResponse.json(everything)
    }
    

    Flexpa API supports reading and searching a variety of FHIR Resources. The Quickstart demonstrates a few common requests:

    • Patient $everything
    • Patient Read
    • Explanation of Benefit Search
    • Coverage Search

    When making FHIR API requests, you may encounter 429 status codes while Flexpa syncs data from the payer. This happens during the initial sync period, which typically lasts less than 1 minute. Implement retry logic to handle these, or use the Node SDK which retries automatically.

    How to query for records

    #Advanced

    The FHIR responses above contain rich healthcare data, but they're deeply nested and complex to parse. For most applications, you want specific fields—not raw FHIR structures.

    The ViewDefinition/$run endpoint lets you define exactly what data you need and receive it as simple rows and columns. No FHIR parsing required.

    Here's an example that extracts a summary from ExplanationOfBenefit resources (claims data):

    src/app/api/fhir/claims-summary/route.ts

    import { NextResponse } from 'next/server'
    import { getSession } from '@/app/lib/session';
    
    const claimsView = {
      resourceType: 'ViewDefinition',
      name: 'claims_summary',
      status: 'active',
      resource: 'ExplanationOfBenefit',
      select: [{
        column: [
          { name: 'claim_id', path: 'id' },
          { name: 'type', path: "type.coding.where(system='http://terminology.hl7.org/CodeSystem/claim-type').code.first()" },
          { name: 'service_date', path: 'billablePeriod.start' },
          { name: 'provider', path: 'provider.display' },
          { name: 'total_billed', path: "total.where(category.coding.code='submitted').amount.value.first()" },
          { name: 'you_paid', path: "total.where(category.coding.code='memberliability').amount.value.first()" },
          { name: 'diagnosis_codes', path: 'diagnosis.diagnosisCodeableConcept.coding.code.distinct()', collection: true },
        ]
      }]
    };
    
    export async function GET() {
      const session = await getSession();
      if (!session?.accessToken) {
        return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
      }
    
      const response = await fetch('https://api.flexpa.com/fhir/ViewDefinition/$run', {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${session.accessToken}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          resourceType: 'Parameters',
          parameter: [{ name: 'viewResource', resource: claimsView }]
        })
      });
    
      return NextResponse.json(await response.json());
    }
    

    Instead of parsing nested FHIR structures, you get clean, flat data:

    Response

    {
      "rows": [
        {
          "claim_id": "eob-12345",
          "type": "professional",
          "service_date": "2024-03-15",
          "provider": "Dr. Sarah Chen",
          "total_billed": 250.00,
          "you_paid": 35.00,
          "diagnosis_codes": ["Z00.00", "J06.9"]
        }
      ],
      "resourceCount": 1
    }
    

    Need help building ViewDefinitions? We're FHIR experts. Tell us what data your application needs, and we can help you craft a ViewDefinition that extracts exactly that. Reach out to your Flexpa contact or our support team.

    Learn more about ViewDefinitions in our parsing guide or see the API reference.

    #Next steps

    Want to see an example of how to integrate Flexpa into an existing application? Check out our integration tutorial!

    Congratulations, you have completed the Flexpa Quickstart! There are a few directions you can go in now:

    • Learn more about ViewDefinitions and FHIRPath expressions
    • Try accessing your own health claims records on MyFlexpa
    • Learn how to add Medplum to the Quickstart
    • Schedule a demo to discuss your integration needs
    Status TwitterGitHub

    © 2026 Flexpa. All rights reserved.