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

# collectPayment

> Open a Stripe Checkout session for a workspace billing plan.

export const ExpectedOutput = ({caption = "Expected output", children}) => <div className="gv-output">
    <div className="gv-output__label">
      <svg className="gv-output__icon" viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
        <polyline points="15 10 20 15 15 20" />
        <path d="M4 4v7a4 4 0 0 0 4 4h12" />
      </svg>
      <span>{caption}</span>
    </div>
    <div className="gv-output__body">{children}</div>
  </div>;

export const ErrorTable = ({errors}) => <div className="gv-error-table" role="table" aria-label="Errors and fixes">
    <div className="gv-error-table__head" role="row">
      <span className="gv-error-table__col-head" role="columnheader">Error</span>
      <span className="gv-error-table__col-head" role="columnheader">Cause</span>
      <span className="gv-error-table__col-head" role="columnheader">Fix</span>
    </div>
    {errors.map((err, i) => <div className="gv-error-table__row" role="row" key={i}>
        <code className="gv-error-table__code" role="cell">{err.code}</code>
        <div className="gv-error-table__cause" role="cell">{err.cause}</div>
        <div className="gv-error-table__fix" role="cell">{err.fix}</div>
      </div>)}
  </div>;

export const Def = ({term, type, defaultValue, required, children}) => <>
    <dt className="gv-def-list__term">
      <span className="gv-def-list__name">{term}</span>
      {type && <span className="gv-def-list__type">{type}</span>}
      {required && <span className="gv-def-list__required">required</span>}
      {defaultValue !== undefined && <span className="gv-def-list__default">
          default <code>{defaultValue}</code>
        </span>}
    </dt>
    <dd className="gv-def-list__description">{children}</dd>
  </>;

export const DefList = ({children}) => <dl className="gv-def-list">{children}</dl>;

export const ArrowItem = ({children}) => <li className="gv-arrow-item">
    <span className="gv-arrow-item__arrow" aria-hidden="true">{"↳︎"}</span>
    <span className="gv-arrow-item__content">{children}</span>
  </li>;

export const ArrowList = ({children}) => <ul className="gv-arrow-list">{children}</ul>;

export const Eyebrow = ({label, tone = "default"}) => <div className={`gv-eyebrow gv-eyebrow--${tone}`}>
    <span className="gv-eyebrow__bar" aria-hidden="true" />
    <span className="gv-eyebrow__label">{label}</span>
  </div>;

<Eyebrow label="CAPABILITY" />

`collectPayment` opens a hosted Stripe Checkout session for a workspace-defined billing plan. When a user triggers it — typically by clicking a pricing CTA — the runtime calls Stripe on the workspace's behalf, returns a short-lived `checkout_url`, and your page redirects the user there. Revenue settles directly into the workspace owner's Stripe Connect account; the platform holds no funds in transit. By the end of this page you can wire a CTA to charge a customer for a published plan.

## Invoke from a CTA

The canonical pattern is `collectPayment` on a `Cta` block's `on_click`. Pass `success_url` and `cancel_url` as absolute URLs:

```json cta-pricing.json theme={null}
{
  "block": "Cta",
  "props": {
    "headline": "Start your Pro trial",
    "cta_label": "Subscribe",
    "on_click": {
      "capability": "collectPayment",
      "args": {
        "plan_id": "plan_pro_monthly",
        "success_url": "https://app.acme.com/welcome",
        "cancel_url": "https://app.acme.com/pricing",
        "customer_email": "ada@acme.com"
      }
    }
  }
}
```

The runtime validates the args, creates a Stripe Checkout session under the workspace's Connect account, and returns a `checkout_url`. The block redirects the browser to that URL — the user lands on Stripe's hosted page, completes payment, and Stripe sends them to `success_url` (or `cancel_url` if they back out).

## Inputs

<DefList>
  <Def term="plan_id" type="string" required>
    The workspace-defined billing plan to check out. Use a `plans[].id` value returned by [`listPlans`](/capabilities/list-plans).
  </Def>

  <Def term="success_url" type="string" required>
    Absolute URL Stripe redirects the user to after a successful payment.
  </Def>

  <Def term="cancel_url" type="string" required>
    Absolute URL Stripe redirects the user to if they abandon the checkout.
  </Def>

  <Def term="customer_email" type="string">
    Pre-fills the email field on the Stripe Checkout page. Useful when the calling user is already signed in.
  </Def>

  <Def term="metadata" type="Record<string, string>">
    Arbitrary key-value pairs attached to the Stripe session. Available on downstream webhook events for reconciliation.
  </Def>
</DefList>

## Outputs

<DefList>
  <Def term="checkout_url" type="string">
    The hosted Stripe Checkout URL. Redirect the user here, or open it in a new tab.
  </Def>

  <Def term="session_id" type="string">
    The Stripe Session ID. Use it to reconcile webhook events back to this invocation.
  </Def>

  <Def term="expires_at" type="string">
    ISO 8601 timestamp when the Checkout session expires. Sessions are short-lived — do not cache the URL beyond `expires_at`.
  </Def>
</DefList>

## Provisioning

The workspace must complete Stripe Connect onboarding before `collectPayment` can dispatch. The Builder walks the workspace owner through the flow. Until onboarding is complete, every call returns `stripe_not_connected`. The programmatic onboarding endpoints live in the [Monetization API](/api-reference/resources/monetization).

## Error codes

<ErrorTable
  errors={[
{
  code: "stripe_not_connected",
  cause: "The workspace has not completed Stripe Connect onboarding.",
  fix: "Walk the workspace owner through Stripe Connect in the Builder, or call the Monetization API.",
},
{
  code: "plan_not_found",
  cause: "No published plan exists with the given `plan_id`.",
  fix: "Confirm the plan is published, and pass an `id` returned by `listPlans`.",
},
{
  code: "invalid_input",
  cause: "One or more required fields failed schema validation.",
  fix: "Inspect `error.details` for field-level messages and correct the args.",
},
]}
/>

Every error returns the standard envelope:

<ExpectedOutput caption="Error envelope">
  ```json error-envelope.json theme={null}
  {
    "ok": false,
    "error": {
      "code": "stripe_not_connected",
      "message": "This workspace has not completed Stripe Connect onboarding.",
      "details": {}
    }
  }
  ```
</ExpectedOutput>

## Related

<Columns cols={2}>
  <Card title="listPlans" icon="list" href="/capabilities/list-plans">
    Fetch the workspace's published billing plans to populate a pricing UI.
  </Card>

  <Card title="Accept payments guide" icon="credit-card" href="/guides/accept-payments">
    End-to-end walkthrough: Stripe Connect, plan setup, and CTA wiring.
  </Card>
</Columns>
