# Squire Developers
> Integrate Squire consultation notes, dictation and patient intake into your medical software with the Squire JavaScript SDK, widgets and REST API.
Generated from https://developers.squire.eu. Each section below is one documentation page.
---
Source: https://developers.squire.eu/
# Squire developer documentation
Add consultation notes, dictation and patient intake to your medical software. Integrate through the JavaScript SDK, drop in a widget, or call the REST API directly.
- [Get started](https://developers.squire.eu/get-started)
- [API reference](https://app.squire.eu/api/v1/external/schema/redoc/)
## Products
- [Consultation](https://developers.squire.eu/consultation): Record a consultation and receive a structured clinical note or SOAP note.
- [Dictation](https://developers.squire.eu/dictation): Stream speech to a live transcript, with finalized and in-progress text.
- [Medical coding](https://developers.squire.eu/medical-coding): Encode clinical text into SNOMED CT, with the position and negation of every concept found.
- [Intake](https://developers.squire.eu/intake): Let patients complete an intake questionnaire before their visit and show the summary in your application.
- Online consultation (Early access): Have Squire join a video consultation and capture it, with nothing recording on either device.
- Follow-up (Early access): Turn the actions agreed during a consultation into a follow-up list.
## Ways to integrate
Every product is reachable through the same three routes. Most integrations mix them: the SDK for recording, a widget for intake configuration, the API for server-side reads.
- [JavaScript SDK](https://developers.squire.eu/get-started/sdk-installation): Full control over the interface. Handles audio capture, streaming and session state in your client.
- [Widgets](https://developers.squire.eu/widgets): Complete flows mounted with one SDK call, themed to match your application.
- [REST API](https://app.squire.eu/api/v1/external/schema/redoc/): Server-to-server access to sessions, summaries and usage, without a browser.
## Quickstart
Three steps take you from an API key to a first consultation summary.
- [1. Create an API key](https://developers.squire.eu/reference/portal#managing-api-keys): Generate a staging or production key in the Portal.
- [2. Request an access token](https://developers.squire.eu/get-started/authentication): Exchange the API key for a short-lived user token on your server.
- [3. Install the SDK](https://developers.squire.eu/get-started/sdk-installation): Add the SDK to your client and start your first recording.
## Resources
- [API reference](https://app.squire.eu/api/v1/external/schema/redoc/)
- [SDK changelog](https://developers.squire.eu/reference/sdk-changelog)
- [Output format](https://developers.squire.eu/consultation/output)
- [Languages](https://developers.squire.eu/reference/languages)
- [FHIR](https://developers.squire.eu/reference/fhir)
- [Microphones](https://developers.squire.eu/reference/microphones)
- [API status](https://status.squire.eu/)
- [Support](https://developers.squire.eu/reference/support)
---
Source: https://developers.squire.eu/get-started
# Get started
Squire integrates into medical software, so healthcare providers use it without leaving their existing workflow. Every integration starts with the same two steps: obtain an access token, then install the SDK.
## Setup
- [Authentication](https://developers.squire.eu/get-started/authentication): Exchange your API key for a user access token on your server.
- [SDK installation](https://developers.squire.eu/get-started/sdk-installation): Install the SDK from the private npm registry in your client.
## Choose a product
- [Consultation](https://developers.squire.eu/consultation): Capture consultation audio and generate structured clinical output.
- [Dictation](https://developers.squire.eu/dictation): Stream speech to a live transcript, with finalized and in-progress text.
- [Medical coding](https://developers.squire.eu/medical-coding): Encode clinical text into SNOMED CT from your server.
- [Intake](https://developers.squire.eu/intake): Schedule patient intake questionnaires and show summaries in your application.
## Choose how to integrate
The SDK, the widgets and the REST API are three routes to the same products, not three products. Pick per feature; most integrations use more than one.
- [JavaScript SDK](https://developers.squire.eu/get-started/sdk-installation): Build your own interface. The SDK handles audio capture, streaming and session state.
- [Widgets](https://developers.squire.eu/widgets): Embed ready-made, themeable UI components with one method call.
- [REST API](https://app.squire.eu/api/v1/external/schema/redoc/): Read and write from your server, without a browser.
---
Source: https://developers.squire.eu/get-started/authentication
# Authentication
Using the Squire SDK requires having a valid access token. An access token can be requested from the Squire API using your Squire API key. If you do not have a Squire API key yet, [create one via the Portal](https://developers.squire.eu/reference/portal#managing-api-keys).
## Authentication flow
The SDK uses token-based authentication to securely identify users per integration. It goes as follows:
1. Your EHR client requests an access token from your backend
2. Your EHR backend requests an access token from Squire API using your private API key
3. The Squire API validates the request and returns an access token
4. Your EHR backend provides the access token to your client application
5. Your EHR client initializes the Squire SDK using the access token
```mermaid
sequenceDiagram
participant EHR Client
participant EHR Backend
participant Squire API
participant Squire SDK
EHR Client->>EHR Backend: Request access token
EHR Backend->>Squire API: Request access token (using API key)
Note over EHR Backend,Squire API: Authentication request includes
EHR and user context
Squire API-->>EHR Backend: Return access token
EHR Backend->>EHR Client: Provide access token
EHR Client->>Squire SDK: Initialize with access token
Note over EHR Client,Squire SDK: SDK boots and authenticates
using the access token
```
## Requesting an access token
> **Note**
>
> Request access tokens from your server. Never ship your API key to the client.
To request an access token, make a POST request to `https://api.squire.eu/api/v1/external/token/` with your API key in the header and the user ID in the request body.
### Request specification
Request an access token by calling the Squire API from your preferred programming language.
| Header | Required | Description |
|--------|----------|-------------|
| `X-Api-Key` | Yes | Your Squire API key for authentication |
| `Content-Type` | Yes | Must be set to `application/json` |
The request body is a JSON object with the following keys:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `user_id` | string | Yes | Unique identifier of the user in your system |
| `first_name` | string | Yes | First name of the user |
| `last_name` | string | Yes | Last name of the user |
| `organisation` | string | Yes | The name of the organisation (the practice, hospital, or similar) where the user works |
| `organisation_id` | string | No | Unique identifier of the organisation (practice or hospital department) in your system. Acts as the data scope: all users sharing the same `organisation_id` see the same intake configurations and session data. |
| `healthcare_provider_identification_number` | string | No | The healthcare provider identification number of the user (e.g. RIZIV number in Belgium). Separators between the numbers or characters are allowed. |
| `email` | string | No | Email address of the user in your system |
| `healthcare_provider_type` | string | No | The specific type of healthcare provider |
**Healthcare provider types**
| Name | id |
|------|------|
| Anesthesiologist | `anesthesiologist` |
| Cardiologist | `cardiologist` |
| Dermatologist | `dermatologist` |
| Dietitian | `dietitian` |
| Emergency Doctor | `emergency_doctor` |
| Endocrinologist | `endocrinologist` |
| Gastroenterologist | `gastroenterologist` |
| General Practitioner | `general_practitioner` |
| Geriatrician | `geriatrician` |
| Gynecologist | `gynecologist` |
| Hematologist | `hematologist` |
| Home Nurse | `home_nurse` |
| Hospital Nurse | `hospital_nurse` |
| Infectiologist | `infectiologist` |
| Medical Social Worker | `medical_social_worker` |
| Nephrologist | `nephrologist` |
| Neurologist | `neurologist` |
| Nursing Home Nurse | `nursing_home_nurse` |
| Oncologist | `oncologist` |
| Ophthalmologist | `ophthalmologist` |
| Orthopedic | `orthopedic` |
| Otorhinolaryngologist | `otorhinolaryngologist` |
| Pathologist | `pathologist` |
| Pediatrician | `pediatrician` |
| Physiotherapist | `physiotherapist` |
| Practice Nurse | `practice_nurse` |
| Psychiatrist | `psychiatrist` |
| Psychologist | `psychologist` |
| Pulmonologist | `pulmonologist` |
| Radiologist | `radiologist` |
| Rheumatologist | `rheumatologist` |
| Secretariat Staff | `secretariat_staff` |
| Speech-Language Pathologist | `speech_language_pathologist` |
| Stomatologist | `stomatologist` |
| Surgeon | `surgeon` |
| Urologist | `urologist` |
#### Example request
```bash
curl -X POST "https://api.squire.eu/api/v1/external/token/" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"user_id": "doctor123", "first_name": "doctor", "last_name": "123", "organisation": "practice_name", "healthcare_provider_identification_number": "12345678901", "email": "doctor@123.com", "healthcare_provider_type": "general_practitioner"}'
```
### Response specification
A successful request returns an access token and its expiration date:
```json
{
"token": "eyJhbGciOiJIUzI1NiIs...",
"expires_at": "2025-01-01T14:30:00Z"
}
```
| Field | Type | Description |
|-------|------|-------------|
| `token` | string | JWT access token for SDK initialization |
| `expires_at` | string | ISO 8601 formatted expiration timestamp |
For examples in other languages and the full list of possible status codes, see the [token endpoint API reference](https://app.squire.eu/api/v1/external/docs/#tag/tokens/POST/api/v1/external/token/).
## Next steps
Now that you have acquired a valid access token, continue with either [SDK installation](https://developers.squire.eu/get-started/sdk-installation) or the [widget overview](https://developers.squire.eu/widgets).
---
Source: https://developers.squire.eu/get-started/sdk-installation
# Installation
Squire ships a JavaScript SDK for web-based clients. It has no framework dependency, so it works with React, Angular, Vue or plain JavaScript.
### Configure the npm registry
The SDK is published to a private npm registry. Add the registry and your token to the `.npmrc` file in your project, or create the file if it does not exist:
```ini filename=".npmrc"
@squirehealth:registry=https://pkg.squire.eu/npm/
//pkg.squire.eu/npm/:_authToken=YOUR_TOKEN
```
Replace `YOUR_TOKEN` with the package repository token from the [Portal](https://developers.squire.eu/reference/portal).
### Install the SDK
**npm**
```bash
npm install @squirehealth/sdk
```
**pnpm**
```bash
pnpm add @squirehealth/sdk
```
**yarn**
```bash
yarn add @squirehealth/sdk
```
The package includes TypeScript type definitions.
## Next steps
- [Recording with the SDK](https://developers.squire.eu/consultation/sdk): Initialize the SDK and build your own recording interface.
- [Widgets](https://developers.squire.eu/widgets): Mount a ready-made recording, microphone test or intake widget.
---
Source: https://developers.squire.eu/consultation
# Consultation
Consultation records what is said during a visit and turns it into structured clinical output. Integrate it with the SDK when you want full control over the interface, or mount the widget when you want a complete recording experience out of the box.
## Integration paths
- [Recording with the SDK](https://developers.squire.eu/consultation/sdk): Build your own recording interface and stream audio through the Squire SDK.
- [Consultation widget](https://developers.squire.eu/consultation/widget): Embed a complete recording interface with microphone selection, controls and summary generation.
## Guides
- [Templates](https://developers.squire.eu/consultation/templates): Define the structure of the consultation output.
- [Output](https://developers.squire.eu/consultation/output): The JSON summary returned by the SDK and widget.
- [Multi-SOAP](https://developers.squire.eu/consultation/multi-soap): Split one consultation into several SOAP notes, or merge them.
- [Product usage](https://developers.squire.eu/consultation/product-usage): Read the remaining allowance per product for a user.
- [Terms & Conditions](https://developers.squire.eu/consultation/terms-and-conditions): Handle end-user acceptance before recording.
- [Error handling](https://developers.squire.eu/consultation/error-handling): Session states, retries and API errors.
---
Source: https://developers.squire.eu/consultation/sdk
# Recording with the SDK
Once a way is set up to obtain a valid access token, follow these steps to add consultation recording to your application:
## Initialize the SDK
> **Note**
>
> Initialize the SDK in the client, using the access token obtained from your server.
Once you have obtained a valid access token via your backend, initialize the Squire SDK on the client instantiating the `Squire` class with the access token. The `outputLanguage` option should be set to the language in which the consultation report will be generated. (See [Languages](https://developers.squire.eu/reference/languages) for supported languages.)
```js
import Squire from '@squirehealth/sdk';
// Your logic to fetch an access token goes here ...
const squire = new Squire({
token: 'REPLACE_WITH_ACCESS_TOKEN',
outputLanguage: 'nl',
});
```
This step must only be done once. We recommend to do this after users log into your system, or on opening of the EHR client if they are already authenticated.
Once initialized, the SDK can be used.
## Recording Flow
### Get microphones
Get the list of available microphones. This is useful to show the user which microphone they can use for the consultation.
```js
const audioInputs = await squire.getAudioInputs();
```
Calling this function also will request microphone permissions, if not yet granted.
The function returns a list of microphone devices, each with the following properties:
- `deviceId`: The unique identifier of the microphone device.
- `label`: The display name of the microphone device.
- `isDefault`: A boolean indicating whether this is the default selected microphone.
### Register event listeners
Register a callback function that will receive the consultation report data when the user finishes:
```js
squire.on('summary-ready', (summary) => {
if (summary.data === null) {
// No report content. `summary.report_status` says why.
return;
}
// `summary` contains the structured report data as generated by Squire
// your logic to store consultation report data in the EHR goes here
});
```
> **Warning**
>
> Check `summary.data` before reading it. A consultation can end without any report content, in which
> case `data` is `null` and `report_status` says why. See [Report status](https://developers.squire.eu/consultation/output#report-status).
For information about the structure of the summary, see the [output documentation](output).
### Start a consultation
Start a consultation by calling the `startRecording` method. This will start a new consultation in the background and begin streaming audio. This method returns a promise that resolves with the `Consultation` object.
```js
const consultation = await squire.startRecording();
```
By default, the same input language as the output language will be used. If you want to set a different input language, you can do so by passing the `inputLanguage` option when starting the consultation. (See [Languages](https://developers.squire.eu/reference/languages) for supported languages.)
Likewise, the default audio input is the system default microphone. If you want to use a different microphone, you can pass the `audioInput` option of the desired microphone.
```js
const consultation = await squire.startRecording({
inputLanguage: 'fr',
audioInput: audioInputs[0],
templateId: 'specialist_general_api'
});
```
The `templateId` option is used to specify the template that will be used for the output summary. Supported: `specialist_general_api`, `soap_new_complaint_api`.
You can optionally set report length per consultation with `writingStyle`: `brief`, `balanced`, or `detailed`. If you omit it, the user's default report length is used, as in earlier SDK versions.
```js
const consultation = await squire.startRecording({
inputLanguage: 'nl',
templateId: 'soap_new_complaint_api',
writingStyle: 'brief',
});
```
That default is the authenticated user's report length preference stored for their account. To read it (for example to pre-fill your UI):
```js
const defaultStyle = await squire.getDefaultWritingStyle();
```
To update it from your integration (for example so later calls without `writingStyle` use the new preference):
```js
await squire.setDefaultWritingStyle('balanced');
```
### Stop a consultation
Stop a consultation by calling the `stopRecording` method. This will stop the recording and close the consultation.
```js
squire.stopRecording();
```
Once the consultation has finished processing, the `summary-ready` event will be emitted with the consultation data. That last event ends the recording whether or not a report was produced: if there is no report content, its `data` is `null` and `report_status` says why. See [Report status](https://developers.squire.eu/consultation/output#report-status).
## Pausing and resuming a consultation
You can temporarily pause and later resume an ongoing consultation. This is useful if you want to temporarily stop recording without ending the consultation.
To pause recording:
```js
squire.pauseRecording();
```
To resume recording:
```js
squire.resumeRecording();
```
## Retrieve a consultation summary
You can retrieve the full consultation summary at any time. This is useful if you need to fetch the summary data on-demand.
Using the `Consultation` object returned by `startRecording`:
```js
const summary = await consultation.getSummary();
```
If you no longer hold the original `Consultation` object (e.g. after a page refresh), you can create one from a consultation ID using `squire.consultation()`:
```js
const consultation = squire.consultation('consultation-uuid');
const summary = await consultation.getSummary();
```
`getSummary()` resolves for a consultation with no report as well: it returns the consultation's metadata with `data` set to `null`, and `report_status` explaining why. Check `summary.data` before iterating over it. See [Report status](https://developers.squire.eu/consultation/output#report-status).
For information about the structure of the summary, see the [output documentation](output).
> **Note**
>
> For advanced SOAP functionality including splitting and merging consultations, see the [Multi-SOAP](https://developers.squire.eu/consultation/multi-soap) documentation.
> **Note**
>
> For real-time transcription workflows, see the [Dictation](https://developers.squire.eu/dictation) documentation.
## Product usage
To fetch the remaining allowance per product for the signed-in user, see [Product usage](https://developers.squire.eu/consultation/product-usage).
## Error handling
For details on error handling, including built-in and explicit error handling strategies, as well as log level configuration, see the [Error Handling](https://developers.squire.eu/consultation/error-handling) page.
---
Source: https://developers.squire.eu/consultation/widget
# Consultation Widget
The Consultation widget is a pre-built UI component that provides a complete recording interface for capturing and processing medical consultations. This widget includes microphone selection, recording controls with pause/resume functionality, real-time audio visualization, and automatic summary generation.
_Figure: The Consultation widget. Consultation widget showing microphone selection and recording controls_
## Features
- Microphone selection from the available audio input devices
- Recording controls to start, pause, resume and stop
- Real-time waveform visualization with audio level detection
- Theming of colors, border radius and font
- Configurable interface and input language
- Template support for structured output
- Events for the widget lifecycle and results
## Widget state flow
The widget manages multiple states to handle different scenarios and user interactions. Understanding this flow helps you integrate the widget effectively and handle events appropriately.
**View microphone permission flow**
The widget first requests microphone access before any recording can begin.
```mermaid
stateDiagram-v2
[*] --> CheckPermission: Widget Loaded
CheckPermission --> Pending: Permission Unknown
CheckPermission --> Denied: Permission Denied
CheckPermission --> Granted: Permission Granted
Pending --> Requesting: Click Enable Microphone
Denied --> Requesting: Click Try Again
Requesting --> Granted: User Allows
Requesting --> Denied: User Denies
Granted --> [*]: Ready to Record
```
**View AI consultation flow**
Once microphone permission is granted, users can start an AI consultation session.
```mermaid
stateDiagram-v2
[*] --> Ready: Permission Granted
Ready --> Recording: Start consultation
state "Recording" as Recording
state "Paused" as Paused
state "Processing" as Processing
state "Completed" as Completed
Recording --> Paused: Click Pause
Paused --> Recording: Click Resume
Recording --> Processing: Click Stop
Processing --> Completed: Summary Ready
Completed --> Ready: New Consult
Recording --> Error: Error Occurs
Processing --> Error: Error Occurs
state "Error" as Error
Error --> Ready: Auto Recovery
```
**View dictation flow**
Alternatively, users can start a dictation session for simple transcription.
```mermaid
stateDiagram-v2
[*] --> Ready: Permission Granted
Ready --> Recording: Start Dictation
state "Recording" as Recording
state "Paused" as Paused
state "Processing" as Processing
state "Completed" as Completed
Recording --> Paused: Click Pause
Paused --> Recording: Click Resume
Recording --> Processing: Click Stop
Processing --> Completed: Transcript Final
Completed --> Ready: New Dictation
Recording --> Error: Error Occurs
Processing --> Error: Error Occurs
state "Error" as Error
Error --> Ready: Auto Recovery
```
## Basic usage
### HTML setup
First, create a container element where the widget will be mounted:
```html
```
### Initialize the SDK
Then, initialize the Squire SDK. See [the usage documentation](https://developers.squire.eu/consultation/sdk#initialize-the-sdk) for more detail.
```javascript
const squire = new Squire({
token: 'REPLACE_WITH_ACCESS_TOKEN',
outputLanguage: 'en',
});
```
### Mount the widget
After initializing the Squire SDK, mount the widget using the `mountWidget` method:
```javascript
const widget = squire.mountWidget('#squire-ai-consult', 'ai-consult');
```
The method takes three parameters:
1. **Container selector**: A string CSS selector of the container element
2. **Widget name**: The string `'ai-consult'`
3. **Configuration object** (optional): Customize behavior and appearance
## Configuration options
The widget supports extensive customization through configuration options. You can pass these options as the third parameter to `mountWidget`:
```javascript
const widget = squire.mountWidget('#squire-ai-consult', 'ai-consult', {
locale: 'en',
templateId: 'YOUR_TEMPLATE_ID',
theme: {
colorPrimary: '#337ab7',
colorDark: '#212529',
colorLight: '#236aa7',
colorLightest: '#f8f9fa',
borderRadius: '0.25rem',
font: 'Roboto'
}
});
```
### Configuration properties
```ts
/**
* Configuration options for the Consultation widget.
*/
type AiConsultationConfig = {
/**
* Language code for the widget interface and input language.
*
* Supported values: 'en', 'nl', 'fr', 'de'
*
* @default Uses outputLanguage from SDK initialization
*/
locale?: string;
/**
* Template ID to use for structured output generation.
*
* Templates define the structure and format of the consultation summary.
* See the templates documentation for available options.
*
* @default undefined (uses default template)
*/
templateId?: string;
/**
* Theme configuration for customizing the widget's appearance.
*/
theme?: ThemeConfig;
};
/**
* Theme configuration object for customizing the widget's appearance.
*/
type ThemeConfig = {
/**
* Primary color for buttons and accents.
*
* @default '#539DD6'
*/
colorPrimary?: string;
/**
* Dark color for text and borders.
*
* @default '#0C2639'
*/
colorDark?: string;
/**
* Light accent color for hover states.
*
* @default '#7CC1F6'
*/
colorLight?: string;
/**
* Lightest color for backgrounds.
*
* @default '#E1F1FD'
*/
colorLightest?: string;
/**
* Border radius for UI elements.
*
* Affects buttons, controls, and the audio visualizer bars.
*
* @default '0.5rem'
*/
borderRadius?: string;
/**
* Font family for the widget.
*
* All Google Fonts are supported and loaded from https://fonts.google.com/
*
* @default 'system-ui, sans-serif'
*/
font?: string;
};
export default AiConsultationConfig;
```
### Locale
The `locale` property sets both the widget interface language and the input language for speech recognition. Supported values:
| Language code | Language |
|-------------|----------|
| `en` | English |
| `nl` | Dutch |
| `fr` | French |
| `de` | German |
If no `locale` is provided, the widget uses the `outputLanguage` from SDK initialization.
### Template ID
The `templateId` property specifies which template to use for generating the consultation summary. Templates define the structure and sections of the output. See the [templates documentation](https://developers.squire.eu/consultation/templates) for available options.
## Events
The widget emits events to notify your application of important actions. Listen for events using the `on` method:
```javascript
widget.on('loaded', () => {
console.log('Widget is ready');
});
widget.on('summary-ready', (summary) => {
console.log('Consultation summary:', summary);
});
```
### Available events
```ts
/**
* Event types emitted by the Consultation widget.
*/
type AiConsultationEvents = {
/**
* Emitted when the widget has fully loaded and is ready for use.
*
* @example
* widget.on('loaded', () => {
* console.log('Widget ready');
* });
*/
loaded: () => void;
/**
* Emitted when a consultation summary is ready.
*
* This event fires multiple times:
* - First with intermediate results (report_status: 'intermediate')
* - Finally with the complete summary (report_status: 'final')
*
* @param summary - The consultation summary object
* @param summary.report_status - Status: 'intermediate' or 'final'
*
* @example
* widget.on('summary-ready', (summary) => {
* if (summary.report_status === 'final') {
* console.log('Final summary:', summary);
* // Save to database, display to user, etc.
* }
* });
*/
'summary-ready': (summary: ConsultationSummary) => void;
};
/**
* Consultation summary object structure.
*/
type ConsultationSummary = {
/**
* Status of the report.
*
* - 'intermediate': Partial results while processing continues
* - 'final': Complete and final consultation summary
*/
report_status: 'intermediate' | 'final';
/**
* Unique identifier for the consultation.
*/
id: string;
/**
* Additional summary data based on the template used.
* Structure depends on your template configuration.
*/
[key: string]: any;
};
export default AiConsultationEvents;
```
## Complete example
```html
Consultation Widget
```
---
Source: https://developers.squire.eu/consultation/templates
# Templates
Define the structure of consultation outputs by creating templates. This lets you map Squire's output directly to your system's data format.
## Creating templates
### Using the API (server side)
Create and store templates via the [Template API](https://app.squire.eu/api/v1/external/schema/redoc/#tag/templates) on the server.
A custom template can set `content_format` to `plain` (the default) or `markdown` for rich text. See [Content format](https://developers.squire.eu/consultation/templates#content-format).
Once created, you can use the template in your recording sessions:
```typescript
await squire.startRecording({ templateId: 'your-template-id' });
```
### Using the SDK (client side)
The template schema can also be passed when calling `startRecording`. This will create the template if it doesn't exist yet, or update it if it does.
```typescript
await squire.startRecording({
templateId: 'your-template-id',
templateSchema: schema,
});
```
When passing a `templateSchema`, you should also provide a `templateId`. This can be any string (for example, your own internal ID). The `templateId` will be shown in the Portal, which helps with identification and debugging.
### Content format
A template is either plain text or rich text, and the reports generated from it take the same format. Rich text is currently written as Markdown; more rich text formats may be added later. Set it with `contentFormat` alongside the `templateSchema`:
```typescript
await squire.startRecording({
templateId: 'your-template-id',
templateSchema: schema,
contentFormat: 'markdown',
});
```
| Value | Meaning |
|-------|---------|
| `plain` | The template's text fields, and the report generated from it, are plain text. |
| `markdown` | Rich text: the template's text fields use Markdown for formatting, and the report's text fields come back as Markdown. |
- A new template defaults to `plain`.
- When you omit `contentFormat`, an existing template keeps the format it already has, so a template that was switched to rich text elsewhere (for example in the app) is not flipped back.
- `contentFormat` only applies to a `templateSchema`. Passing it without one throws `contentFormat requires a templateSchema`, since there is no template to set it on.
Every summary reports the format it was generated in as `content_format`. Read it to decide how to render the text. See [Content format](https://developers.squire.eu/consultation/output#content-format).
> **Note**
>
> In a Markdown template, a backslash marks a character as literal text rather than formatting (for
> example `\*` or `1\.`). The report keeps those backslashes, so render it with a Markdown renderer rather
> than displaying the raw text.
## Template schema
Templates consist of fields. Each field has an `id`, `name`, and a `valueType` defining the data type for the expected value.
Optionally, a description can be provided for each field to improve understanding and accuracy of each field.
Nested fields can be defined using the `fields` property. This is useful for creating fields where values are related to each other.
### Field Properties
| Property | Required | Description |
|----------|----------|-------------|
| `id` | Yes | Unique identifier (e.g., 'symptoms_start') |
| `name` | Yes | Display name (e.g., 'Onset Date') |
| `valueType` | Yes | One of: `text`, `options`, `date`, `boolean` |
| `valueOptions` | For `options` type | Array of `{value: string, description?: string}` |
| `description` | No | Additional context or unit information. A hint about the content, not a structure the value must follow |
| `textPattern` | No | Only for `text` fields. A pattern the value must follow. See [Text pattern](https://developers.squire.eu/consultation/templates#text-pattern) |
| `fields` | No | Array of nested fields |
### Field Types
| Type | Usage |
|------|--------|
| `text` | Free text output |
| `options` | Fixed choices, as defined in the `valueOptions` property |
| `date` | Date value, in the `YYYY-MM-DD` format |
| `boolean` | `true` or `false` output |
### Schema Example
```typescript
const schema = {
fields: [
{
id: 'symptoms_start',
name: 'Onset Date',
valueType: 'date',
description: 'First occurrence of symptoms'
},
{
id: 'severity',
name: 'Severity',
valueType: 'options',
valueOptions: [
{ value: 'mild', description: 'Mild' },
{ value: 'moderate', description: 'Moderate' },
{ value: 'severe', description: 'Severe' }
]
},
{
id: 'has_allergies',
name: 'Has allergies?',
valueType: 'boolean',
description: 'Does the patient have any allergies?',
fields: [
{
id: 'allergy_details',
name: 'Allergy details',
valueType: 'text',
description: 'If yes, specify the allergens (e.g., pollen, peanuts, medications)'
}
]
}
]
};
```
### Text pattern
A `text` field can carry a `textPattern`: a fill-in-the-blanks template the generated value must follow. Where `description` is only a hint about what belongs in the field, a `textPattern` fixes the structure of the value itself.
The pattern works with these rules:
- **Plain text stays as written.** Headings, labels, punctuation and line breaks are copied into the value unchanged.
- **Square brackets mark fields to fill in.** `[reason for referral]` is replaced with the matching content from the consultation.
- **Round brackets right after a field give styling details** for that field: `[medication](bulleted list, include dosage)`.
```typescript
{
id: 'referral_letter',
name: 'Referral letter',
valueType: 'text',
description: 'Letter to the specialist the patient is referred to',
textPattern: `Dear colleague,
I am referring [patient name](first name only) for [reason for referral](one sentence).
Relevant history: [medical history](short bulleted list)
Current medication: [medication](bulleted list, include dosage)
Kind regards,`,
}
```
Which generates a value such as:
```text
Dear colleague,
I am referring Anna for persistent lower back pain radiating to the left leg.
Relevant history:
- Hypertension
- Lumbar disc herniation in 2019
Current medication:
- Amlodipine 5 mg, once daily
Kind regards,
```
`textPattern` is only allowed on `text` fields: a template that sets it on an `options`, `date` or `boolean` field is rejected. In a [rich text template](https://developers.squire.eu/consultation/templates#content-format), the pattern can use Markdown, and the formatting is carried into the report.
## Processing Results
The `summary` object in the `summary-ready` event contains the values as extracted by Squire. The SDK provides a `Template` utility class to help you work with these results.
### Using the Template utility
The `Template` class offers convenient methods for working with template results:
```typescript
squire.on('summary-ready', (summary) => {
if (summary.data) {
// Create a Template instance from the API response
const template = Squire.Template.fromResponse(summary.data);
// Get all field values as a Record
const values = template.getFieldValues();
console.log(values['severity']);
// Or get a specific field by id
const severityField = template.getFieldById('severity');
console.log(severityField?.value);
}
});
```
The `Template` class provides these main methods:
| Method | Description |
|--------|-------------|
| `fromResponse(response)` | Creates a Template instance from an API response |
| `getFieldValues()` | Returns a flat map of all field IDs and their values |
| `getFieldById(id)` | Searches for a specific field by ID, including nested fields |
---
Source: https://developers.squire.eu/consultation/output
# Data output
The Squire SDK returns structured consultation data in JSON format. The data is structured according to the template used for the consultation.
**View an example of a SOAP note in Dutch**
```json
{
"id": "yoEh163Y1cHih2S1",
"input_language": "nl",
"output_language": "nl",
"start_datetime": "2025-01-01T12:00:00Z",
"end_datetime": "2025-01-01T12:30:00Z",
"report_status": "final",
"generation_result": "success",
"content_format": "plain",
"data": [
{
"episode": "Consultation",
"template": "soap_new_complaint_api",
"sections": [
{
"section_id": "subjective",
"fields": {
"summary": {}
}
},
{
"section_id": "objective",
"fields": {
"summary": {},
"vital_signs": []
}
},
{
"section_id": "assessment",
"fields": {
"medical_coding": []
}
},
{
"section_id": "plan",
"fields": {
"summary": {},
"prescribed_medication": [],
"sick_note": {}
}
}
]
}
]
}
```
**View an example of a specialist note with free text in Dutch**
```json
{
"id": "qIe6WDaV1dN5f6y2",
"input_language": "nl",
"output_language": "nl",
"start_datetime": "2025-10-02T08:59:13.128Z",
"end_datetime": "2025-10-02T09:00:20.405Z",
"report_status": "final",
"generation_result": "success",
"content_format": "plain",
"data": [
{
"episode": "Consultation",
"template": "specialist_general_free_text_api",
"sections": [
{
"section_id": "free_text",
"fields": {
"summary": {
"text": "Reden van het bezoek:\n---------------------\nDiarree sinds drie dagen.\n\nAnamnese:\n---------\nSinds drie dagen frequente, waterige en losse ontlasting. Gemiddeld zes tot zeven keer per dag naar het toilet. Klachten van pijn in de onderbuik. Diarree heeft invloed op dagelijkse activiteiten.\n\nKlinisch onderzoek:\n-------------------\n-\n\nDiagnose:\n---------\nAcute diarree, waarschijnlijk infectieus van aard.\n\nBehandelingsplan:\n-----------------\n-\n\nConclusie:\n----------\nAcute diarree met frequente, waterige ontlasting en onderbuikspijn sinds drie dagen."
}
}
}
]
}
]
}
```
**View an example of a dictation**
```json
{
"id": "j3hc7l6TgeKL15GQ",
"input_language": "nl",
"output_language": "en",
"start_datetime": "2025-10-10T14:33:49.646709+00:00",
"end_datetime": null,
"report_status": "intermediate",
"generation_result": "success",
"content_format": "plain",
"data": [
{
"episode": "Dictation",
"template": "dictation_api",
"sections": [
{
"section_id": "transcription",
"fields": {
"fixed": {
"text": "Patient complains of a sore throat."
},
"ongoing": {
"text": "And a headache for the last two"
}
}
}
]
}
]
}
```
**View an example of a split SOAP note with multiple episodes**
```json
{
"id": "8lbv3SJ7ObqOWh11",
"input_language": "nl",
"output_language": "nl",
"start_datetime": "2026-01-30T09:58:01.276040+00:00",
"end_datetime": "2026-01-30T09:58:29.360123+00:00",
"report_status": "final",
"generation_result": "success",
"generation_result_message": null,
"content_format": "plain",
"data": [
{
"episode": "Episode 1",
"template": "soap_new_complaint_api",
"sections": [
{
"section_id": "subjective",
"fields": {
"summary": {
"text": "Koorts, 39°C. Ziektebriefje gevraagd."
}
}
},
{
"section_id": "objective",
"fields": {
"summary": {
"text": "Lichaamstemperatuur 39°C."
},
"vital_signs": [
{
"vital_sign_id": "body_temperature",
"unit": "°C",
"value": 39
}
]
}
},
{
"section_id": "assessment",
"fields": {
"medical_coding": [
{
"icd_10": "R50",
"icpc_2": "A03",
"ibui": "10049426",
"description": "koorts van onbekende oorsprong"
}
]
}
},
{
"section_id": "plan",
"fields": {
"summary": {
"text": "Ibuprofen en paracetamol voorgeschreven. Ziektebriefje tot einde week."
},
"prescribed_medication": [
{
"active_ingredient": "Ibuprofen",
"brand_name": null,
"pharmaceutical_form": null,
"pack_size": null,
"atc_code": "M01AE01"
},
{
"active_ingredient": "Paracetamol",
"brand_name": null,
"pharmaceutical_form": null,
"pack_size": null,
"atc_code": "N02BE01"
}
],
"sick_note": {
"from_date": "2026-01-30",
"to_date": "2026-02-02"
}
}
}
]
},
{
"episode": "Episode 2",
"template": "soap_new_complaint_api",
"sections": [
{
"section_id": "subjective",
"fields": {
"summary": {
"text": "Kniepijn, vooral bij lopen."
}
}
},
{
"section_id": "objective",
"fields": {
"summary": {
"text": ""
},
"vital_signs": []
}
},
{
"section_id": "assessment",
"fields": {
"medical_coding": [
{
"icd_10": "M25.5",
"icpc_2": "L20",
"ibui": "10037707",
"description": "gewrichtsklachten"
}
]
}
},
{
"section_id": "plan",
"fields": {
"summary": {
"text": "2 weken rust, niet lopen. Daarna geleidelijk hervatten."
},
"prescribed_medication": [],
"sick_note": null
}
}
]
}
]
}
```
## Metadata fields
Each API response includes metadata fields that describe the consultation and the generated report. These fields are returned at the top level of the response object.
| Field | Type | Description |
|-------------------|----------|---------------------------------------------------------------------------------------------------------------|
| `id` | `string` | Unique identifier for the consultation. |
| `input_language` | `string` | Language code of the input audio. |
| `output_language` | `string` | Language code of the generated report. |
| `start_datetime` | `string` | ISO 8601 timestamp indicating when the consultation started. |
| `end_datetime` | `string` | ISO 8601 timestamp indicating when the consultation ended. |
| `report_status` | `string` | State of the report: `"intermediate"`, `"final"`, `"not_generated"` or `"purged"`. See [Report status](https://developers.squire.eu/consultation/output#report-status). |
| `generation_result` | `string` | Result of the report generation process. See [Report generation result](https://developers.squire.eu/consultation/output#report-generation-result) for possible values. |
| `generation_result_message` | `string` | User-friendly message providing more details about the report generation result. This is translated in the report output language and is intended to be shown to an end user. |
| `content_format` | `string \| null` | Whether the report's text is plain text (`"plain"`) or rich text (`"markdown"`), or `null` when the consultation has no report. See [Content format](https://developers.squire.eu/consultation/output#content-format). |
| `data` | `Episode[] \| null` | The structured report content, or `null` when there is none. See [Report status](https://developers.squire.eu/consultation/output#report-status). |
## Report status
The `report_status` field describes the state of the consultation's report. It is also the field that explains why `data` is `null` when it is.
| `report_status` | `data` | Meaning |
|---|---|---|
| `final` / `intermediate` | `Episode[]` | A normal report. `intermediate` is a report for a consultation still in progress, `final` one for a finished consultation. |
| `final` / `intermediate` | `null` | The report exists, but produced no structured content. Questionnaire and custom-template reports do this when the transcript was too short to fill them in; `generation_result` says why. |
| `not_generated` | `null` | Generation never produced a report. It may still be running, or it may have failed. |
| `purged` | `null` | A report existed and was removed under the organization's data retention policy. |
> **Warning**
>
> `data: null` on its own does not mean there is no report. The second row above is a real report that
> happens to carry no structured content. Read `report_status` to tell the cases apart.
A report that generated normally but contains no episodes has `data: []`, not `null`.
A summary whose `report_status` is anything other than `intermediate` is the last one the consultation will produce, whether or not it carries content. It arrives on the [`summary-ready` event](https://developers.squire.eu/consultation/sdk#register-event-listeners) and ends the recording.
**View an example of a purged report**
```json
{
"id": "yoEh163Y1cHih2S1",
"input_language": "nl",
"output_language": "nl",
"start_datetime": "2025-01-01T12:00:00Z",
"end_datetime": "2025-01-01T12:30:00Z",
"report_status": "purged",
"generation_result": "success",
"content_format": "plain",
"data": null
}
```
## Content format
The `content_format` field says how to read the report's text fields:
| `content_format` | Meaning |
|---|---|
| `plain` | Plain text. Display it as is. |
| `markdown` | Rich text, written as Markdown. Render it with a Markdown renderer. |
| `null` | The consultation has no report (`report_status: "not_generated"`). |
A report takes the format of the template it was generated from. Predefined templates are always `plain`; only [custom templates](https://developers.squire.eu/consultation/templates#content-format) can be rich text. Markdown is currently the only rich text format; more may be added later. A purged report keeps the format it had.
In TypeScript the field is typed as `ContentFormat`, exported from the SDK. Like `report_status`, it is an open union rather than a closed enum, so a format added after your installed SDK version still passes through. Fall back to plain text for a value you don't recognize.
```ts
import type { ContentFormat } from '@squirehealth/sdk';
const renderers: Partial string>> = {
// Replace renderMarkdown with your actual Markdown rendering function
markdown: renderMarkdown,
};
function renderReportText(text: string, format: ContentFormat | null | undefined) {
// Plain text, and any format without a renderer, is shown as is
const render = format ? renderers[format] : undefined;
return render ? render(text) : text;
}
```
To support another format later, add a renderer for it.
## Report generation result
The `generation_result` field indicates the outcome of the report generation process. The following values are possible:
| Value | Report | Description |
|-------|:------:|-------------|
| `success` | ✓ | Report was generated successfully. |
| `audio_quality_degraded` | ⚠ | A report was generated, but the audio quality was poor, which may have affected the accuracy of the report. |
| `transcript_too_short` | ✗ | The transcription was too short to generate a meaningful report. |
| `audio_too_short` | ✗ | The audio duration was too short to generate a report. |
| `no_medical_context` | ✗ | No medical context was detected in the consultation audio. |
When the status is not `success`, the `generation_result_message` field provides a user-friendly explanation of the issue. Alternatively, you can use the `generation_result` code to display a localized message in your application.
> **Note**
>
> When `generation_result` indicates a failure (e.g., `transcript_too_short`, `audio_too_short`, `no_medical_context`), the structured data may be empty or contain placeholder content.
## Data structure
The API response contains metadata about the consultation, including the start and end time, the language of the input and output, and the structured data itself.
The structured data is organized into sections, each containing fields that represent different aspects of the consultation.
The `data` array contains the list of consultation episodes. Each episode has a `template` and a list of `sections`.
`data` is `null` whenever the response carries no report content, so check it before iterating. In TypeScript it is typed `Episode[] | null`, which surfaces the case at compile time.
```ts
const summary = await consultation.getSummary();
if (summary.data === null) {
// No report content. `summary.report_status` says why.
return;
}
for (const episode of summary.data) {
// ...
}
```
[Report status](https://developers.squire.eu/consultation/output#report-status) lists the cases in which `data` comes back `null`.
## Templates
The Squire SDK supports different templates for generating structured data. The following templates are currently available:
| Template Id | Description | Sections |
|-------------|-------------|----------|
| `soap_new_complaint_api` | SOAP note for general practitioners | `subjective`, `objective`, `assessment`, `plan` |
| `soap_urgent_care_api` | SOAP note for GP urgent care consultations (out of hours service) | `subjective`, `objective`, `assessment`, `plan` |
| `specialist_general_api` | Contact note for specialist consultations. All sections have `summary` fields. | `reason_for_encounter`, `anamnesis`, `clinical_research`, `diagnosis`, `action_plan`, `conclusion` |
| `specialist_general_free_text_api` | Specialist contact note with all sections combined into a single free-text string. | `free_text` |
| `dictation_api` | Dictation session with the raw transcription. | `transcription` |
Need a different structure? Create your own using [templates](https://developers.squire.eu/consultation/templates).
## Fields per section
### Subjective
| Field Id | Type | Description |
|------------|------|-------------|
| `summary` | `object` | Summary of the section. |
| `medical_coding` | `array` | List of medical coding. (only included for `soap_urgent_care_api`) |
### Objective
| Field Id | Type | Description |
|------------|------|-------------|
| `summary` | `object` | Summary of the section. |
| `vital_signs` | `array` | List of vital signs. |
### Assessment
| Field Id | Type | Description |
|------------|------|-------------|
| `summary` | `object` | Summary of the section. (only included for `soap_urgent_care_api`) |
| `medical_coding` | `array` | List of medical coding. |
### Plan
| Field Id | Type | Description |
|------------|------|-------------|
| `summary` | `object` | Summary of the section. |
| `prescribed_medication` | `array` | List of prescribed medication. |
| `sick_note` | `object` | Sick note information. |
### Transcription
The `transcription` section is used in the `dictation_api` template and contains the following fields:
| Field Id | Type | Description |
|------------|------|-------------|
| `fixed` | `object` | The text that has been finalized. |
| `ongoing` | `object` | The ongoing transcription, which may still change as the user speaks. |
Both `fixed` and `ongoing` fields have a `text` property, just like the [`summary`](https://developers.squire.eu/consultation/output#summary) field.
## Fields
### `summary`
#### Structure
| Field Id | Type | Description |
|------------|------|-------------|
| `text` | `string` | The textual summary of the section. |
#### Example
```json
{
"summary": {
"text": "Patient is feeling better."
}
}
```
### `vital_signs`
#### Structure
| Field Id | Type | Description |
|------------|------|-------------|
| `vital_sign_id` | `string` | The ID of the vital sign. |
| `unit` | `string` | The unit of the vital sign. |
| `value` | `number` | The value of the vital sign. |
### Available vital signs
| Vital Sign ID | Unit | Description |
|---------------------|------|-------------|
| `weight` | `kg` | Weight of the patient. |
| `height` | `cm` | Height of the patient. |
| `bmi` | `null` | Body Mass Index of the patient. |
| `systolic_blood_pressure` | `mmHg` | Systolic blood pressure of the patient. |
| `diastolic_blood_pressure` | `mmHg` | Diastolic blood pressure of the patient. |
| `heart_rate` | `bpm` | Heart rate of the patient. |
| `blood_glucose` | `mg/dL` | Blood glucose level of the patient. |
| `body_temperature` | `°C` | Body temperature of the patient. |
| `peak_flow` | `L/min` | Peak flow of the lungs. |
| `oxygen_saturation` | `%` | Oxygen saturation of the patient. |
#### Example
```json
{
"vital_signs": [
{
"vital_sign_id": "systolic_blood_pressure",
"unit": "mmHg",
"value": 100.0
},
{
"vital_sign_id": "diastolic_blood_pressure",
"unit": "mmHg",
"value": 60.0
}
]
}
```
### `medical_coding`
#### Structure
| Field Id | Type | Description |
|------------|------|-------------|
| `icd_10` | `string` | The ICD-10 code. |
| `icpc_2` | `string` | The ICPC-2 code. |
| `ibui` | `string` | The IBUI code. |
| `description` | `string` | The description of the diagnosis. |
#### Example
```json
{
"medical_coding": [
{
"icd_10": "E61.1",
"icpc_2": "T91",
"ibui": "10024489",
"description": "ijzerdeficiëntie"
},
{
"icd_10": "M54.9",
"icpc_2": "L02",
"ibui": "10080680",
"description": "rugpijn"
}
]
}
```
### `prescribed_medication`
#### Structure
| Field Id | Type | Description |
|------------|------|-------------|
| `active_ingredient` | `string` | The active ingredient of the medication. |
| `brand_name` | `string` | The brand name of the medication. |
| `pharmaceutical_form` | `string` | The pharmaceutical form of the medication. |
| `pack_size` | `string` | The pack size of the medication. |
| `atc_code` | `string` | The ATC code of the active ingredient. |
#### Example
```json
{
"prescribed_medication": [
{
"active_ingredient": "Paracetamol",
"brand_name": "Panadol",
"pharmaceutical_form": "Tablet",
"pack_size": "20",
"atc_code": "N02BE01"
}
]
}
```
### `sick_note`
#### Structure
| Field Id | Type | Description |
|------------|------|-------------|
| `from_date` | `string` | The start date of the sick note. (in `YYYY-MM-DD` format) |
| `to_date` | `string` | The end date of the sick note. (in `YYYY-MM-DD` format) |
#### Example
```json
{
"sick_note": {
"from_date": "2025-01-01",
"to_date": "2025-01-07"
}
}
```
---
Source: https://developers.squire.eu/consultation/multi-soap
# Multi-SOAP
When using SOAP templates, you can split a single consultation into multiple separate SOAP notes or merge previously split consultations back together. This is useful when multiple patient concerns are discussed in one visit and need to be documented separately.
## Prerequisites
Before using multi-SOAP functionality:
- You must have completed a consultation using a SOAP template (e.g., `soap_new_complaint_api`)
- You need the consultation ID from the `startRecording` method
## Splitting a consultation
To split a consultation into multiple SOAP notes, use the `splitSoap` method on the `Consultation` object returned by `startRecording`:
```js
await consultation.splitSoap();
```
Regeneration keeps the report length already stored on the consultation (from `startRecording`, including when you omitted `writingStyle`), with the user's account default as fallback. The SDK does not send a new `writingStyle` for split or merge.
This asynchronous operation will process the consultation and create separate SOAP notes for distinct patient concerns or topics discussed during the visit.
```mermaid
graph LR
A["Single Consultation
🗂️
(Multiple concerns)"] -->|splitSoap| B["Multiple SOAP Notes
📄📄📄
(Separated by concern)"]
B -->|mergeSoap| A
style A fill:#3b82f6,color:#fff
style B fill:#10b981,color:#fff
```
## Merging split consultations
If you've previously split a consultation and want to merge the SOAP notes back into a single consultation, use the `mergeSoap` method on the `Consultation` object:
```js
await consultation.mergeSoap();
```
This will combine the previously split SOAP notes back into a unified consultation summary.
> **Warning**
>
> Only consultations that have been previously split can be merged. Attempting to merge a consultation that hasn't been split will result in an error.
## Example
```js
// Start recording
const consultation = await squire.startRecording({
inputLanguage: 'nl',
templateId: 'soap_new_complaint_api',
});
// Split the consultation into multiple episodes
const splitSummary = await consultation.splitSoap();
console.log('Split result:', splitSummary);
// splitSummary contains the final summary with multiple episodes in `data`
// Or merge episodes back into a single consultation
const mergedSummary = await consultation.mergeSoap();
console.log('Merge result:', mergedSummary);
// mergedSummary contains the final summary with a single consolidated episode
```
> **Note**
>
> Both `splitSoap` and `mergeSoap` return a promise that resolves with the final summary object.
## Purged consultations
Both methods regenerate the report from the consultation's transcript. Organizations can set a data retention policy that permanently removes that transcript on a schedule, and once it is gone the report can no longer be regenerated. `splitSoap()` and `mergeSoap()` then reject with a `Squire.ApiError` carrying `status: 410` and `code === Squire.DATA_PURGED`.
```ts
import Squire from '@squirehealth/sdk';
try {
await consultation.splitSoap();
} catch (error) {
if (error instanceof Squire.ApiError && error.code === Squire.DATA_PURGED) {
// `error.detail` names which data went and is safe to show, but it can be null
return;
}
throw error;
}
```
Branch on `error.code` rather than on the message or the response shape, and treat the failure as final: the transcript is not coming back, so retrying will fail the same way. See [Purged data](https://developers.squire.eu/consultation/error-handling#purged-data).
## Recovering a lost consultation reference
If you no longer hold a reference to the `Consultation` object (e.g. after a page refresh or navigation), you can reconstruct it using `squire.consultation()`:
```js
const consultation = squire.consultation('consultation-uuid');
// You can now call splitSoap / mergeSoap / getSummary as usual
const summary = await consultation.splitSoap();
```
This creates a `Consultation` instance bound to the given ID, allowing you to call any consultation method without needing the original object from `startRecording`.
## Output format
After splitting a consultation, the returned summary will contain multiple episodes in the `data` array:
```json
{
"id": "8lbv3SJ7ObqOWh11",
"data": [
{
"episode": "Episode 1",
"template": "soap_new_complaint_api",
"sections": [...]
},
{
"episode": "Episode 2",
"template": "soap_new_complaint_api",
"sections": [...]
}
]
}
```
Each episode contains its own SOAP sections with separate patient concerns. For the complete output structure and available fields, see the [output documentation](https://developers.squire.eu/consultation/output).
---
Source: https://developers.squire.eu/consultation/product-usage
# Product usage
Usage is tracked per product for the signed-in user. The organization comes from the access token. Each user gets an allowance for every billing period. It goes back to the full limit at `resetsAt`.
```js
const usage = await squire.user.getUsage();
const scribe = usage.products.find((product) => product.productId === 'squire_scribe');
console.log(scribe);
// { productId: "squire_scribe", plan: "free", used: 3, limit: 10, remaining: 7, resetsAt: "2026-06-01T00:00:00Z" }
```
## Response shape
`getUsage()` returns a `products` list with one entry per product. Look your product up by its `productId` rather than by position, so that your code keeps working as products are added:
```ts
/**
* Usage for a single product in the current period, one entry of usage.products.
*/
type ProductUsage = {
/**
* Identifier of the product this allowance applies to, for example "squire_scribe".
*/
productId: string;
/**
* Plan the user is on, for example "free" or "standard". Read the limit below for
* the allowance actually in force.
*/
plan: string;
/**
* Amount used so far this period.
*/
used: number;
/**
* Total amount allowed for the period on the user's plan.
*/
limit: number;
/**
* Amount still available this period (limit minus used).
*/
remaining: number;
/**
* ISO 8601 timestamp, always UTC, at which the allowance goes back to the
* full limit. This moment belongs to the next period: a consultation started
* exactly then, or later, counts towards the new allowance.
*/
resetsAt: string;
};
export default ProductUsage;
```
## Running out of allowance
Squire checks the limit on the server, so you do not need to check it yourself before each recording. Once a user has no allowance left, `startRecording` fails with HTTP 402 and the code `consultation_quota_exceeded`:
```js
try {
const consultation = await squire.startRecording();
} catch (error) {
if (
error instanceof Squire.ApiError &&
error.code === Squire.CONSULTATION_QUOTA_EXCEEDED
) {
// Show an upgrade prompt
return;
}
throw error;
}
```
Handling this error is all you need to do. We do recommend showing the usage somewhere in your app, such as a counter or a warning when users get close to their limit, so that running out does not come as a surprise.
## Reading usage from your backend
To show usage outside the SDK, your backend can read the same numbers with your API key, without requesting an access token:
```bash
curl "https://api.squire.eu/api/v1/external/users/USER_ID/usage/" \
-H "X-Api-Key: YOUR_API_KEY"
```
`USER_ID` is the user ID you passed when you created the user. The response is the same, except that the field names stay in snake_case (`product_id`, `resets_at`). See the [usage endpoint API reference](https://app.squire.eu/api/v1/external/docs/#tag/users/GET/api/v1/external/users/{user_id}/usage/).
---
Source: https://developers.squire.eu/consultation/terms-and-conditions
# Terms & Conditions
Before using the SDK's transcribe functionality, end users must accept the Terms & Conditions. The SDK provides useful methods to check the acceptance status and handle the acceptance flow.
## Usage
### Check terms & conditions status
After [initializing the Squire SDK](https://developers.squire.eu/consultation/sdk#initialize-the-sdk), retrieve the Terms & Conditions document information for the current user:
```js
const terms = await squire.getTermsAndConditionsDocumentInfo();
```
This document exposes properties such as `isAccepted`, `documentUrl`, and the method `accept()` to handle the acceptance flow.
### Verify acceptance
Validate if the user has already accepted the Terms & Conditions by checking the `isAccepted` property:
```js
if (terms.isAccepted) {
console.log('All good, the Terms & Conditions have already been accepted.');
return;
}
```
### Display a terms & conditions document
In case the user has not yet accepted the Terms & Conditions, you should display the document to them. The `documentUrl` property provides a link to the Terms & Conditions document, which can be displayed in your application.
You can use a simple link to open the document in a new tab:
```html
View Terms & Conditions
```
```js
const termsLink = document.getElementById('terms-link');
termsLink.href = terms.documentUrl;
```
Alternatively, you can embed the document in an iframe.
### Handle acceptance
Handle the accept button click:
```js
const acceptButton = document.getElementById('accept-terms');
acceptButton.addEventListener('click', async () => {
await terms.accept();
console.log('Terms accepted successfully');
});
```
## Handling Updates
When a new version of the Terms & Conditions is available, the SDK will automatically return the new version with updated `documentUrl` and `isAccepted` properties. If the user has already accepted the previous version, they will need to accept the new version to continue using the transcribe functionality.
## API Reference
### `getTermsAndConditionsDocumentInfo()`
Returns information about the current Terms & Conditions document.
#### Return Value
Returns a promise that resolves to an object with the following properties:
| Property | Type | Description |
|----------|------|-------------|
| `uuid` | `string` | Unique identifier of the T&C document |
| `documentFilename` | `string` | Filename of the T&C document |
| `documentUrl` | `string` | URL where the T&C document can be downloaded |
| `createdDt` | `Date` | Creation date of the T&C document |
| `acceptedDt` | `Date`, `null` | Date when terms were accepted, or null if not accepted |
| `isAccepted` | `boolean` | Whether the terms have been accepted |
| `accept()` | `function` | Method to accept the terms |
---
Source: https://developers.squire.eu/consultation/error-handling
# Error Handling
Proper error handling is essential for providing a good user experience. Squire SDK provides robust error handling mechanisms to ensure a smooth integration experience. This page covers both built-in and explicit error handling strategies, as well as log level configuration.
## State Diagram
The sessions in the Squire SDK follow the state diagram below:
```mermaid
stateDiagram-v2
[*] --> INITIALIZING: startRecording()
INITIALIZING --> RECORDING: establish connection to server & microphone
RECORDING --> PAUSED: pauseRecording()
PAUSED --> RECORDING: resumeRecording()
RECORDING --> AWAITING_SUMMARY: stopRecording()
AWAITING_SUMMARY --> FINISHED
FINISHED --> [*]
RECORDING --> RECONNECTING
RECONNECTING --> RECORDING
RECONNECTING --> [*]
```
### Listening for state changes
You can listen to state transitions using the `state-change` event. This event is emitted whenever the SDK transitions between states, allowing you to update your UI accordingly.
```ts
squire.on('state-change', (status) => {
console.log('SDK status changed to:', status);
});
```
The possible status values are: `INITIALIZING`, `RECORDING`, `PAUSED`, `RECONNECTING`, `AWAITING_SUMMARY`, and `FINISHED`.
## Error handling
### Built-in Error Handling
The SDK includes built-in error handling and retry logic for transient errors, such as network issues or server errors. If a non-recoverable error occurs, an `error` event will be emitted.
If the connection drops during audio streaming of an active consultation, the SDK will attempt to reconnect automatically. During the `RECONNECTING` state, the client continues to buffer audio locally. Once the connection is re-established, all buffered audio is sent to the server, ensuring no data is lost.
### Explicit Error Handling
The `startRecording` method processes asynchronously to set up a new session, connect to the microphone, and start streaming audio. If any error occurs during this process, the promise will be rejected with an error. You can handle these errors using a try-catch block:
```ts
try {
// Your logic to show a loading state goes here ...
const consultation = await squire.startRecording();
// Your logic to hide the loading state goes here ...
} catch (error) {
// Your logic to handle errors goes here, e.g. show a notification to the user
}
```
### API errors
When a request to the Squire API fails, the promise rejects with a `Squire.ApiError`. It extends `Error`, so `error.message` still holds a readable description, and adds the machine-readable parts of the response:
| Property | Type | Description |
|---|---|---|
| `status` | `number` | HTTP status code of the response |
| `code` | `string \| null` | Machine-readable error code when the API returns one |
| `detail` | `string \| null` | Human-readable message from the API |
Both the error class and the codes are reachable as statics on the default export, so no named imports are needed. The codes to handle explicitly are:
| Code | Constant | HTTP | Meaning |
|---|---|---|---|
| `consultation_quota_exceeded` | `Squire.CONSULTATION_QUOTA_EXCEEDED` | 402 | The user has used their full consultation allowance for the current billing period, so `startRecording` fails. |
| `data_purged` | `Squire.DATA_PURGED` | 410 | The data the request needed was permanently removed under the organization's data retention policy. |
> **Note**
>
> Branch on `error.code`, not on `error.message` or the shape of the response body. The message is a
> human-readable sentence that can be reworded or translated at any time; the code is the stable,
> machine-readable part of the contract.
#### Quota exceeded
```ts
import Squire from '@squirehealth/sdk';
try {
const consultation = await squire.startRecording();
} catch (error) {
if (
error instanceof Squire.ApiError &&
error.code === Squire.CONSULTATION_QUOTA_EXCEEDED
) {
// Show an upgrade prompt instead of a generic error
return;
}
throw error;
}
```
See [Product usage](https://developers.squire.eu/consultation/product-usage) for reading the remaining allowance and the date it resets.
#### Purged data
Organizations can set a data retention policy that permanently removes a consultation's audio, transcript and report on a schedule. Once the transcript is gone, the report can no longer be regenerated, so `splitSoap()` and `mergeSoap()` reject with a `Squire.ApiError` carrying `status: 410` and `code === Squire.DATA_PURGED`. When `detail` is set it names which data went, in wording written to be shown to the user, but it can be `null`, so keep a fallback message.
```ts
import Squire from '@squirehealth/sdk';
try {
await consultation.splitSoap();
} catch (error) {
if (error instanceof Squire.ApiError && error.code === Squire.DATA_PURGED) {
// `detail` names which data went and is safe to show, but it can be null
showMessage(error.detail ?? 'This consultation is no longer available.');
return;
}
throw error;
}
```
This is a final state rather than a transient failure: the data is not coming back, so retrying the call will fail the same way. Present it to the user as such instead of offering a retry.
A consultation can outlive its report, so the same policy shows up in a summary: it comes back with `report_status: "purged"` and `data: null`. See [Report status](https://developers.squire.eu/consultation/output#report-status).
## Report Generation Result
After a consultation is completed, check the `generation_result` field to ensure the report was generated successfully. See [Report generation result](https://developers.squire.eu/consultation/output#report-generation-result) for possible values and how to handle them.
## Log Level
> **Note**
>
> New in SDK v1.8.1: The SDK now supports adjustable log levels for more granular control over logging output.
You can set the desired log level when initializing the Squire SDK by adding the `logLevel` option. The available log levels are:
- `debug`: Detailed debugging information.
- `info`: General operational information. (default)
- `warn`: Warnings about potential issues.
- `error`: Only error messages.
- `silent`: No logging output.
```ts
const squire = new Squire({
token: 'REPLACE_WITH_ACCESS_TOKEN',
outputLanguage: 'en',
logLevel: 'debug',
});
```
---
Source: https://developers.squire.eu/dictation
# Dictation
Dictation turns speech into a transcript while the user is still speaking. The SDK streams the audio and returns the transcript in two parts: the text that has been finalized, and the text that is still being processed and can still change. Use it when you want the words themselves rather than a structured note. For structured clinical output, see [Consultation](https://developers.squire.eu/consultation).
It runs on the same SDK as consultation recording, so the setup is identical: request an access token on your server, initialize the SDK in your client, and select a microphone. See [Authentication](https://developers.squire.eu/get-started/authentication), [SDK installation](https://developers.squire.eu/get-started/sdk-installation) and [Recording with the SDK](https://developers.squire.eu/consultation/sdk) for those steps. If you would rather not build the recording interface yourself, the [Consultation widget](https://developers.squire.eu/consultation/widget) has a dictation flow built in.
## Starting a dictation
To start a dictation, call `startRecording` with the `templateId` set to `'dictation_api'`.
```javascript
const consultation = await squire.startRecording({
inputLanguage: 'en',
templateId: 'dictation_api',
});
```
## Handling transcription results
Listen for the `summary-ready` event to receive transcription updates. The event is triggered multiple times during the dictation, providing intermediate results.
The `summary` object in the event payload contains the transcription data. The transcription is divided into two parts:
- `fixed`: The portion of the transcript that has been finalized.
- `ongoing`: The portion of the transcript that is still being processed and may change.
Here's how you can access and display the transcription:
```javascript
squire.on('summary-ready', (summary) => {
const transcription = summary.data?.find((d) => d.template === 'dictation_api');
if (!transcription) return;
const transcriptionSection = transcription.sections?.find((s) => s.section_id === 'transcription');
if (!transcriptionSection) return;
const fixedText = transcriptionSection.fields.fixed?.text || '';
const ongoingText = transcriptionSection.fields.ongoing?.text || '';
// Update your UI with the fixed and ongoing text.
document.getElementById('fixed-text-output').textContent = fixedText;
document.getElementById('ongoing-text-output').textContent = ongoingText;
});
```
When the dictation is stopped, a final `summary-ready` event is emitted with the complete transcription. The `report_status` field in the summary will be `'final'`.
For more details on the structure of the summary, refer to the [output documentation](https://developers.squire.eu/consultation/output).
## Error handling
Dictation sessions report failures the same way consultation recordings do. See [Error handling](https://developers.squire.eu/consultation/error-handling) for session states, retries and API errors.
---
Source: https://developers.squire.eu/intake
# Intake
Intake lets healthcare providers digitize patient intake workflows. By integrating Intake into your medical or calendar software, patients can complete intake questionnaires before their appointment, and providers can view structured summaries directly within their existing system.
## How it works
The Intake integration consists of three main components:
1. **Scheduling API**: create intake sessions via the SDK, linked to your calendar system. Patient data and a unique patient ID are passed along so results can be queried later.
2. **Protocol widget**: an embeddable widget that lets providers create, configure, activate, and deactivate intake configs.
3. **Summary widget**: an embeddable widget that displays intake sessions and completed summaries within your application.
```mermaid
sequenceDiagram
participant EHR
participant Squire SDK
participant Squire API
participant Patient
EHR->>Squire SDK: Create intake session (patient data + patient ID)
Squire SDK->>Squire API: Schedule session with intake config
Squire API-->>Patient: Send intake invitation email
Patient->>Squire API: Complete intake questionnaire
Squire API-->>EHR: Intake summary available
Note over EHR: Display summary via Summary Widget
```
## Integration approach
| Component | Integration method | Purpose |
|-----------|-------------------|---------|
| [Scheduling](https://developers.squire.eu/intake/scheduling) | SDK / API | Create and schedule intake sessions from your calendar |
| [Protocol widget](https://developers.squire.eu/intake/settings-widget) | Widget | Create and configure intake configs |
| [Summary widget](https://developers.squire.eu/intake/summary-widget) | Widget | View intake sessions and completed summaries in your application |
| [Email & DNS](https://developers.squire.eu/intake/email-setup) | Portal configuration | Configure custom email sender and hostname |
> **Note**
>
> The scheduling component is intentionally API-based (not a widget) to allow seamless integration with any calendar system without replacing your existing scheduling workflow.
## Prerequisites
- A valid Squire API key (see [Authentication](https://developers.squire.eu/get-started/authentication))
- The Squire SDK installed (see [Installation](https://developers.squire.eu/get-started/sdk-installation))
---
Source: https://developers.squire.eu/intake/scheduling
# Scheduling
Intake sessions are created via the SDK's API rather than through a widget. This allows you to keep your existing calendar and booking flow while connecting it to Squire Intake behind the scenes.
> **Note**
>
> Scheduling is API-based so you can integrate it directly into your existing calendar system without replacing your booking UI.
## Flow
### List available intake configs
Before creating a session, retrieve the available intake configs. Each one represents a specific intake questionnaire.
```js
const configs = await squire.intake.getIntakeConfigs();
```
The function returns a list of intake configs, each with the following properties:
| Property | Type | Description |
|----------|------|-------------|
| `id` | string | Unique identifier of the intake config |
| `name` | string | Human-readable name of the intake config |
### Create an intake session
Create a new intake session by calling `createSession` with the patient data, selected intake config, and appointment details.
```js
const session = await squire.intake.createSession({
intakeConfigId: 'intake_config_id',
appointmentDt: '2025-06-15T10:00:00Z',
firstName: 'John',
lastName: 'Doe',
email: 'john.doe@example.com',
phoneNumber: '+32412345678',
healthcareProviderId: 'your_ehr_user_id',
});
```
## Session Parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `intakeConfigId` | string | Yes | The ID of the intake config to use (from `getIntakeConfigs()`) |
| `appointmentDt` | string \| Date | Yes | Scheduled date and time of the appointment (ISO 8601 or `Date` object) |
| `firstName` | string | No | Patient's first name |
| `lastName` | string | No | Patient's last name |
| `email` | string | No | Patient's email address (used for sending the intake invitation) |
| `phoneNumber` | string | No | Patient's phone number |
| `healthcareProviderId` | string | No | The healthcare provider's user identifier from your system |
## Session Response
The `createSession` call returns an `IntakeSession` object:
| Property | Type | Description |
|----------|------|-------------|
| `id` | string | Unique session identifier |
| `intakeUrl` | string | URL sent to the patient to complete the intake |
## What Happens Next
After a session is created:
1. The patient receives an **email invitation** with a link to complete the intake questionnaire.
2. The patient fills in the questionnaire at their own pace before the appointment.
3. Once completed, the intake summary becomes available and can be viewed via the [Summary Widget](https://developers.squire.eu/intake/summary-widget).
---
Source: https://developers.squire.eu/intake/settings-widget
# Protocol widget
Intake configs define the questionnaires that patients receive before their appointment. The Protocol widget gives healthcare providers a hosted UI for creating and maintaining those questionnaires from inside your application's settings area.
## What Providers Can Manage
The widget lets providers:
- Create intake configs
- Edit a config's name
- Configure the intake flow with topics and conditional branches
- Set follow-up depth (`None`, `Short`, or `Detailed`)
- Add additional instructions
- Activate or deactivate a config
Changes are autosaved by the widget.
### Mounting the widget
Mount the widget in your application's settings or configuration area.
```js
const widget = squire.mountWidget('#intake-settings-container', 'intake-settings', {
theme: {
colorPrimary: '#337ab7',
colorLightest: '#f8f9fa',
borderRadius: '0.25rem',
font: 'Roboto',
},
});
```
```html
```
### Events
Listen for lifecycle events on the widget handle returned by `mountWidget`:
```js
widget.on('loaded', () => {
console.log('Protocol widget loaded');
});
```
| Event | Payload | Description |
|-------|---------|-------------|
| `loaded` | `null` | Fired when the widget has initialized |
### Theming
Customize the widget's appearance by passing a `theme` object:
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| `colorPrimary` | string | `'#539DD6'` | Primary color for buttons and accents |
| `colorLightest` | string | `'#E1F1FD'` | Lightest color for backgrounds |
| `borderRadius` | string | `'0.5rem'` | Border radius for UI elements |
| `font` | string | `'system-ui, sans-serif'` | Font family (all [Google Fonts](https://fonts.google.com/) are supported) |
You can also pass `locale` to localize the widget. Supported locales are `en`, `nl`, `de`, and `fr`.
```js
squire.mountWidget('#intake-settings-container', 'intake-settings', {
locale: 'nl',
});
```
## Listing Intake Configs via API
Use the API when you need to populate your own UI, such as a dropdown in your booking flow:
```js
const configs = await squire.intake.getIntakeConfigs();
```
Returns an array of intake config objects:
```json
[
{
"id": "proto_abc123",
"name": "General Intake"
},
{
"id": "proto_def456",
"name": "Specialist Referral"
}
]
```
> **Note**
>
> Use the intake config `id` when [creating an intake session](https://developers.squire.eu/intake/scheduling) to link the correct questionnaire to the appointment.
---
Source: https://developers.squire.eu/intake/summary-widget
# Summary Widget
The Summary Widget displays intake sessions and completed summaries within your medical software. It can be mounted as a tab or panel in your patient dashboard, or as a daily intake overview for providers.
## Mounting the widget
Mount the Summary Widget in your patient view and pass an intake session ID to open a specific summary.
```js
const widget = squire.mountWidget('#intake-summary-container', 'intake-summary', {
sessionId: 'intake_session_id',
theme: {
colorPrimary: '#337ab7',
colorLightest: '#f8f9fa',
borderRadius: '0.25rem',
font: 'Roboto',
},
});
```
```html
```
> **Note**
>
> If you omit `sessionId`, the widget shows today's intake sessions for the authenticated organization and lets the provider open one from the list.
## Configuration Options
| Option | Type | Required | Description |
|--------|------|----------|-------------|
| `sessionId` | string | No | The intake session ID returned when [creating a session](https://developers.squire.eu/intake/scheduling). When omitted, the widget lists today's intake sessions. |
| `locale` | string | No | Widget language. Supported values are `en`, `nl`, `de`, and `fr`. |
### Theming
Customize the widget's appearance by passing a `theme` object:
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| `colorPrimary` | string | `'#539DD6'` | Primary color for buttons and accents |
| `colorLightest` | string | `'#E1F1FD'` | Lightest color for backgrounds |
| `borderRadius` | string | `'0.5rem'` | Border radius for UI elements |
| `font` | string | `'system-ui, sans-serif'` | Font family (all [Google Fonts](https://fonts.google.com/) are supported) |
## Events
```js
widget.on('loaded', () => {
console.log('Intake summary widget loaded');
});
```
| Event | Payload | Description |
|-------|---------|-------------|
| `loaded` | `null` | Fired when the widget has initialized |
## Summary Content
The Summary Widget displays a structured overview of the patient's intake responses, including:
- Patient name, appointment time, email, and phone number when available
- Intake config name and current status
- A concise text summary
- Structured summary entries
- Conversation history between the patient and intake assistant
- Intake timeline and completion state
## Linking Intake with Consultation
> **Warning**
>
> Coming soon: the intake summary will be linkable with the [Consultation widget](https://developers.squire.eu/consultation/widget) to provide additional context during the consultation.
---
Source: https://developers.squire.eu/intake/email-setup
# Email & DNS Setup
When a patient is invited for an intake, Squire sends a confirmation email with a link to the questionnaire. You can customize the sender email address and use a custom hostname for the intake pages through DNS configuration.
## What Gets Configured
| Feature | Description |
|---------|-------------|
| **Custom email sender** | Emails are sent from your own domain (e.g. `intake@yourclinic.com`) instead of a generic Squire address |
| **Custom hostname** | The intake questionnaire is served on your own subdomain (e.g. `intake.yourclinic.com`) |
## Setup
Configuration is done through the [Squire Portal](https://developers.squire.eu/reference/portal).
### Navigate to DNS settings
In the Squire Portal, go to **Settings** → **Email & DNS**.
### Configure email sender
Enter the email address you want intake emails to be sent from. Squire will provide the DNS records (SPF, DKIM, DMARC) that need to be added to your domain.
### Configure custom hostname
Enter the subdomain you want to use for the intake pages. Squire will provide a CNAME record to add to your DNS.
### Verify DNS records
After adding the DNS records, click **Verify** in the Portal to confirm the configuration is active.
> **Note**
>
> DNS propagation can take up to 48 hours. The Portal will show the verification status for each record.
---
Source: https://developers.squire.eu/medical-coding
# Coding
Coding encodes clinical text into standardised medical coding systems. You send free text or point at a consultation, and get back the clinical entities found in it, each with its codes and its position in the source text.
It is a server-side product: one REST endpoint, authenticated with your API key. There is no SDK method and no widget for it.
## Coding systems
| System | `coding_systems` value | Availability |
|---|---|---|
| SNOMED CT | `snomed-ct` | Generally available |
| ICD-10 | `icd-10` | Early access, invite-only |
> **Note**
>
> ICD-10 is in early access and is only enabled for invited accounts. Email integrations@squire.eu if you want access. See [Support](https://developers.squire.eu/reference/support).
## Encoding text
`POST https://api.squire.eu/api/v1/external/medical-coding/`
| Header | Required | Description |
|---|---|---|
| `X-Api-Key` | Yes | Your Squire API key. See [Authentication](https://developers.squire.eu/get-started/authentication) |
| `Content-Type` | Yes | `application/json` |
| Field | Type | Description |
|---|---|---|
| `coding_systems` | `string[]` | The systems to encode into. See [Coding systems](https://developers.squire.eu/medical-coding#coding-systems). |
| `text` | `string` | Clinical free text, 1 to 50,000 characters. |
| `consultation_id` | `string` | ID of a consultation whose active report text is encoded. |
Provide exactly one of `text` or `consultation_id`. Use `text` when the text lives in your own system, and `consultation_id` when you want to encode a report Squire already produced.
```bash
curl -X POST "https://api.squire.eu/api/v1/external/medical-coding/" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"coding_systems": ["snomed-ct"],
"text": "Patient presents with type 2 diabetes mellitus and hypertension."
}'
```
## Response
```json
{
"coding_systems": ["snomed-ct"],
"text": "Patient presents with type 2 diabetes mellitus and hypertension.",
"entities": [
{
"entity_text": "type 2 diabetes mellitus",
"entity_start_char": 23,
"entity_end_char": 47,
"negated": false,
"relevance": "high",
"codes": [
{
"code": "44054006",
"code_name": "Type 2 diabetes mellitus (disorder)",
"coding_system": "snomed-ct"
}
]
},
{
"entity_text": "hypertension",
"entity_start_char": 52,
"entity_end_char": 64,
"negated": false,
"relevance": "high",
"codes": [
{
"code": "38341003",
"code_name": "Hypertensive disorder (disorder)",
"coding_system": "snomed-ct"
}
]
}
]
}
```
`text` is echoed back, so the character offsets always refer to a string you have. Each entry in `entities` is one clinical concept found in it:
| Field | Type | Description |
|---|---|---|
| `entity_text` | `string` | The span of source text this entity was read from. |
| `entity_start_char` | `number` | Start offset of that span in `text`. |
| `entity_end_char` | `number` | End offset of that span in `text`. |
| `negated` | `boolean` | Whether the text states the concept is absent. |
| `relevance` | `string` | How central the concept is to the text. |
| `codes` | `array` | One entry per code found, with `code`, `code_name` and `coding_system`. |
> **Warning**
>
> Check `negated` before you store anything. "No history of hypertension" produces a hypertension entity with `negated: true`, and recording it as a diagnosis would be wrong.
An entity can carry more than one code, and asking for several coding systems puts all of their codes in the same `codes` array. Read `coding_system` on each code rather than relying on position.
The offsets let you highlight the source text in your interface, so a user can see what a code was derived from before accepting it.
## Rate limits
250 requests per minute and 1,000 per hour, per API key. Encoding a long document in one request costs the same as a short one, so batch text together where you can rather than calling once per sentence.
## Coding in a consultation summary
This endpoint is separate from the codes that come back with a consultation. A consultation summary can include a [`medical_coding`](https://developers.squire.eu/consultation/output#medical_coding) field with ICD-10, ICPC-2 and IBUI codes per diagnosis, produced as part of generating the note. Use this endpoint when you want to encode text on demand, or text Squire did not produce; use the summary field when the codes for a consultation are all you need.
---
Source: https://developers.squire.eu/widgets
# Widgets
Widgets are one of the three ways to integrate Squire, next to the [JavaScript SDK](https://developers.squire.eu/get-started/sdk-installation) and the [REST API](https://app.squire.eu/api/v1/external/schema/redoc/). A widget is not a product of its own: it is a complete flow for one of the products, mounted into your application with a single SDK call, so you can ship a feature without building the interface yourself.
Every widget shares the same model:
- Mounted with `squire.mountWidget(selector, widgetName, config)` after the SDK is initialized
- Themed through a `theme` object with colors, border radius and font
- Localized in English, Dutch, French and German
- Emits events through the `on` method on the widget handle
## Widget lifecycle
Widgets follow the same initialization and event flow. For obtaining a token, see [authentication](https://developers.squire.eu/get-started/authentication).
```mermaid
sequenceDiagram
participant Host Client
participant Squire SDK
participant Squire Widget
participant Squire API
Note over Host Client: Initialize SDK with token
Host Client->>Squire SDK: mountWidget(selector, widgetName, config)
Squire SDK->>Squire Widget: Mount widget in host
Squire Widget->>Squire API: Connect and authenticate
Squire API-->>Squire Widget: Widget resources & configuration
Squire Widget->>Squire SDK: Emit `loaded` event
Squire SDK->>Host Client: Expose event via `on` method
loop User interaction
Host Client->>Squire Widget: User interactions
Squire Widget->>Squire SDK: Emit events
Squire SDK->>Host Client: Expose events via `on` method
end
```
## Available widgets
- [Consultation widget](https://developers.squire.eu/consultation/widget): A complete recording interface for Consultation, including dictation.
- [Microphone quality test](https://developers.squire.eu/widgets/microphone-quality-test): Let users verify their microphone before recording.
- [Intake protocol widget](https://developers.squire.eu/intake/settings-widget): A hosted interface for creating and configuring intake questionnaires.
- [Intake summary widget](https://developers.squire.eu/intake/summary-widget): A hosted interface for viewing intake sessions and summaries.
---
Source: https://developers.squire.eu/widgets/microphone-quality-test
# Microphone Quality Test
The Microphone Quality Test Widget is a pre-built UI component that allows users to test the quality of their microphone directly within your application. This widget provides an easy-to-use interface for users to check their microphone's performance, ensuring optimal audio quality.
## Overview
The microphone quality test widget helps users verify their audio setup before starting a recording session. It can be embedded directly into your application using the Squire SDK's `mountWidget` method.
_Figure: The Microphone Quality Test widget before and after a test. Microphone quality test widget, ready to start; Microphone quality test widget showing the result_
## Basic usage
### HTML setup
First, create a container element where the widget will be mounted:
```html
```
### Initialize the SDK
Then, initialize the Squire SDK. See [the usage documentation](https://developers.squire.eu/consultation/sdk#initialize-the-sdk) for more detail.
```javascript
const squire = new Squire({
token: 'REPLACE_WITH_ACCESS_TOKEN',
outputLanguage: 'en',
});
```
### Mounting the Widget
After initializing the Squire SDK, mount the widget using the `mountWidget` method:
```javascript
const widget = squire.mountWidget('#squire-mic-test', 'microphone-quality-test');
```
The method takes two required parameters:
1. **Container selector**: A string CSS selector of the container element
2. **Widget name**: A string specifying the type of widget to mount
## Configuration Options
The widget supports extensive customization through theme configuration. You can pass theme options in the config object as the third parameter to `mountWidget`:
```javascript
const widget = squire.mountWidget('#squire-mic-test', 'microphone-quality-test', {
locale: 'en',
microphoneLabel: 'MacBook Pro Microphone (Built-in)',
theme: {
colorPrimary: '#337ab7',
colorDark: '#212529',
colorLight: '#236aa7',
colorLightest: '#f8f9fa',
borderRadius: '0.25rem',
font: 'Roboto'
}
});
```
### Theme Properties
```ts
/**
* Theme configuration object for customizing the widget's appearance.
*/
type ThemeConfig = {
/**
* Primary color for buttons and accents.
*
* @default '#539DD6'
*/
colorPrimary?: string;
/**
* Dark color for text and borders.
*
* @default '#0C2639'
*/
colorDark?: string;
/**
* Light accent color for hover states.
*
* @default '#7CC1F6'
*/
colorLight?: string;
/**
* Lightest color for backgrounds.
*
* @default '#E1F1FD'
*/
colorLightest?: string;
/**
* Border radius for UI elements.
*
* @default '0.5rem'
*/
borderRadius?: string;
/**
* Font family for the widget.
* All Google Fonts are supported and loaded from https://fonts.google.com/
*
* @default 'system-ui, sans-serif'
*/
font?: string;
};
export default ThemeConfig;
```
### Locale
The `locale` property allows you to set the language for the widget's interface. Supported values include:
| Language code | Language |
|-------------|----------|
| `en` | English |
| `nl` | Dutch |
| `fr` | French |
| `de` | German |
If no `locale` is provided, the widget will use the value of `outputLanguage` as the default locale.
### Microphone Label
The `microphoneLabel` property allows you to preselect a specific microphone device by its label. This is useful in scenarios where the mic selection is shown next to the quality test, so the view does not need to be duplicated.
This parameter is optional; if not provided, the widget will display the default microphone selection UI.
## Events
Widgets emit events to notify your application of certain actions. You can listen for these events using the `on` method:
```js
widget.on('loaded', () => {
console.log('Mic quality test widget loaded');
});
```
### Available Events
| Event Name | Description |
|------------|--------------------------------------|
| `loaded` | Emitted when the widget has loaded. |
## Complete Example
```html
Microphone Quality Test
```
---
Source: https://developers.squire.eu/reference
# Reference
Supporting details that apply across Squire products.
- [SDK changelog](https://developers.squire.eu/reference/sdk-changelog): Release notes for every SDK version.
- [Languages](https://developers.squire.eu/reference/languages): Supported input and output languages.
- [Microphones](https://developers.squire.eu/reference/microphones): Recommended hardware and the microphone store.
- [FHIR](https://developers.squire.eu/reference/fhir): Consultation data as FHIR resources.
- [Coding agents](https://developers.squire.eu/reference/coding-agents): Give Claude Code, Cursor or Copilot the docs and the SDK types.
- [Portal](https://developers.squire.eu/reference/portal): Manage API keys, environments and team access.
- [Microsoft Entra ID (SSO)](https://developers.squire.eu/reference/entra-id-sso): Authorize the Squire app in your Entra ID tenant.
- [Support](https://developers.squire.eu/reference/support): Reach the integrations team.
---
Source: https://developers.squire.eu/reference/sdk-changelog
# Changelog
This page lists the changes made to the Squire SDK, including new features, improvements, and bug fixes.
The Squire SDK follows [semver](https://semver.org/) versioning.
## Upgrading
To upgrade to the latest version of the Squire SDK, run the install command for your package manager:
**npm**
```bash
npm install @squirehealth/sdk@latest
```
**pnpm**
```bash
pnpm add @squirehealth/sdk@latest
```
**yarn**
```bash
yarn add @squirehealth/sdk@latest
```
## Releases
### 1.17.0 (2026-11-04)
- feat: Recording audio is streamed with a more efficient codec, which uses much less upload bandwidth. Browsers without codec support keep working as before.
- fix: The last moments of a recording are no longer cut off when it stops.
- fix: Stopping a recording while it is still starting now stops it cleanly and releases the microphone.
### 1.16.0 (2026-10-26)
- feat: Every summary now carries `content_format`: `plain` for plain text or `markdown` for rich text, or `null` when the consultation has no report. A report takes the format of the template it was generated from. The type is exported as `ContentFormat`, an open union so a format the installed SDK predates still passes through. See [Content format](https://developers.squire.eu/consultation/output#content-format).
- feat: `startRecording()` accepts a `contentFormat` alongside a `templateSchema`, which makes the custom template, and the reports generated from it, rich text (Markdown) or plain text. A new template defaults to `plain`; when omitted, an existing template keeps its format. Passing `contentFormat` without a `templateSchema` throws. See [Templates](https://developers.squire.eu/consultation/templates#content-format).
- fix: `splitSoap()` and `mergeSoap()` now return the summary in snake_case, like `getSummary()`, instead of camelCase.
### 1.15.0 (2026-09-15)
> **Note**
>
> **Type fix:** `Summary.data` is now typed `Episode[] | null`. The API has always been able to answer with
> `data: null`; the type declared otherwise, so `summary.data.map(...)` type-checked and then threw at
> runtime. Nothing changes at runtime. TypeScript now flags that code until it handles the `null` case,
> which is the bug it was hiding. Guard on `summary.data` before iterating, and read `report_status` for why
> it is `null`. See [Report status](https://developers.squire.eu/consultation/output#report-status).
- A recording now ends on any summary whose `report_status` is not `intermediate`, instead of only on `final`. A consultation with no report content arrives as a regular `summary-ready` event whose `data` is `null` and whose `report_status` says why. Nothing new to hook into: `summary-ready` remains the one event that ends a recording. Previously such a consultation left the SDK waiting forever, so the recording never finished and the microphone was never released.
- `report_status` gains the `not_generated` and `purged` states, which accompany a `null` `data`. A `final` or `intermediate` report can also carry a `null` `data` when it produced no structured content. See [Report status](https://developers.squire.eu/consultation/output#report-status).
- New `Squire.DATA_PURGED` error code (HTTP 410). `splitSoap()` and `mergeSoap()` reject with a `Squire.ApiError` carrying it once the consultation's transcript has been removed under a data retention policy; the report can no longer be regenerated, so the error is final rather than worth retrying. See [Purged data](https://developers.squire.eu/consultation/error-handling#purged-data).
- `Squire.ApiError#code` is now populated for error bodies that carry a code but no human-readable `detail`, where it was previously dropped.
### 1.14.0 (2026-08-20)
- New `user.getUsage()` method on the SDK instance to get the current usage per product for the signed-in user. See [Product usage](https://developers.squire.eu/consultation/product-usage).
- Failed API requests now reject with a `Squire.ApiError` carrying the response `status`, `code` and `detail`. Use the `Squire.CONSULTATION_QUOTA_EXCEEDED` code to detect a user who has used their full allowance for the current period (HTTP 402). See [API errors](https://developers.squire.eu/consultation/error-handling#api-errors).
- `startRecording()` now rejects on a failed consultation creation instead of throwing an unrelated error further down.
### 1.13.0 (2026-06-01)
- Support for Intake: schedule and manage patient intake forms via the `Intake` API
### 1.12.0 (2026-05-19)
- Optimized audio streaming: audio is now transmitted as 16-bit PCM (int16), halving network bandwidth with no impact on transcription quality.
### 1.11.0 (2026-04-14)
- Report length: optional `writingStyle` (`brief`, `balanced`, `detailed`) on `startRecording`; when omitted, behavior matches earlier releases (user default).
- `getDefaultWritingStyle()` on the `Squire` instance returns the authenticated user's default report length from the API.
- `setDefaultWritingStyle(style)` on the `Squire` instance updates that default for the authenticated user.
- [internal]: changed bundler to tsdown. This change is backwards compatible, and should have no impact on the usage. In case you notice issues, do not hesitate to contact us for help.
### 1.10.0 (2026-02-11)
- Multi-SOAP support: `splitSoap()` and `mergeSoap()` methods on the `Consultation` object to split a consultation into multiple SOAP notes or merge them back together
- New `getSummary()` method on the `Consultation` object to retrieve a consultation summary
- New `squire.consultation(id)` method to create a `Consultation` instance from an existing consultation ID
- Deprecate `getConsultationSummary()` in favor of `consultation.getSummary()`
### 1.9.0 (2026-01-27)
- Expose state change events via `state-change` event
### 1.8.0 (2025-10-27)
- Introduction of Widgets
- Use of AudioWorklet for improved audio processing and reduced latency, with fallback for unsupported browsers
- Patch `1.8.1`: Await `startRecording` until session is started, request retry logic on failures (e.g. network issues, server errors), `logLevel` param to control logging verbosity
### 1.7.0 (2025-10-08)
- New `getConsultationSummary` method to retrieve a consultation summary by its ID
- The `startRecording` method now returns the `Consultation` object, which includes the `id`
- Support for new template `specialist_general_free_text_api`
- Patch `1.7.1`: Collect microphone technical stats
### 1.6.0 (2025-08-25)
- Support for passing `templateSchema` in `startRecording`
- Patch `1.6.2`: Fix for improved audio buffering
- Patch `1.6.4`: Enforce starting one recording at a time in the SDK to prevent users from starting multiple recordings simultaneously (e.g. when clicking the start button multiple times)
### 1.5.0 (2025-08-15)
- Add support for the Squire microphone
- Improve start recording speed on lower quality connections
- Add JSDoc info for public methods
### 1.4.0 (2025-07-04)
- Add support for `pauseRecording` and `resumeRecording` methods
### 1.3.0 (2025-06-19)
- Support for live intermediate report responses
### 1.2.0 (2025-05-28)
- Terms & conditions management (viewing, accepting)
### 1.1.0 (2025-04-25)
- Allow specifying the template ID when generating a consultation report. (e.g. for specialists)
- Expose `IBUI` code for diagnosis
### 1.0.0 (2025-02-17)
- Initial release of the Squire SDK
---
Source: https://developers.squire.eu/reference/languages
# Languages
Squire supports multiple languages, and offers translations between spoken language and report language out of the box.
## Input languages
The `inputLanguage` defines the language spoken during the consultation. Squire supports the following languages:
| Language | Code |
|----------|------|
| Auto-detect | `auto` |
| Dutch | `nl` |
| English | `en` |
| French | `fr` |
| German | `de` |
> **Note**
>
> Auto-detection (`auto`) identifies the spoken language during consultations. If you know the input language in advance, you can optimize the experience by providing the specific language code directly. This is especially recommended for shorter consultations to have a higher accuracy.
## Output languages
The `outputLanguage` defines the language in which the report is generated. Squire supports the following languages:
| Language | Code |
|----------|------|
| Dutch | `nl` |
| English | `en` |
| French | `fr` |
| German | `de` |
---
Source: https://developers.squire.eu/reference/microphones
# Microphones
The Squire SDK supports all microphones as detected by the browser. However, we recommend using high-quality microphones for the best results. Especially in environments where the consultation happens at a distance from the microphone, a good microphone can significantly improve audio quality.
## Squire Microphone
The Squire Microphone is designed to work seamlessly with the Squire SDK, providing optimal audio quality for consultations. It can be purchased by healthcare professionals and institutions from the [Squire webshop](https://shop.squire.eu/).
_Figure: The Squire Microphone. The Squire Microphone_
## Embedding
To embed the microphone store on your website, you can use the following code snippet. This code integrates with the Squire webshop to display and sell Squire microphones directly from your site.
```js
```
---
Source: https://developers.squire.eu/reference/fhir
# FHIR interface
For structured data, Squire offers a FHIR interface that allows you to receive FHIR resources. These include:
- Observations made by the healthcare provider
- Conditions assessed during the consultation
- Procedures performed
- Medications prescribed
> **Note**
>
> The granularity of which details are included per resources can vary depending on what is discussed during the consultation.
## FHIR bundle
A collection of FHIR resources from a consultation is exposed as a FHIR bundle.
```json
{
"resourceType": "Bundle",
"type": "collection",
"entry": [
{
// FHIR resource 1
},
{
// FHIR resource 2
}
]
}
```
## Resources
### Observation
Observation resources are exposed for measurements and other observations made during a consultation. The following is an example of a body weight observation:
```json
{
"resourceType": "Observation",
"status": "final",
"code": {
"coding": [
{
"system": "http://loinc.org",
"code": "29463-7",
"display": "Body weight"
}
],
"text": "Body weight"
},
"subject": {
"reference": "Patient/example"
},
"effectiveDateTime": "2025-01-01T10:00:00+00:00",
"performer": [
{
"reference": "Practitioner/example",
"display": "Dr. John Smith"
}
],
"valueQuantity": {
"value": 68,
"unit": "kg",
"system": "http://unitsofmeasure.org",
"code": "kg"
}
}
```
### Condition
When conditions are assessed during a consultation, they are exposed as condition resources. The following is an example of a hypertension condition:
```json
{
"resourceType": "Condition",
"code": {
"coding": [
{
"system": "http://snomed.info/sct",
"code": "38341003",
"display": "Hypertension"
}
],
"text": "Hypertension"
},
"subject": {
"reference": "Patient/example"
},
"encounter": {
"reference": "Encounter/example"
},
"onsetDateTime": "2025-01-01",
"recordedDate": "2025-01-01",
"recorder": {
"reference": "Practitioner/example",
"display": "Dr. John Smith"
}
}
```
### Procedure
When procedures are done during the consultation, they are exposed as procedure resources. The following is an example of a procedure:
```json
{
"resourceType": "Procedure",
"status": "completed",
"category": {
"coding": [
{
"system": "http://snomed.info/sct",
"code": "103693007",
"display": "Diagnostic procedure"
}
],
"text": "Minor surgical procedure"
},
"subject": {
"reference": "Patient/example"
},
"performedPeriod": {
"start": "2025-01-01T11:00:00+01:00",
"end": "2025-01-01T11:30:00+01:00"
},
"encounter": {
"reference": "Encounter/example"
},
"bodySite": [
{
"coding": [
{
"system": "http://snomed.info/sct",
"code": "83738005",
"display": "Finger structure"
}
],
"text": "Right index finger"
}
],
"outcome": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/procedure-outcome",
"code": "successful",
"display": "Successful"
}
],
"text": "Wound cleaned and sutured successfully"
},
"followUp": [
{
"text": "Stitch removal in 10 days, monitor for infection"
}
]
}
```
### MedicationRequest
When medications are prescribed during a consultation, they are exposed as medication request resources. The following is an example of a paracetamol prescription:
```json
{
"resourceType": "MedicationRequest",
"status": "active",
"intent": "order",
"medicationCodeableConcept": {
"coding": [
{
"system": "https://www.ehealth.fgov.be/standards/reference/fhir/CodeSystem/cnk",
"code": "1234567",
"display": "Paracetamol EG 1g Tablet"
}
]
},
"subject": {
"reference": "Patient/example"
},
"authoredOn": "2025-01-01",
"dosageInstruction": [
{
"text": "Take 1 tablet orally every 6 hours as needed for pain",
"timing": {
"repeat": {
"frequency": 4,
"period": 1,
"periodUnit": "d"
}
},
"route": {
"coding": [
{
"system": "http://snomed.info/sct",
"code": "26643006",
"display": "Oral route"
}
]
},
"doseAndRate": [
{
"doseQuantity": {
"value": 1,
"unit": "tablet",
"system": "http://unitsofmeasure.org",
"code": "{tbl}"
}
}
]
}
]
}
```
## Country-specific resources
Squire supports country-specific implementations for FHIR resources. Currently, Squire offers extensions for eHealth Belgium FHIR Resources.
---
Source: https://developers.squire.eu/reference/coding-agents
# Coding agents
These docs are built to be read by coding agents. Hand yours the Markdown and a short rules file. It will then use the real method names, endpoints and token flow instead of guessing at them.
## Provide the docs
Add `.md` to any page URL to get that page as Markdown. [`/llms.txt`](https://developers.squire.eu/llms.txt) lists every page in the docs. [`/llms-full.txt`](https://developers.squire.eu/llms-full.txt) holds all of it in one file.
If your agent can fetch URLs, give it `/llms.txt`. If it cannot, paste `llms-full.txt`. For a single page, use the Copy page button at the top.
## Write down the rules
Put this in the file your agent reads at startup:
```md filename="AGENTS.md"
## Squire (updated 2026-09-07)
- Squire covers consultation notes, dictation, medical coding and patient intake.
- Docs: https://developers.squire.eu/llms.txt. Any page is Markdown at `.md`.
Read the page before writing Squire code. Do not guess method or endpoint names.
- In the client, use the `@squirehealth/sdk` package (private registry
https://pkg.squire.eu/npm/) or the prebuilt widgets. Types ship with the package.
- On the server, use the REST API at https://api.squire.eu. The schema is at
https://app.squire.eu/api/v1/external/schema/redoc/
- The API key is server-side only. The client gets an access token, nothing else.
- Test against staging. Never use real audio, transcripts or reports as test data.
- If the date above is more than a few months old, read
https://developers.squire.eu/reference/sdk-changelog.md before relying on this section.
```
Update the date whenever you revise this section. It tells the agent how much to trust what it reads.
| Tool | File |
|------|------|
| Claude Code | `CLAUDE.md` |
| GitHub Copilot | `.github/copilot-instructions.md` |
| Cursor | `.cursor/rules/*.mdc` |
| OpenAI Codex | `AGENTS.md` |
| Gemini CLI | `GEMINI.md` |
Keep one file and point the rest at it. A `CLAUDE.md` containing `@AGENTS.md` inlines it.
## Good to know
Install the SDK yourself. It needs the registry token from the [Portal](https://developers.squire.eu/reference/portal), so an agent in a sandbox cannot do it.
> **Warning**
>
> No patient data. Consultation audio, transcripts and reports do not belong in a prompt
> or an indexed workspace. Build against staging with test recordings.
---
Source: https://developers.squire.eu/reference/portal
# Portal
The Portal is your central hub for managing and monitoring your integration with Squire. Different roles have access to specific functionalities designed for their needs.
- **Product Managers**: Access usage statistics and user engagement metrics
- **Support Teams**: Manage cases, view logs, and handle troubleshooting
- **Developers**: Manage API credentials, environments, and monitor performance
## Getting Started
1. [Log in](https://portal.squire.eu/) to the portal using your personal credentials
2. Invite team members and set their respective role
3. Contact support if you need additional access or have questions
## Managing API keys
Developers can manage API keys within the Portal. API keys are used to create user sessions for initializing the Squire SDK.
### Navigate to API Keys
Go to the API Keys page in the settings section of the portal.
_Figure: API key management in the Portal. API keys page in the Squire Portal_
### Create a new API key
Click the `Create API Key` button in the top right corner, and fill in the required information:
- Environment
- `staging`: For testing purposes
- `production`: For usage with real users
- Key name: internal name for identification purposes
### Securely store the API key
Your API key should be stored as secret. It's a private key and should never be exposed in any client.
If you disclose your key by any accident, create a new one and revoke access for the old one.
---
Source: https://developers.squire.eu/reference/entra-id-sso
# Microsoft Entra ID (SSO)
Your organization can let users sign in to Squire with their Microsoft work account. Activating the connection takes one step, performed once by a Global Administrator of your Entra ID tenant. This page is written for the IT team that performs it.
## How it works
Squire uses a multi-tenant app registration, so there is nothing for you to set up or exchange:
- No Enterprise Application to create manually, and no SAML metadata to exchange.
- After authorization, Squire is added automatically to the Enterprise Applications in your tenant.
- Your existing security, MFA and Conditional Access policies keep applying in full.
- Squire requests only minimal, delegated permissions (see below).
## Requirements
- An account with the Global Administrator role in your Microsoft Entra ID tenant.
- The authorization is a one-time, organization-wide action. Individual users are not prompted for consent afterwards.
## Requested permissions
Squire requests only the permission needed to sign a user in and link their account. No access is requested to mailboxes, files or any other data.
| Permission | Type | Purpose |
|---|---|---|
| Sign in and read user profile (`User.Read`) | Delegated | Sign the user in and read the basic profile (name, email address) to link the account. |
## Grant the authorization
### Open the consent link
While signed in as a Global Administrator, open the Microsoft consent page:
[Grant admin consent](https://login.microsoftonline.com/common/adminconsent?client_id=87b4a2e6-9a0c-4d46-b227-ebf54be03bbf&redirect_uri=https://app.squire.eu/accounts/microsoft/login/callback/)
Sign in with a Global Administrator account if you are prompted to.
### Review and accept
Check the Microsoft consent screen, which lists Squire Health as the publisher and `User.Read` as the requested permission, then click `Accept`.
### Confirm the result
You are redirected back to Squire with the confirmation "Microsoft consent received". You can close the window.
## Result
- Squire appears under Enterprise Applications in Entra ID.
- Users in your organization can sign in to Squire through Microsoft Entra ID SSO.
---
Source: https://developers.squire.eu/reference/support
# Support
We're here to help you succeed with Squire. Here are the various ways to get support:
## Documentation
Our documentation covers everything from basic setup to advanced features. Start with [Get started](https://developers.squire.eu/get-started) for the fastest way to get up and running.
## Direct Support
### Email Support
Contact our technical support team at integrations@squire.eu.