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

# Post claim payments

> Resolves the location from the `X-Vendor-Request-Key` header (slot); no `location_id` in the path.

Creates insurance claim payments from a Stedi claim status response and posts them to the PMS.

Send the claim status response exactly as returned by Stedi in `stedi_response`. **One claim payment is created for each entry in `claims` that matches a claim** (see Matching), using that claim's:

- `claimStatus.amountPaid` as the check amount
- `claimStatus.checkNumber` and `claimStatus.checkIssueDate`
- `payer.organizationName` as the carrier name

#### Matching

- **Claim:** `claimStatus.clearingHouseClaimNumber` is matched to the claim's `clearinghouse_claim_id`. Set it first with `PATCH /locations/{location_id}/insurance_claims/{insurance_claim_id}`. Entries with no `clearingHouseClaimNumber`, or one that matches no claim in the location, are skipped: no claim payment is created and they are not included in the response.
- **Procedures:** each `serviceDetails[].service.procedureId` must be the PMS procedure ID (Open Dental `ProcNum`) of a procedure on that claim that is not yet attached to a payment. Its `amountPaid` is posted as the insurance payment for that procedure.

#### PMS writeback

Each claim payment is written to the PMS in the background. For Open Dental:

1. Each matched procedure is marked Received with its paid amount.
2. The claim is marked Received.
3. The check is created and attached to the claim. Offices with Open Dental's `ClaimPaymentBatchOnly` preference use the batch claim payment endpoint.

The check amount must equal the total paid across the claim's received procedures. Write-offs and deductibles are not posted: a claim status response does not include them.

Writeback runs only for Open Dental practices. If a procedure cannot be matched to an unpaid procedure on the claim, the writeback stops at that procedure and records an error; procedures before it may already be marked Received.

Requires an API key with **RCM enabled**. Keys without it receive `401` with `{"errors": "RCM is not enabled for this API key"}`; contact TeamCare support to enable it.



## OpenAPI

````yaml https://app.teamcaredental.com/openapi-vendors-v2.json post /claim_payments
openapi: 3.1.0
info:
  title: TeamCare Vendor API (v2)
  version: 2.0.0
  description: >-
    Version 2 of the TeamCare Vendor API. HIPAA-compliant and opt-in.


    ## What changed from v1


    The data endpoints and response shapes are identical to v1 — **only how you
    address a location changes.** In v1 the location lived in every URL
    (`/locations/{location_id}/patients`). In v2 you request a **slot** for a
    location once, then send the returned `request_key` in the
    `X-Vendor-Request-Key` header; `location_id` is gone from the data routes.


    ## Request cycle


    1. `POST /auth/token` → JWT (unchanged from v1).

    2. `GET /organizations`, `GET /locations` → pick a `location_id`.

    3. `POST /locations/{location_id}/slots` → `{ request_key, expires_at }`.

    4. Call any data endpoint with header `X-Vendor-Request-Key: <request_key>`
    (no `location_id` in the path).


    ## Minimal changes to migrate


    - Point your base URL at `https://api.teamcaredental.com/api/v2/vendors` (v2
    is served from `api.teamcaredental.com`, not `app.teamcaredental.com`).

    - Call the slot endpoint **once per location**.

    - Drop `/locations/{location_id}` from your data paths and add the
    `X-Vendor-Request-Key` header.

    - Everything else — authentication, Ransack `q` filters, pagination,
    response shapes — is unchanged.


    ## Slot validity, cooldown & quota


    - **Validity:** a `request_key` is valid for **6 hours** — the same lifetime
    as the access token. After that it stops authorizing and you must request a
    new slot.

    - **Cooldown:** you can only re-request the **same** location's slot once
    every **2 minutes**. Within the cooldown the slot endpoint returns `429`
    with a `retry_after` (seconds).

    - **Quota:** each firm may hold up to its `concurrent_slots` quota (default
    **10**) active request keys at once, so data for at most 10 locations can be
    pulled concurrently. Requesting an 11th slot trims the oldest key, so its
    `request_key` stops authorizing immediately and any in-flight requests using
    it fail with `401`. To raise the quota above 10, contact TeamCare support.

    - **Rate limit:** the slot endpoint accepts at most 10 requests per 10
    seconds per token.


    ## Recommended usage


    Request a slot for a location and pull **all** of that location's data in
    one pass before moving on — don't re-request slots per call or churn between
    locations. If you fan out across locations in parallel, keep the fan-out at
    or below your quota: once an 11th slot is requested, the oldest
    `request_key` is invalidated even if a sync is still running on it.


    See the [changelog](https://docs.teamcaredental.com/changelog) for the full
    list of changes from v1.
servers:
  - url: https://api.teamcaredental.com/api/v2/vendors
security:
  - bearerAuth: []
paths:
  /claim_payments:
    post:
      tags:
        - Claim Payments
      summary: Post claim payments
      description: >-
        Resolves the location from the `X-Vendor-Request-Key` header (slot); no
        `location_id` in the path.


        Creates insurance claim payments from a Stedi claim status response and
        posts them to the PMS.


        Send the claim status response exactly as returned by Stedi in
        `stedi_response`. **One claim payment is created for each entry in
        `claims` that matches a claim** (see Matching), using that claim's:


        - `claimStatus.amountPaid` as the check amount

        - `claimStatus.checkNumber` and `claimStatus.checkIssueDate`

        - `payer.organizationName` as the carrier name


        #### Matching


        - **Claim:** `claimStatus.clearingHouseClaimNumber` is matched to the
        claim's `clearinghouse_claim_id`. Set it first with `PATCH
        /locations/{location_id}/insurance_claims/{insurance_claim_id}`. Entries
        with no `clearingHouseClaimNumber`, or one that matches no claim in the
        location, are skipped: no claim payment is created and they are not
        included in the response.

        - **Procedures:** each `serviceDetails[].service.procedureId` must be
        the PMS procedure ID (Open Dental `ProcNum`) of a procedure on that
        claim that is not yet attached to a payment. Its `amountPaid` is posted
        as the insurance payment for that procedure.


        #### PMS writeback


        Each claim payment is written to the PMS in the background. For Open
        Dental:


        1. Each matched procedure is marked Received with its paid amount.

        2. The claim is marked Received.

        3. The check is created and attached to the claim. Offices with Open
        Dental's `ClaimPaymentBatchOnly` preference use the batch claim payment
        endpoint.


        The check amount must equal the total paid across the claim's received
        procedures. Write-offs and deductibles are not posted: a claim status
        response does not include them.


        Writeback runs only for Open Dental practices. If a procedure cannot be
        matched to an unpaid procedure on the claim, the writeback stops at that
        procedure and records an error; procedures before it may already be
        marked Received.


        Requires an API key with **RCM enabled**. Keys without it receive `401`
        with `{"errors": "RCM is not enabled for this API key"}`; contact
        TeamCare support to enable it.
      operationId: locations_resources_claim_payments_create
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - claim_payment
              properties:
                claim_payment:
                  type: object
                  required:
                    - stedi_response
                  properties:
                    stedi_response:
                      type: object
                      description: >-
                        The Stedi claim status response, unchanged. TeamCare
                        reads `controlNumber`, `payer.organizationName` and, for
                        each entry in `claims`, `claimStatus` and
                        `serviceDetails`.
                      additionalProperties: true
            example:
              claim_payment:
                stedi_response:
                  claims:
                    - claimStatus:
                        amountPaid: '68.00'
                        checkIssueDate: '2025-07-17'
                        checkNumber: '123456789'
                        clearingHouseClaimNumber: CH-0098431
                        patientAccountNumber: 17/3
                        statusCategoryCode: F1
                        statusCategoryCodeValue: Finalized/Payment - The claim/line has been paid.
                        statusCode: '65'
                        submittedAmount: '68.00'
                      serviceDetails:
                        - service:
                            procedureId: '21'
                            amountPaid: '60.00'
                            submittedAmount: '60.00'
                            submittedUnits: '1'
                        - service:
                            procedureId: '23'
                            amountPaid: '8.00'
                            submittedAmount: '8.00'
                            submittedUnits: '1'
                  controlNumber: '123456789'
                  payer:
                    organizationName: UNITEDHEALTHCARE
                    payerIdentification: '87726'
      responses:
        '201':
          description: >-
            The created claim payments, one per matched claim in the Stedi
            response. Empty when no claim matches.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        type:
                          type: string
                          example: claim_payment
                        attributes:
                          type: object
                          properties:
                            deleted:
                              type: boolean
                            check_date:
                              type:
                                - string
                                - 'null'
                              format: date
                              description: Date the check was entered in the PMS.
                            date_issued:
                              type:
                                - string
                                - 'null'
                              format: date
                              description: Date the payer issued the check.
                            check_amount:
                              type:
                                - string
                                - 'null'
                              description: Check amount, as a decimal string.
                              example: '68.0'
                            check_number:
                              type:
                                - string
                                - 'null'
                            carrier_name:
                              type:
                                - string
                                - 'null'
                            note:
                              type:
                                - string
                                - 'null'
                            updated_at:
                              type: string
                              format: date-time
              example:
                data:
                  - id: '301'
                    type: claim_payment
                    attributes:
                      deleted: false
                      check_date: null
                      date_issued: '2025-07-17'
                      check_amount: '68.0'
                      check_number: '123456789'
                      carrier_name: UNITEDHEALTHCARE
                      note: Posted through Stedi 123456789
                      updated_at: '2026-10-09T09:15:02.000Z'
        '401':
          description: >-
            Missing/invalid/expired JWT, or missing/invalid/expired
            X-Vendor-Request-Key.
          content:
            application/json:
              schema:
                type: object
                properties:
                  errors:
                    type: string
              examples:
                not_authorized:
                  value:
                    errors: not authorized
                rcm_not_enabled:
                  value:
                    errors: RCM is not enabled for this API key
        '403':
          description: The credential may not access this resource.
          content:
            application/json:
              schema:
                type: object
                properties:
                  errors:
                    type: string
              example:
                errors: access Denied
        '404':
          description: Resource not found.
          content:
            application/json:
              schema:
                type: object
                properties:
                  errors:
                    type: string
              example:
                errors: resource not found
        '422':
          description: The request could not be processed.
          content:
            application/json:
              schema:
                type: object
                properties:
                  errors:
                    type: string
              example:
                errors: ...
      security:
        - bearerAuth: []
          vendorRequestKey: []
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: JWT returned by POST /auth/token. Valid for six hours.
    vendorRequestKey:
      type: apiKey
      in: header
      name: X-Vendor-Request-Key
      description: >-
        Request key returned by POST /locations/{location_id}/slots. Identifies
        the practice for a data request; valid for 6 hours (the access token's
        lifetime) and subject to the firm's concurrent-slot quota.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.