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

# Create a Customer Portal Session

> Cria uma sessão hospedada do portal do cliente.

Cria uma `customer_portal.session` e retorna uma `url` temporária. Redirecione
o cliente para essa URL assim que ela for criada; a autorização embutida no link
é de uso único e pode ser aberta pela primeira vez em até 1 hora.

Depois do primeiro acesso bem-sucedido, o `authorization_code` é consumido e a
hosted page passa a usar uma sessão curta do navegador por até 1 hora. Depois
desse período, crie uma nova `customer_portal.session` para gerar uma nova URL.

## Autenticação

Header `Authorization: Bearer {{API_KEY}}`. Escopo necessário: `write`.

| Tipo de chave          | Header `Organization` | Escopo                                     |
| ---------------------- | --------------------- | ------------------------------------------ |
| API key da organização | proibido              | Customer da própria organização            |
| API key de plataforma  | obrigatório           | Customer da organização conectada indicada |

## Attributes

<ParamField body="customer" type="string" required>
  Customer que abrirá o portal.
</ParamField>

<ParamField body="flow_data" type="object">
  Fluxo inicial da hosted page. Quando omitido, o cliente abre a home do portal.

  <Expandable title="Campos de flow_data">
    <ParamField body="type" type="string" required>
      `customer_update`, `payment_method_update` ou `subscription_cancel`.
    </ParamField>

    <ParamField body="after_completion" type="object">
      Ação após concluir o fluxo. No V1 aceita apenas `type: "redirect"`.
    </ParamField>

    <ParamField body="payment_method_update" type="object">
      Opções para troca de cartão. `subscription` é opcional para atualizar o
      padrão da assinatura; `invoice` é opcional para atualizar o padrão de uma
      invoice `open`.
    </ParamField>

    <ParamField body="subscription_cancel" type="object">
      Opções para cancelamento. `subscription` é obrigatório.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="locale" type="string">
  Locale sugerido para a hosted page, por exemplo `pt-BR`.
</ParamField>

<ParamField body="metadata" type="object">
  Metadata da sessão. Padrão `{}`.
</ParamField>

<ParamField body="return_url" type="string">
  URL para onde o cliente pode voltar no seu app.
</ParamField>

<RequestExample>
  ```bash cURL theme={}
  curl -X POST "https://api.chargefy.io/v1/customer-portal-sessions" \
    -H "Authorization: Bearer {{API_KEY}}" \
    -H "Content-Type: application/json" \
    -d '{
      "customer": "cus_123"
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={}
  {
    "id": "cps_123",
    "object": "customer_portal.session",
    "configuration": null,
    "created_at": "2026-05-27T12:00:00Z",
    "customer": "cus_123",
    "expires_at": "2026-05-27T13:00:00Z",
    "flow": null,
    "livemode": true,
    "locale": "pt-BR",
    "metadata": {},
    "return_url": "https://example.com/account",
    "status": "created",
    "updated_at": null,
    "url": "https://billing.chargefy.io/portal/session/cps_123?authorization_code=..."
  }
  ```
</ResponseExample>

## Deep link para cancelamento

<RequestExample>
  ```bash cURL theme={}
  curl -X POST "https://api.chargefy.io/v1/customer-portal-sessions" \
    -H "Authorization: Bearer {{API_KEY}}" \
    -H "Content-Type: application/json" \
    -d '{
      "customer": "cus_123",
      "flow_data": {
        "subscription_cancel": {
          "subscription": "sub_123"
        },
        "type": "subscription_cancel"
      }
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={}
  {
    "id": "cps_123",
    "object": "customer_portal.session",
    "configuration": null,
    "created_at": "2026-05-27T12:00:00Z",
    "customer": "cus_123",
    "expires_at": "2026-05-27T13:00:00Z",
    "flow": {
      "after_completion": {
        "redirect": {
          "return_url": "https://example.com/account/subscription-canceled"
        },
        "type": "redirect"
      },
      "subscription_cancel": {
        "subscription": "sub_123"
      },
      "type": "subscription_cancel"
    },
    "livemode": true,
    "locale": null,
    "metadata": {},
    "return_url": "https://example.com/account",
    "status": "created",
    "updated_at": null,
    "url": "https://billing.chargefy.io/portal/session/cps_123?authorization_code=..."
  }
  ```
</ResponseExample>

## Deep link para atualizar cartão de uma invoice

<RequestExample>
  ```bash cURL theme={}
  curl -X POST "https://api.chargefy.io/v1/customer-portal-sessions" \
    -H "Authorization: Bearer {{API_KEY}}" \
    -H "Content-Type: application/json" \
    -d '{
      "customer": "cus_123",
      "flow_data": {
        "payment_method_update": {
          "invoice": "inv_123"
        },
        "type": "payment_method_update"
      }
    }'
  ```
</RequestExample>

Quando o cliente conclui o formulário hospedado, o cartão salvo passa a ser o
`default_payment_method` do customer e da invoice informada. Se a sessão também
enviar `subscription`, o mesmo cartão passa a ser o padrão da assinatura.

## Erros comuns

| Status | `code`                    | Quando ocorre                                                      |
| ------ | ------------------------- | ------------------------------------------------------------------ |
| `400`  | `invalid_request`         | `customer`, `flow_data.type` ou `subscription` obrigatório ausente |
| `404`  | `resource_missing`        | Customer ou subscription não pertence ao escopo da API key         |
| `409`  | `resource_state_conflict` | Subscription em estado terminal                                    |

## Próximos passos

Depois de criar a sessão, redirecione o cliente para `url`. A URL não deve ser
armazenada como link permanente, mas pode ser enviada por email: ela expira em 1
hora se ainda não tiver sido aberta. Após o primeiro acesso, a autorização do
link é invalidada e a sessão hosted dura até 1 hora.
