Assinaturas
Atualizar assinatura
Atualize os campos editáveis de uma assinatura existente ou troque o plano dela.
PATCH
/
v2
/
subscriptions
/
{id}
Update a Subscription
curl --request PATCH \
--url https://api.pagou.ai/v2/subscriptions/{id} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"metadata": {},
"retry_offsets_days": [
15
],
"product_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"quantity": 500000
}
'import requests
url = "https://api.pagou.ai/v2/subscriptions/{id}"
payload = {
"metadata": {},
"retry_offsets_days": [15],
"product_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"quantity": 500000
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
metadata: {},
retry_offsets_days: [15],
product_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
quantity: 500000
})
};
fetch('https://api.pagou.ai/v2/subscriptions/{id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.pagou.ai/v2/subscriptions/{id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'metadata' => [
],
'retry_offsets_days' => [
15
],
'product_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'quantity' => 500000
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.pagou.ai/v2/subscriptions/{id}"
payload := strings.NewReader("{\n \"metadata\": {},\n \"retry_offsets_days\": [\n 15\n ],\n \"product_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"quantity\": 500000\n}")
req, _ := http.NewRequest("PATCH", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.patch("https://api.pagou.ai/v2/subscriptions/{id}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"metadata\": {},\n \"retry_offsets_days\": [\n 15\n ],\n \"product_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"quantity\": 500000\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.pagou.ai/v2/subscriptions/{id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"metadata\": {},\n \"retry_offsets_days\": [\n 15\n ],\n \"product_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"quantity\": 500000\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"requestId": "0190a2b4-18a7-7de0-9a43-69b7cf261201",
"data": {
"id": "string",
"customerId": "string",
"status": "incomplete",
"paymentMethod": "credit_card",
"billingModel": "merchant_initiated",
"billingDayOfMonth": 1,
"interval": "day",
"intervalCount": 1,
"amount": 0,
"currency": "BRL",
"trialEnd": "2026-07-14T12:00:00.000Z",
"currentPeriodStart": "2026-07-14T12:00:00.000Z",
"currentPeriodEnd": "2026-07-14T12:00:00.000Z",
"cancelAtPeriodEnd": false,
"canceledAt": "2026-07-14T12:00:00.000Z",
"failurePolicy": "immediate_cancel",
"retryOffsetsDays": [
1
],
"cancellationReason": "user_requested",
"customerEmail": "string",
"cardLast4": "string",
"metadata": {},
"informations": [
{
"key": "string",
"value": "string"
}
],
"products": [
{
"name": "string",
"price": 0,
"quantity": 1,
"tangible": false
}
],
"recurringAuthorization": {
"status": "pending"
},
"createdAt": "2026-07-14T12:00:00.000Z",
"updatedAt": "2026-07-14T12:00:00.000Z"
}
}{
"title": "<string>",
"status": 0,
"type": "<string>",
"detail": "<string>",
"instance": "<string>"
}{
"title": "<string>",
"status": 0,
"type": "<string>",
"detail": "<string>",
"instance": "<string>"
}{
"title": "<string>",
"status": 0,
"type": "<string>",
"detail": "<string>",
"instance": "<string>"
}{
"title": "<string>",
"status": 0,
"type": "<string>",
"detail": "<string>",
"instance": "<string>"
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>"
}Este endpoint faz duas coisas diferentes, e cada requisição pode fazer apenas uma delas.
O ciclo de cobrança tem precedência: mover entre planos de ciclos diferentes é sempre imediato e sempre cobra o valor cheio, qualquer que seja o nível do alvo.
Quando a cobrança é recusada, o plano não muda — a requisição falha com
- Editar campos.
metadata,failure_policyeretry_offsets_dayspodem ser alterados a qualquer momento. - Trocar o plano. Envie
product_id, opcionalmente comquantity.
product_id não pode ser combinado com os campos editáveis, e quantity exige product_id. As duas combinações são recusadas com 422, para que nenhuma parte da requisição seja descartada em silêncio.
Valor, intervalo e moeda não são editados diretamente — eles vêm do plano e mudam quando o plano muda.
Um webhook subscription.updated é disparado em todos os casos.
Numa assinatura com Pix Automático, a troca de plano não está disponível: enviar product_id retorna 422 e o plano não muda (PLAN_CHANGE_UNAVAILABLE_FOR_PAYMENT_METHOD quando a assinatura está vinculada a um plano do catálogo). retry_offsets_days é gravado, mas não tem efeito ali, porque o intervalo entre tentativas segue as regras do Pix Automático.
Para quais planos a assinatura pode ir
A assinatura só pode trocar de plano quando já está vinculada a um plano do catálogo. ConfiraproductId antes: quando ele é null, não há troca possível.
O alvo precisa ser um plano ativo da mesma família de produtos do atual — productFamilyId indica qual família é essa. Um alvo de outra família, ou um produto que não seja um plano recorrente, é recusado antes de qualquer cobrança ou gravação.
O que acontece, e quando o cliente é cobrado
| Caso | Efeito |
|---|---|
| Plano de nível maior | cobrado na hora pelo que resta do período atual; a data de renovação não muda |
| Plano de nível menor | agendado para current_period_end. Nada é cobrado e nada é estornado |
| Qualquer plano cujo total fique abaixo do valor atual — menos unidades, ou nível maior com preço menor que o plano atual | agendado para current_period_end, exatamente como um nível menor |
| Plano com ciclo de cobrança diferente | aplicado na hora pelo valor cheio do novo plano; a data de renovação reinicia |
Assinatura em past_due | aplicado na hora pelo valor cheio do novo plano, liquidando o ciclo em aberto; a assinatura volta para active |
402 e a assinatura fica exatamente como estava.
Quando a cobrança não devolve resultado nenhum — um timeout, por exemplo — o desfecho é desconhecido, não uma recusa, e a requisição falha com 409 PLAN_CHARGE_INDETERMINATE. O plano não muda. Repita a mesma troca depois que a cobrança se resolver; antes disso ela é recusada, porque a cobrança pode já ter entrado.
Trocas agendadas
Uma troca agendada para o fim do período fica visível empendingChange, com o plano de destino, o valor que será cobrado — o plano mais o que for cobrado junto dele — e a data em que passa a valer. O preço é congelado no momento do agendamento, então edições posteriores no plano não alteram o que foi combinado.
Para cancelar uma troca agendada, envie product_id com o plano em que a assinatura já está. pendingChange volta a ser null.
Campos da resposta
| Campo | Significado |
|---|---|
productId | o plano cobrado, ou null quando a assinatura não está vinculada a nenhum |
productFamilyId | a família de produtos a que o plano pertence, ou null |
pendingChange | a troca agendada (productId, amount, effectiveAt), ou null |
Erros
| Status | Código | Quando |
|---|---|---|
422 | PRODUCT_NOT_FOUND | o id do produto não resolve, ou o plano alvo está inativo |
422 | PRODUCT_NOT_RECURRING | o alvo não é um plano recorrente |
422 | PLAN_NOT_IN_SAME_FAMILY | o alvo é de outra família, ou algum dos lados não tem família |
422 | SUBSCRIPTION_HAS_NO_CATALOG_PLAN | a assinatura não está vinculada a um plano do catálogo |
422 | PLAN_CHANGE_CURRENCY_MISMATCH | o alvo é cobrado em outra moeda |
422 | PLAN_CHANGE_SAME_PRODUCT | a assinatura já está nesse plano e não há nada agendado |
422 | PLAN_CHANGE_NOT_ALLOWED_DURING_TRIAL | a assinatura está em trialing |
422 | PLAN_CHANGE_NOT_ALLOWED_FOR_STATUS | o status não permite a troca |
422 | PLAN_CHANGE_UNAVAILABLE_FOR_PAYMENT_METHOD | o meio de pagamento não suporta troca de plano |
409 | PLAN_CHANGE_BLOCKED_BY_PENDING_RENEWAL | há uma cobrança desta assinatura em voo; tente de novo depois que ela liquidar |
402 | PLAN_CHARGE_DECLINED | a cobrança do novo plano foi recusada |
409 | PLAN_CHARGE_INDETERMINATE | a cobrança não devolveu resultado; o plano não mudou e a cobrança está em reconciliação |
409 | PLAN_CHANGE_NOT_APPLIED | a assinatura mudou enquanto a troca era aplicada; o plano não foi trocado |
Leia a seguir
Autorizações
BearerAuthApiKeyAuthBasicAuth
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Parâmetros de caminho
Public subscription id (UUID).
Pattern:
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$Corpo
application/json
Show child attributes
Show child attributes
Opções disponíveis:
immediate_cancel, retry_then_cancel Required array length:
1 - 10 elementsIntervalo obrigatório:
1 <= x <= 30Public id of a catalog product in the same family. Changes the subscription's plan.
Pattern:
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$Quantity for the new plan. Omitted keeps the current one.
Intervalo obrigatório:
1 <= x <= 999999Update a Subscription
curl --request PATCH \
--url https://api.pagou.ai/v2/subscriptions/{id} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"metadata": {},
"retry_offsets_days": [
15
],
"product_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"quantity": 500000
}
'import requests
url = "https://api.pagou.ai/v2/subscriptions/{id}"
payload = {
"metadata": {},
"retry_offsets_days": [15],
"product_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"quantity": 500000
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
metadata: {},
retry_offsets_days: [15],
product_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
quantity: 500000
})
};
fetch('https://api.pagou.ai/v2/subscriptions/{id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.pagou.ai/v2/subscriptions/{id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'metadata' => [
],
'retry_offsets_days' => [
15
],
'product_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'quantity' => 500000
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.pagou.ai/v2/subscriptions/{id}"
payload := strings.NewReader("{\n \"metadata\": {},\n \"retry_offsets_days\": [\n 15\n ],\n \"product_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"quantity\": 500000\n}")
req, _ := http.NewRequest("PATCH", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.patch("https://api.pagou.ai/v2/subscriptions/{id}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"metadata\": {},\n \"retry_offsets_days\": [\n 15\n ],\n \"product_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"quantity\": 500000\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.pagou.ai/v2/subscriptions/{id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"metadata\": {},\n \"retry_offsets_days\": [\n 15\n ],\n \"product_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"quantity\": 500000\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"requestId": "0190a2b4-18a7-7de0-9a43-69b7cf261201",
"data": {
"id": "string",
"customerId": "string",
"status": "incomplete",
"paymentMethod": "credit_card",
"billingModel": "merchant_initiated",
"billingDayOfMonth": 1,
"interval": "day",
"intervalCount": 1,
"amount": 0,
"currency": "BRL",
"trialEnd": "2026-07-14T12:00:00.000Z",
"currentPeriodStart": "2026-07-14T12:00:00.000Z",
"currentPeriodEnd": "2026-07-14T12:00:00.000Z",
"cancelAtPeriodEnd": false,
"canceledAt": "2026-07-14T12:00:00.000Z",
"failurePolicy": "immediate_cancel",
"retryOffsetsDays": [
1
],
"cancellationReason": "user_requested",
"customerEmail": "string",
"cardLast4": "string",
"metadata": {},
"informations": [
{
"key": "string",
"value": "string"
}
],
"products": [
{
"name": "string",
"price": 0,
"quantity": 1,
"tangible": false
}
],
"recurringAuthorization": {
"status": "pending"
},
"createdAt": "2026-07-14T12:00:00.000Z",
"updatedAt": "2026-07-14T12:00:00.000Z"
}
}{
"title": "<string>",
"status": 0,
"type": "<string>",
"detail": "<string>",
"instance": "<string>"
}{
"title": "<string>",
"status": 0,
"type": "<string>",
"detail": "<string>",
"instance": "<string>"
}{
"title": "<string>",
"status": 0,
"type": "<string>",
"detail": "<string>",
"instance": "<string>"
}{
"title": "<string>",
"status": 0,
"type": "<string>",
"detail": "<string>",
"instance": "<string>"
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>"
}
