Files
cfw-autumn/apps/docs/mintlify/documentation/customers/payment-flow.mdx
mintlify[bot] 00baab31ac Fix broken internal links across docs
Generated-By: mintlify-agent
2026-04-28 12:10:56 +00:00

200 lines
4.5 KiB
Plaintext

---
title: "Payment Flow"
description: "Hosted checkout pages vs building your own payment flow"
---
## Using hosted pages
By default, `billing.attach` returns a `paymentUrl` — just redirect the customer and Autumn handles payment collection, confirmation, and activation.
<CodeGroup>
```typescript TypeScript
const response = await autumn.billing.attach({
customerId: "user_123",
planId: "pro",
});
redirect(response.paymentUrl);
```
```tsx React
import { useCustomer } from "autumn-js/react";
const { attach } = useCustomer();
await attach({ planId: "pro" });
```
```python Python
response = await autumn.billing.attach(
customer_id="user_123",
plan_id="pro",
)
# Redirect to response.payment_url
```
```bash cURL
curl -X POST 'https://api.useautumn.com/v1/billing.attach' \
-H 'Authorization: Bearer am_sk_...' \
-H 'Content-Type: application/json' \
-d '{
"customer_id": "user_123",
"plan_id": "pro"
}'
```
</CodeGroup>
New customers without a payment method are sent to **Stripe Checkout**. Existing customers are sent to **Autumn Checkout** to review and confirm. After checkout, the customer is redirected to your `successUrl` (or the default URL in your Autumn dashboard).
## Building your own checkout
For full control over the checkout experience, use `redirectMode: "if_required"`. This charges the saved payment method directly instead of redirecting — the customer is only sent to Stripe Checkout if they don't have a payment method yet.
```mermaid actions={false}
graph LR
A["previewAttach"] --> B["user confirms"] --> C["attach"] --> D{"Payment method?"}
D -->|Yes| E["Charged"]
D -->|No| F["Stripe Checkout"]
E --> G["Plan enabled"]
F --> G
style A fill:#f472b622,stroke:#f472b6
style C fill:#f472b622,stroke:#f472b6
```
### Step 1: Preview the charge
Call `billing.previewAttach` to get line items, totals, and proration details to display in your UI.
<CodeGroup>
```typescript TypeScript
const preview = await autumn.billing.previewAttach({
customerId: "user_123",
planId: "pro",
});
// preview.lineItems — array of charges and credits
// preview.total — net amount in cents
// preview.currency — e.g. "usd"
```
```tsx React
import { useCustomer } from "autumn-js/react";
const { previewAttach } = useCustomer();
const preview = await previewAttach({ planId: "pro" });
```
```python Python
preview = await autumn.billing.preview_attach(
customer_id="user_123",
plan_id="pro",
)
```
```bash cURL
curl -X POST 'https://api.useautumn.com/v1/billing.preview_attach' \
-H 'Authorization: Bearer am_sk_...' \
-H 'Content-Type: application/json' \
-d '{
"customer_id": "user_123",
"plan_id": "pro"
}'
```
</CodeGroup>
<Expandable title="Example response">
```json
{
"customerId": "user_123",
"lineItems": [
{
"title": "Pro Plan",
"description": "Monthly subscription",
"amount": 20
},
{
"title": "Credit for Free Plan",
"description": "Unused time on current plan",
"amount": -5
}
],
"total": 15,
"currency": "usd",
"nextCycle": {
"startsAt": 1735689600000,
"total": 20
}
}
```
</Expandable>
### Step 2: Confirm and charge
Once the customer confirms, call `billing.attach` with `redirectMode: "if_required"`.
<CodeGroup>
```typescript TypeScript
const response = await autumn.billing.attach({
customerId: "user_123",
planId: "pro",
redirectMode: "if_required",
});
if (response.paymentUrl) {
redirect(response.paymentUrl);
} else {
showSuccess();
}
```
```tsx React
import { useCustomer } from "autumn-js/react";
const { attach } = useCustomer();
const response = await attach({
planId: "pro",
redirectMode: "if_required",
});
```
```python Python
response = await autumn.billing.attach(
customer_id="user_123",
plan_id="pro",
redirect_mode="if_required",
)
if response.payment_url:
redirect(response.payment_url)
else:
show_success()
```
```bash cURL
curl -X POST 'https://api.useautumn.com/v1/billing.attach' \
-H 'Authorization: Bearer am_sk_...' \
-H 'Content-Type: application/json' \
-d '{
"customer_id": "user_123",
"plan_id": "pro",
"redirect_mode": "if_required"
}'
```
</CodeGroup>
## Handling the response
The `billing.attach` response has two key fields:
**`payment_url`** — a URL the customer should be redirected to, or `null` if no redirect is needed.
**`required_action`** — present when payment couldn't be processed automatically. See [Edge Cases](/documentation/customers/edge-cases) for details on handling 3DS, payment failures, and retries.