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

# Payments

> How pay-per-use billing works

## Overview

Arlo is **pay-per-use**: the patient is charged per provider visit, and there are no recurring subscriptions. Two independent pieces make up the payment flow:

1. **A card on file** — saved once through Stripe (`create_payment_setup`). Saving the card never charges the patient.
2. **The per-visit hold** — placed only when the patient explicitly confirms a provider connection (`confirm_provider_connection`).

<Note>
  **Arlo never auto-charges.** The payment gate always waits for the patient's explicit confirmation.
</Note>

## Checking Payment Status

Use `get_payment_status` to check the user's current payment configuration:

```json theme={null}
{
  "billingMode": "PAY_AS_YOU_GO",
  "paymentStatus": "ACTIVE",
  "paymentOptions": [
    {
      "id": "opt_paygo",
      "title": "Pay Per Use",
      "price": "$30/visit",
      "priceAmountCents": 3000,
      "billingMode": "PAY_AS_YOU_GO"
    }
  ]
}
```

### Billing Mode Values

| Mode                      | Description                                                                                       |
| ------------------------- | ------------------------------------------------------------------------------------------------- |
| `NONE`                    | No payment method configured                                                                      |
| `PAY_AS_YOU_GO`           | Pay per visit — the standard mode                                                                 |
| `SUBSCRIPTION` / `LEGACY` | Grandfathered plans from earlier pricing. Treat as having access without additional payment setup |

### Payment Status Values

| Status                | Description                                                    |
| --------------------- | -------------------------------------------------------------- |
| `PENDING`             | No usable payment method yet                                   |
| `ACTIVE`              | Payment method on file and valid                               |
| `FAILED`              | Payment failed (card declined, etc.)                           |
| `CANCELLED`           | Payment method removed                                         |
| `ACTIVE_UNTIL_EXPIRY` | Legacy subscription cancelled but active until the period ends |

## The Payment Gate

When a conversation reaches `PAYMENT_REQUIRED`, the `paymentGate` object indicates what action is needed:

```json theme={null}
{
  "status": "PAYMENT_REQUIRED",
  "paymentGate": {
    "consultationSummary": "Based on your symptoms, Arlo can help with...",
    "paymentType": "pay_per_use",
    "ctaText": "Connect with Provider - $30",
    "gateType": "PAY_PER_USE"
  }
}
```

### Gate Types

| `gateType`               | Meaning      | Required Action                                                             |
| ------------------------ | ------------ | --------------------------------------------------------------------------- |
| `PAY_PER_USE`            | Card on file | Confirm with the user, then `confirm_provider_connection` to place the hold |
| `PAYMENT_SETUP_REQUIRED` | No card yet  | `create_payment_setup` first, then confirm                                  |

## Pay-Per-Use Flow

<Steps>
  <Step title="Conversation reaches PAYMENT_REQUIRED">
    Triage is complete and the user is ready to connect with a provider
  </Step>

  <Step title="Present summary to user">
    Show the `consultationSummary` from the payment gate
  </Step>

  <Step title="User confirms">
    User agrees to proceed with the per-visit fee
  </Step>

  <Step title="Call confirm_provider_connection">
    This places the per-visit hold on the user's card
  </Step>

  <Step title="User enters MATCHING queue">
    Status changes to `MATCHING` while finding a provider
  </Step>
</Steps>

### Example

```javascript theme={null}
const conversation = await getConversation({ conversationId });

if (conversation.status === "PAYMENT_REQUIRED") {
  const { paymentGate } = conversation;

  // Present summary to user
  await showUser(paymentGate.consultationSummary);

  // Get user confirmation — Arlo never auto-charges
  const confirmed = await askUser(paymentGate.ctaText);

  if (confirmed) {
    await confirmProviderConnection({ conversationId });
  } else {
    await cancelRequest({ conversationId }); // dismisses the gate; conversation stays open
  }
}
```

## Card Setup Flow

When there's no card on file (`gateType: "PAYMENT_SETUP_REQUIRED"` or `paymentStatus: "PENDING"`):

<Steps>
  <Step title="Call create_payment_setup">
    Returns a Stripe-hosted card-setup URL. Saving the card does not charge the user
  </Step>

  <Step title="User saves their card">
    Direct the user to the `paymentUrl` in their browser
  </Step>

  <Step title="Poll get_payment_status">
    Every \~15–30 seconds (or when the user says they're done) until `paymentStatus` is `ACTIVE`
  </Step>

  <Step title="Confirm the connection">
    Call `confirm_provider_connection` to place the per-visit hold and enter MATCHING
  </Step>
</Steps>

## Stripe Integration

Arlo uses Stripe for payment processing. All card entry happens through Stripe's hosted pages.

* Card details never pass through Arlo or your agent
* All payment data handled by Stripe
* PCI compliance maintained by Stripe

## Payment Errors

| Error                 | Cause                                  | Resolution                                                                         |
| --------------------- | -------------------------------------- | ---------------------------------------------------------------------------------- |
| `payment_hold_failed` | Card declined                          | `create_payment_setup` to add a different card, poll until `ACTIVE`, confirm again |
| `no_payment_gate`     | Conversation not in `PAYMENT_REQUIRED` | Check `get_conversation` for the current status                                    |

### Handling Payment Failures

```javascript theme={null}
try {
  await confirmProviderConnection({ conversationId });
} catch (error) {
  if (error.code === "payment_hold_failed") {
    const { paymentUrl } = await createPaymentSetup();
    await showUser(`Update payment method: ${paymentUrl}`);
    // poll get_payment_status until ACTIVE, then confirm again
  }
}
```

## Legacy Subscriptions

Earlier versions of Arlo offered subscriptions. Grandfathered accounts (`billingMode: SUBSCRIPTION` or `LEGACY`) keep their access without per-visit setup. The REST API retains deprecated endpoints ([activate](/api-reference/subscriptions/activate), [cancel](/api-reference/subscriptions/cancel)) for legacy clients; they are not part of the MCP tool surface.
