> ## Documentation Index
> Fetch the complete documentation index at: https://docs.samplehc.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Calling the Sample API

> Using the SampleHC API

## Overview

The SampleHC API is a RESTful API that allows you to interact with workflows. It is used to start, stop, and manage workflows, as well as to retrieve workflow data.

## Client

<Note>
  Workflows created before the client was released may not have the client installed. Please refer to the latest template to see how the client is set up.
</Note>

<Note>
  If any methods are different/missing from the SDK, you may need to update the SDK version in `requirements.txt` to the latest version.
</Note>

A [Python SDK](https://pypi.org/project/samplehc/) is available for ease of calling the [SampleHC API](/api-reference).

By default, a client manager is included in the new workflow template in `src/client_manager.py` that automatically configures the client with the correct backend URL and API key.

Here is a minimal example of how to use the client manager to initiate a client and call the API in a workflow.

<CodeGroup>
  ```python src/workflow.py theme={null}
  from workflows_py.workflow import ScreenStep, Step, Workflow
  from client_manager import SampleHealthcareClient

  def trigger_reasoning(ctx):
      documents = ctx.get_start_data()["documents"]
      client = SampleHealthcareClient()
      return client.v2.documents.legacy.reason(
          documents=documents,
          task={
              "id": "reasoning-task-1",
              "description": "Extract key information from the document",
              "label": "Information Extraction",
              "type": "reasoning",
          },
      ).async_result_id

  workflow = Workflow().then(
    Step("trigger-reasoning", trigger_reasoning)
  ).then(
    ScreenStep(
      "reasoning-screen",
      screen_path="./screens/legacy-document-reasoning-screen.tsx",
      get_props=lambda ctx: {"resultId": ctx.get_step_result("trigger-reasoning")},
    )
  )
  ```
</CodeGroup>

## Common Operations

The sections below cover the API operations that come up most often in
workflows. Refer to the [SampleHC API Reference](/api-reference) for the full
list of endpoints and parameters.

### Extracting Data from Documents

The `extract` method runs a structured extraction over one or more documents.
You provide a prompt and a JSON schema describing the output you want, and the
extraction runs asynchronously — so pair it with
[suspend and resume](/workflows/suspend-resume):

```python theme={null}
def extract_patient_info(ctx):
    if ctx.resume_data:
        return ctx.resume_data  # The extraction result, matching the schema

    documents = ctx.get_start_data()["documents"]
    client = SampleHealthcareClient()

    result = client.v2.documents.extract(
        documents=documents,
        prompt="Extract the patient's demographic information from these documents.",
        response_json_schema={
            "type": "object",
            "properties": {
                "patient_name": {"type": "string"},
                "date_of_birth": {"type": "string", "description": "YYYY-MM-DD"},
                "member_id": {"type": "string"},
            },
            "required": ["patient_name"],
        },
    )

    client.v2.workflow_runs.resume_when_complete(
        async_result_id=result.async_result_id,
    )
    ctx.suspend_fn({"type": "extraction", "asyncResultId": result.async_result_id})
```

When the workflow resumes, `ctx.resume_data` contains the extraction output
matching your `response_json_schema`.

Optional parameters:

* **model**: The extraction model to use.
* **reasoning\_effort**: `"low"`, `"medium"`, or `"high"` — controls how much
  reasoning the extraction applies.
* **priority**: `"interactive"` (default) or `"non-interactive"`. Use
  `"non-interactive"` for scheduled or bulk extractions where no user is
  waiting, so interactive workflows are processed first. The same option is
  available on `classify`.

<Note>
  `extract` is the recommended method for new workflows. It supersedes the
  `legacy.reason` and `legacy.extract` methods you may see in older examples.
</Note>

### Generating Documents from Templates

Document templates (managed in the Sample dashboard) let workflows produce
consistent letters and forms. A common flow is to render the template to
editable content, let a user review it in a screen, and then generate the
final PDF:

```python theme={null}
def render_letter(ctx):
    client = SampleHealthcareClient()
    rendered = client.v2.documents.templates.render_document(
        slug="patient-outreach-letter",
        variables={
            "patient_name": ctx.get_start_data()["patient_name"],
            "visit_date": ctx.get_start_data()["visit_date"],
        },
    )
    # Pass to a rich text editor screen for review
    return {"document_body": rendered.body}

def generate_final_letter(ctx):
    if ctx.resume_data:
        return ctx.resume_data  # Contains the generated document

    edited_body = ctx.get_step_result("review-letter")["document_body"]
    client = SampleHealthcareClient()

    response = client.v2.documents.templates.generate_document_async(
        type="document",
        slug="patient-outreach-letter",
        document_body=edited_body,
        file_name="Outreach_Letter.pdf",
    )

    client.v2.workflow_runs.resume_when_complete(
        async_result_id=response.async_result_id,
        extra_body={"priority": "interactive"},
    )
    ctx.suspend_fn({
        "type": "screen",
        "screenPath": "./screens/loading-screen.tsx",
        "props": {"text": "Generating document..."},
    })
```

On resume, `ctx.resume_data["document"]` contains the generated document's
`id` and file name, ready to attach to an email or combine with other
documents. To generate directly from template variables without a review step,
pass `variables` to `generate_document_async` instead of `document_body`.

### Working with Documents

Documents are referenced throughout the API by their file metadata ID (the
`id` field, e.g. `fmd_...`) together with a `fileName`. Common utilities:

<CodeGroup>
  ```python Upload theme={null}
  import requests

  def upload_report(ctx, file_content):
      client = SampleHealthcareClient()

      presigned = client.v2.documents.presigned_upload_url(
          file_name="report.pdf",
          mime_type="application/pdf",
      )

      put_response = requests.put(
          presigned.presigned_url,
          data=file_content,
          headers={"Content-Type": "application/pdf"},
      )
      put_response.raise_for_status()

      # The document is now available under this ID
      return {"document_id": presigned.id}
  ```

  ```python Combine theme={null}
  def combine_package(ctx):
      client = SampleHealthcareClient()
      response = client.v2.documents.combine(
          combined_file_name="Complete_Package.pdf",
          documents=[
              {"id": doc["id"], "fileName": doc["fileName"]}
              for doc in ctx.get_step_result("collect-documents")
          ],
      )
      # Pages appear in the order the documents are listed
      return {
          "document": {
              "id": response.document.id,
              "fileName": response.document.file_name,
          }
      }
  ```

  ```python Unzip theme={null}
  def unzip_upload(ctx):
      client = SampleHealthcareClient()
      document = ctx.get_start_data()["document"]
      result = client.v2.documents.unzip(document_id=document["id"])
      return {"documents": [doc.to_dict() for doc in result.documents]}
  ```

  ```python CSV theme={null}
  def build_report(ctx):
      client = SampleHealthcareClient()

      # Generate a CSV document from a list of rows
      response = client.v2.documents.generate_csv(
          file_name="daily_report.csv",
          rows=[
              {"order_id": "12345", "status": "complete"},
              {"order_id": "12346", "status": "pending"},
          ],
      )
      csv_document_id = response.document.id

      # Read a CSV document back as rows
      content = client.v2.documents.retrieve_csv_content(csv_document_id)
      return {"row_count": len(content.data)}
  ```
</CodeGroup>

Other useful utilities:

* **retrieve\_metadata(document\_id)**: Get a document's file name and MIME type.
* **formats.create\_pdf(document\_id, file\_name, mime\_type)**: Convert an image
  document (PNG, JPEG) to a PDF.
* **transform\_json\_to\_html(json)**: Render a JSON object as HTML — useful for
  displaying extraction results in screens or emails.

### Sending Communications

Workflows can send emails, faxes, and physical letters. Attachments reference
documents by ID:

<CodeGroup>
  ```python Email theme={null}
  def send_report_email(ctx):
      client = SampleHealthcareClient()
      csv_document_id = ctx.get_step_result("build-report")["document_id"]

      client.v2.communication.send_email(
          to="team@example.com",
          subject="Daily Processing Report",
          body="Hi,\n\nAttached is today's processing report.",
          attachments=[{"id": csv_document_id}],
          attach_as_files=True,
          enable_encryption=True,
      )
      return {"sent": True}
  ```

  ```python Fax theme={null}
  def fax_package(ctx):
      client = SampleHealthcareClient()
      document = ctx.get_step_result("combine-package")["document"]

      client.v2.communication.send_fax(
          document={"id": document["id"], "file_name": document["fileName"]},
          to="555-555-0100",
      )
      return {"sent": True}
  ```

  ```python Letter theme={null}
  def mail_letter(ctx):
      client = SampleHealthcareClient()
      document = ctx.get_step_result("generate-final-letter")["document"]

      client.v2.communication.send_letter(
          document={"id": document["id"], "file_name": document["fileName"]},
          to_address={
              "name": "Medical Records Department",
              "address": {
                  "street_lines": ["123 Main St", "Suite 100"],
                  "city": "Springfield",
                  "state": "IL",
                  "zip_code": "62701",
              },
          },
          from_address={
              "name": "Example Health",
              "address": {
                  "street_lines": ["456 Oak Ave"],
                  "city": "Springfield",
                  "state": "IL",
                  "zip_code": "62702",
              },
          },
      )
      return {"sent": True}
  ```
</CodeGroup>

<Tip>
  Use `enable_encryption=True` on emails that contain protected health
  information.
</Tip>

### Querying Connected Systems

Integrations configured in the Sample dashboard are addressed by their
integration slug:

<CodeGroup>
  ```python Snowflake theme={null}
  def fetch_open_orders(ctx):
      client = SampleHealthcareClient()
      rows = client.v2.integrations.snowflake.query(
          slug="snowflake",
          query="SELECT order_id, status FROM orders WHERE status = 'open' LIMIT 100",
      )
      return {"orders": rows}
  ```

  ```python Salesforce SOQL theme={null}
  def fetch_new_cases(ctx):
      client = SampleHealthcareClient()
      records = client.v2.integrations.salesforce.run_soql_query(
          slug="salesforce",
          query="SELECT Id, Subject, Status FROM Case WHERE Status = 'New'",
      )
      return {"cases": records}
  ```

  ```python Salesforce CRUD theme={null}
  def create_case(ctx):
      client = SampleHealthcareClient()
      result = client.v2.integrations.salesforce.run_crud_action(
          slug="salesforce",
          crud_action_type="create",
          resource_type="Case",
          resource_body={
              "Subject": "Insurance information needed",
              "Status": "Open",
          },
      )
      return {"case_id": result.get("id")}
  ```
</CodeGroup>

See [Integrations](/integrations/salesforce) for how to connect these systems
to your organization.

### Running SQL

Use `sql_execute` to read and write your Sample [database](/guides/database)
from workflow steps:

```python theme={null}
def record_outcome(ctx):
    client = SampleHealthcareClient()
    result = client.v1.sql_execute(
        query="SELECT * FROM orders WHERE status = $1 LIMIT 10",
        params=["pending"],
    )
    return {"orders": result.rows}
```

See the [database guide](/guides/database) for placeholders, error handling,
and the table editor.

## Gotchas

Our API generally uses `camelCase` for parameter names. However, for ease of use, the SDK also converts parameters to `snake_case` when calling the API.

This means \*\* BOTH \*\* `camelCase` and `snake_case` are supported for parameter names when using the `samplehc` library.

For example, the [document metadata endpoint](/api-reference/document/document-metadata) has a parameter called `fileName` which is converted to `file_name` in the SDK.

```python theme={null}
client = SampleHealthcareClient()
res = client.v2.documents.retrieve_metadata(
    document_id="fmd_xxxxxxxxxxx",
)

# This is valid
print(res.file_name)

# This is ALSO valid
print(res.fileName)
```

Refer to the [SampleHC API Reference](/api-reference) for more details on the available endpoints, required parameters, and the expected responses from the SDK.
