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

# Forms, Payments & Notes Workflow

> Save a payment method, submit a form (and generate a note template from it), create a note pre-filled from the answers, then create an itemized charge and collect payment in the embedded component.

# Forms, Payments & Notes Workflow

This guide chains the Forms, Notes, and Billing APIs into one intake-to-checkout integration. A patient fills out a form (which saves a card on file), that form becomes a note template, a provider's note pre-fills from the patient's answers, and you collect payment on an itemized charge through the embedded payment component.

## Overview

1. **Create a form** and **convert it into a note template** so the note layout matches the form.
2. **Save a payment method** for the patient (or collect one through the form's Payment Methods block).
3. **Submit the form** for the patient — answers flow into the patient record.
4. **Create a note pre-filled** with the patient's submitted answers.
5. **Create a charge** with itemized line items that reference catalog items.
6. **Collect payment** through the embedded payment component.

All amounts are in **cents**. Every request needs the `TENANT` and `API-KEY` headers.

## Step 1: Create a form and its note template

Create the form the patient will fill out with [Create Form](/api-reference/provider/create-form), then convert it into a note template with [Create Note Template From Form](/api-reference/provider/create-note-template-from-form). The conversion flattens the form's blocks and questions into template fields (signature, payment, disclaimer, statement, and document questions are skipped).

<CodeGroup>
  ```bash theme={null}
  # Create the form
  curl -X POST "https://api.decodahealth.com/forms" \
       -H "API-KEY: YOUR_API_KEY" \
       -H "TENANT: YOUR_TENANT" \
       -H "Content-Type: application/json" \
       -d '{ "name": "New Patient Intake", "blocks": [] }'

  # Convert it into a note template (form_id from the response above)
  curl -X POST "https://api.decodahealth.com/notes/templates/from-form/form_xxx" \
       -H "API-KEY: YOUR_API_KEY" \
       -H "TENANT: YOUR_TENANT" \
       -H "Content-Type: application/json" \
       -d '{ "includeBlockNames": true }'
  ```

  ```python theme={null}
  import requests

  BASE_URL = "https://api.decodahealth.com"
  headers = {
      "API-KEY": "YOUR_API_KEY",
      "TENANT": "YOUR_TENANT",
      "Content-Type": "application/json",
  }

  form = requests.post(
      f"{BASE_URL}/forms",
      headers=headers,
      json={"name": "New Patient Intake", "blocks": []},
  ).json()
  form_id = form["id"]

  template = requests.post(
      f"{BASE_URL}/notes/templates/from-form/{form_id}",
      headers=headers,
      json={"includeBlockNames": True},
  ).json()
  template_id = template["id"]
  ```

  ```typescript theme={null}
  import ky from "ky";

  const BASE_URL = "https://api.decodahealth.com";
  const headers = { "API-KEY": "YOUR_API_KEY", TENANT: "YOUR_TENANT" };

  const form = await ky.post(`${BASE_URL}/forms`, {
    headers,
    json: { name: "New Patient Intake", blocks: [] },
  }).json<any>();
  const formId = form.id;

  const template = await ky.post(`${BASE_URL}/notes/templates/from-form/${formId}`, {
    headers,
    json: { includeBlockNames: true },
  }).json<any>();
  const templateId = template.id;
  ```
</CodeGroup>

<Info>
  Build the form's `blocks` with Demographics, Medical History, and Measurement fields where you want answers to flow into the patient record — those are the fields that pre-fill the note later. See [Form Structure Reference](/modules/forms/form-structure) for block and question types, and the [Form Editor](/modules/forms#create-a-form) if you'd rather build the form in the console and just reference its ID here.
</Info>

## Step 2: Save a payment method

Collect a card for the patient with [Create Payment Method](/api-reference/provider/create-payment-method). The `patient_id` goes in the query string. You can also collect the card inside the form itself by adding a **Payment Methods** block — see [Payment Method Collection](/modules/forms#advanced-configuration).

<CodeGroup>
  ```bash theme={null}
  curl -X POST "https://api.decodahealth.com/user/patient/payment-methods/create?patient_id=pat_xxx" \
       -H "API-KEY: YOUR_API_KEY" \
       -H "TENANT: YOUR_TENANT" \
       -H "Content-Type: application/json" \
       -d '{ "token": "PAYMENT_PROCESSOR_TOKEN" }'
  ```

  ```python theme={null}
  payment_method = requests.post(
      f"{BASE_URL}/user/patient/payment-methods/create",
      headers=headers,
      params={"patient_id": "pat_xxx"},
      json={"token": "PAYMENT_PROCESSOR_TOKEN"},
  ).json()
  ```

  ```typescript theme={null}
  const paymentMethod = await ky.post(
    `${BASE_URL}/user/patient/payment-methods/create`,
    {
      headers,
      searchParams: { patient_id: "pat_xxx" },
      json: { token: "PAYMENT_PROCESSOR_TOKEN" },
    },
  ).json<any>();
  ```
</CodeGroup>

<Info>
  See the [Create Payment Method](/api-reference/provider/create-payment-method) reference for the exact request body your processor integration expects.
</Info>

## Step 3: Submit the form

Submit the patient's answers with [Patient Form Submission](/api-reference/provider/patient-form-submission). Each entry in `blocks` carries a `blockType` (`DEMOGRAPHICS`, `MEDICAL_HISTORY`, `PAYMENT_METHODS`, `INSURANCE`, or `DYNAMIC`). Set `isCompleteSubmission` to `true` for a finished submission. Answers mapped to patient-record fields save to the chart automatically.

<CodeGroup>
  ```bash theme={null}
  curl -X PUT "https://api.decodahealth.com/forms/form_xxx/submit" \
       -H "API-KEY: YOUR_API_KEY" \
       -H "TENANT: YOUR_TENANT" \
       -H "Content-Type: application/json" \
       -d '{
         "patientId": "pat_xxx",
         "isCompleteSubmission": true,
         "blocks": []
       }'
  ```

  ```python theme={null}
  requests.put(
      f"{BASE_URL}/forms/{form_id}/submit",
      headers=headers,
      json={
          "patientId": "pat_xxx",
          "isCompleteSubmission": True,
          "blocks": [],  # SubmittedDemographicsBlock, SubmittedDynamicBlock, etc.
      },
  )
  ```

  ```typescript theme={null}
  await ky.put(`${BASE_URL}/forms/${formId}/submit`, {
    headers,
    json: {
      patientId: "pat_xxx",
      isCompleteSubmission: true,
      blocks: [], // SubmittedDemographicsBlock, SubmittedDynamicBlock, etc.
    },
  });
  ```
</CodeGroup>

## Step 4: Create a pre-filled note

Fetch the patient's pre-filled answers for the template with [Get Prefilled Answers](/api-reference/provider/get-prefilled-answers), then pass them straight into [Create Note](/api-reference/provider/create-note). The prefill response returns each answer keyed by `questionId`, in the exact shape `answers` expects.

<CodeGroup>
  ```bash theme={null}
  # Fetch pre-filled answers
  curl -X GET "https://api.decodahealth.com/notes/templates/tpl_xxx/prefill/pat_xxx" \
       -H "API-KEY: YOUR_API_KEY" \
       -H "TENANT: YOUR_TENANT"

  # Create the note with those answers
  curl -X POST "https://api.decodahealth.com/notes/create" \
       -H "API-KEY: YOUR_API_KEY" \
       -H "TENANT: YOUR_TENANT" \
       -H "Content-Type: application/json" \
       -d '{
         "patientId": "pat_xxx",
         "providerId": "prov_xxx",
         "answers": [
           { "questionId": "q_xxx", "data": { "value": "..." } }
         ]
       }'
  ```

  ```python theme={null}
  prefill = requests.get(
      f"{BASE_URL}/notes/templates/{template_id}/prefill/pat_xxx",
      headers=headers,
  ).json()

  answers = [
      {"questionId": a["questionId"], "data": a["data"]}
      for a in prefill["prefilledAnswers"]
  ]

  note = requests.post(
      f"{BASE_URL}/notes/create",
      headers=headers,
      json={
          "patientId": "pat_xxx",
          "providerId": "prov_xxx",
          "template": template,   # from Step 1
          "answers": answers,
      },
  ).json()
  ```

  ```typescript theme={null}
  const prefill = await ky.get(
    `${BASE_URL}/notes/templates/${templateId}/prefill/pat_xxx`,
    { headers },
  ).json<any>();

  const answers = prefill.prefilledAnswers.map((a: any) => ({
    questionId: a.questionId,
    data: a.data,
  }));

  const note = await ky.post(`${BASE_URL}/notes/create`, {
    headers,
    json: {
      patientId: "pat_xxx",
      providerId: "prov_xxx",
      template, // from Step 1
      answers,
    },
  }).json<any>();
  ```
</CodeGroup>

**Prefill response:**

```json theme={null}
{
  "templateId": "tpl_xxx",
  "patientId": "pat_xxx",
  "prefilledAnswers": [
    { "questionId": "q_weight", "data": { "value": 165 }, "source": "Today's Measurement" },
    { "questionId": "q_allergies", "data": { "values": ["Penicillin"] }, "source": "Patient Record" }
  ]
}
```

<Info>
  Only questions mapped to the patient chart (demographics, medical history, and same-day measurements) come back pre-filled. Weight and height only pre-fill when a measurement was recorded the same day. Custom free-text questions convert to empty note fields — fill those in the note itself or with [AI Scribe](/modules/notes/ai-scribe).
</Info>

## Step 5: Create an itemized charge

Create your catalog items once with [Create Item](/api-reference/provider/create-item), then reference each item's `id` as `itemId` on the charge's line items. Build the charge with [Create Charge](/api-reference/provider/create-charge) — set `totalOutstanding` to the sum of the line items minus any discounts.

<CodeGroup>
  ```bash theme={null}
  # Create a catalog item (reusable across charges)
  curl -X POST "https://api.decodahealth.com/inventory/items/create" \
       -H "API-KEY: YOUR_API_KEY" \
       -H "TENANT: YOUR_TENANT" \
       -H "Content-Type: application/json" \
       -d '{ "name": "Consultation", "price": 10000 }'

  # Create the charge, linking line items to the catalog item
  curl -X POST "https://api.decodahealth.com/billing/payment-terminal/charge/create" \
       -H "API-KEY: YOUR_API_KEY" \
       -H "TENANT: YOUR_TENANT" \
       -H "Content-Type: application/json" \
       -d '{
         "patientId": "pat_xxx",
         "totalOutstanding": 8500,
         "items": [
           {
             "itemId": "item_xxx",
             "name": "Consultation",
             "quantity": 1,
             "price": 10000,
             "discountAmount": 1500
           }
         ]
       }'
  ```

  ```python theme={null}
  item = requests.post(
      f"{BASE_URL}/inventory/items/create",
      headers=headers,
      json={"name": "Consultation", "price": 10000},
  ).json()

  charge = requests.post(
      f"{BASE_URL}/billing/payment-terminal/charge/create",
      headers=headers,
      json={
          "patientId": "pat_xxx",
          "totalOutstanding": 8500,
          "items": [
              {
                  "itemId": item["id"],
                  "name": "Consultation",
                  "quantity": 1,
                  "price": 10000,
                  "discountAmount": 1500,
              }
          ],
      },
  ).json()
  charge_id = charge["id"]
  ```

  ```typescript theme={null}
  const item = await ky.post(`${BASE_URL}/inventory/items/create`, {
    headers,
    json: { name: "Consultation", price: 10000 },
  }).json<any>();

  const charge = await ky.post(
    `${BASE_URL}/billing/payment-terminal/charge/create`,
    {
      headers,
      json: {
        patientId: "pat_xxx",
        totalOutstanding: 8500,
        items: [
          {
            itemId: item.id,
            name: "Consultation",
            quantity: 1,
            price: 10000,
            discountAmount: 1500,
          },
        ],
      },
    },
  ).json<any>();
  const chargeId = charge.id;
  ```
</CodeGroup>

<Info>
  Already have a cart? [Convert Cart to Charge](/api-reference/provider/convert-cart-to-charge) is an alternative that carries the cart's items and discounts onto the charge. See [Payment Embed: Itemized Charges](/api-reference/guides/embed-payment-itemized-charges) for that path.
</Info>

## Step 6: Collect payment in the embedded component

Point the embedded payment component at the charge. The embed calls [Create Embed Payment Config](/api-reference/provider/create-embed-payment-config) with the `charge_id`, shows the full itemized breakdown, and applies the payment to the existing charge — no duplicate charge is created.

```html theme={null}
<iframe
  src="https://app.decodahealth.com/your-tenant/embed/pay/pat_xxx?charge_id=chg_xxx&allowedMethods=CARD"
  width="100%"
  height="500"
  allow="payment"
  style="border: none; border-radius: 8px;"
></iframe>
```

Listen for the outcome via `postMessage`:

```javascript theme={null}
window.addEventListener('message', function (event) {
  if (event.data.type === 'payment_success') {
    console.log('Payment successful:', event.data.payinId);
  } else if (event.data.type === 'payment_failure') {
    console.log('Payment failed:', event.data.error);
  }
});
```

The embed URL accepts `allowedMethods` (`CARD`, `ACH`, `APPLE_PAY`), `theme` (`light` / `dark`), and `showSummary`. See [Payment Embed: Itemized Charges](/api-reference/guides/embed-payment-itemized-charges) for the full parameter list and event reference.

## Next steps

* [Webhook Events](/api-reference/guides/webhook-events) — get notified when forms are submitted and payments succeed instead of polling.
* [Payment Embed: Itemized Charges](/api-reference/guides/embed-payment-itemized-charges) — the embedded payment component in depth.
* [Patient Onboarding Workflow](/api-reference/guides/patient-onboarding-workflow) — create the patient and book the appointment that precede this flow.
