Referência completa do endpoint com exemplos TypeScript. Todos os exemplos usam o handypay ajudante da Início Rápido. O Tooling pode baixar o Contrato OpenAPI 3.1.
URL Base
https://api.handypay.me/api/v1Versão do API: 2025-01-01 (retorno em X-API-Version cabeçalho em cada resposta).
Autenticação
Todos os pedidos requerem um token do portador na Authorization Cabeçalho.
Authorization: Bearer hp_live_your_api_key_here- Chaves prefixadas com
hp_live_são para produção. - Chaves prefixadas com
hp_test_são para o sandbox/testing. - Gerar e gerenciar chaves a partir do Portal do lojista.
O modo de teste está totalmente isolado
Cada hp_test_ A requisição utiliza uma conta de teste dedicada. Produtos de teste, clientes, pagamentos, assinaturas e terminais webhook nunca aparecem em atividades de negócios ao vivo. Veja-os no Espaço de trabalho do modo de teste.
curl https://api.handypay.me/api/v1/test-payments \
-H "Authorization: Bearer hp_test_your_api_key_here"Limites de Taxa
1.000 pedidos por hora por chave do API. Excedendo o limite retorna 429 com uma Retry-After Cabeçalho.
Formato de resposta
Cada resposta é envolto num envelope padrão.
Sucesso
{
"success": true,
"data": { ... },
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}Erro
{
"success": false,
"error": {
"code": "validation_error",
"message": "Name is required"
},
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}Paginação
Todos os parâmetros de lista usam paginação baseada em cursores.
| Campo | Tipo | Requerido | Designação das mercadorias |
|---|---|---|---|
| limit | number | Não | Itens por página (1–100, padrão 10) |
| starting_after | string | Não | ID do último item da página anterior |
Resposta inclui has_more: true quando existem páginas adicionais.
Produtos
Crie e gerencie produtos para compras únicas.
| Método | Localização | Designação das mercadorias |
|---|---|---|
| POST | /v1/products | Criar um produto |
| GET | /v1/products | Produtos da lista |
| GET | /v1/products/:id | Obter um produto |
| PUT | /v1/products/:id | Actualizar um produto |
| DELETE | /v1/products/:id | Arquivar um produto |
Criar um produto
const product = await handypay("/products", {
method: "POST",
body: JSON.stringify({
name: "Premium Plan",
description: "Access to all features",
price: {
amount: 2999,
currency: "usd",
},
}),
});
console.log(product.id); // "prod_abc123"exemplo cURL
curl -X POST https://api.handypay.me/api/v1/products \
-H "Authorization: Bearer hp_live_..." \
-H "Content-Type: application/json" \
-d '{
"name": "Premium Plan",
"description": "Access to all features",
"price": {
"amount": 2999,
"currency": "usd"
}
}'Organismo de pedido
| Campo | Tipo | Requerido | Designação das mercadorias |
|---|---|---|---|
| name | string | Sim. | Denominação do produto |
| description | string | Não | Descrição do produto |
| images | string[] | Não | Até 8 URLs de imagens |
| metadata | object | Não | Pares de valor de chave personalizados (até 50 teclas) |
| active | boolean | Não | Verdadeiro padrão |
| url | string | Não | Página do produto URL em seu site |
| shippable | boolean | Não | Se o produto requer ou não envio |
| unit_label | string | Não | Rótulo por unidade (por exemplo: "sede", "licença") |
| statement_descriptor | string | Não | Texto do extrato bancário (máximo de 22 caracteres) |
| tax_code | string | Não | Código fiscal do Stripe |
| price.amount | number | Não | Preço na unidade monetária mais pequena (cents) |
| price.currency | string | Não | Código monetário do ISO 4217 (por exemplo: "usd", "jmd") |
| price.tax_behavior | string | Não | Inclusivo, exclusivo ou não especificado |
Clientes
Gerencie registros de clientes para compras e assinaturas repetidas.
| Método | Localização | Designação das mercadorias |
|---|---|---|
| POST | /v1/customers | Criar um cliente |
| GET | /v1/customers | Listar clientes |
| GET | /v1/customers/:id | Obter um cliente |
| PUT | /v1/customers/:id | Atualizar um cliente |
| DELETE | /v1/customers/:id | Apagar um cliente |
Criar um cliente
const customer = await handypay("/customers", {
method: "POST",
body: JSON.stringify({
email: "customer@example.com",
name: "Jane Doe",
}),
});
console.log(customer.id); // "cus_abc123"exemplo cURL
curl -X POST https://api.handypay.me/api/v1/customers \
-H "Authorization: Bearer hp_live_..." \
-H "Content-Type: application/json" \
-d '{
"email": "customer@example.com",
"name": "Jane Doe"
}'Organismo de pedido
| Campo | Tipo | Requerido | Designação das mercadorias |
|---|---|---|---|
| string | Sim. | E- mail do cliente | |
| name | string | Não | Nome do cliente |
| phone | string | Não | Número de telefone do cliente |
| metadata | object | Não | Pares de valor de chave personalizados |
Sessões de pagamento
Create hosted checkout sessions for one-time payments. Standard HandyPay pricing applies: 4.9% + US$0.40 per transaction on the Free and Brand plans, or 4.2% + US$0.40 on Pro. There is no extra API or platform fee on top.
| Método | Localização | Designação das mercadorias |
|---|---|---|
| POST | /v1/payment-sessions | Criar uma sessão de pagamento |
| GET | /v1/payment-sessions/:id | Obter o estado da sessão |
| GET | /v1/test-payments | Pagamentos de teste da lista (apenas para hp_test_) |
Criar uma sessão de pagamento (com o preço existente)
const session = await handypay("/payment-sessions", {
method: "POST",
body: JSON.stringify({
line_items: [{ price_id: "price_abc123", quantity: 1 }],
success_url: "https://yoursite.com/success?session_id={CHECKOUT_SESSION_ID}",
cancel_url: "https://yoursite.com/cancel",
}),
});
// Redirect customer to checkout
window.location.href = session.url;exemplo cURL
curl -X POST https://api.handypay.me/api/v1/payment-sessions \
-H "Authorization: Bearer hp_live_..." \
-H "Content-Type: application/json" \
-d '{
"line_items": [{ "price_id": "price_abc123", "quantity": 1 }],
"success_url": "https://yoursite.com/success?session_id={CHECKOUT_SESSION_ID}",
"cancel_url": "https://yoursite.com/cancel"
}'Criar uma sessão de pagamento (quantidade personalizada)
const session = await handypay("/payment-sessions", {
method: "POST",
body: JSON.stringify({
line_items: [{
amount: 5000,
currency: "usd",
name: "Custom Order",
quantity: 1,
}],
success_url: "https://yoursite.com/success?session_id={CHECKOUT_SESSION_ID}",
cancel_url: "https://yoursite.com/cancel",
}),
});exemplo cURL
curl -X POST https://api.handypay.me/api/v1/payment-sessions \
-H "Authorization: Bearer hp_live_..." \
-H "Content-Type: application/json" \
-d '{
"line_items": [{
"amount": 5000,
"currency": "usd",
"name": "Custom Order",
"quantity": 1
}],
"success_url": "https://yoursite.com/success?session_id={CHECKOUT_SESSION_ID}",
"cancel_url": "https://yoursite.com/cancel"
}'Organismo de pedido
| Campo | Tipo | Requerido | Designação das mercadorias |
|---|---|---|---|
| line_items | array | Sim. | Pelo menos uma linha de item |
| success_url | string | Sim. | Redirecionar o URL após o pagamento bem-sucedido |
| cancel_url | string | Sim. | Redirecionar o URL se o cliente cancelar |
| customer_id | string | Não | Cliente existente ID |
| customer_email | string | Não | Pré-preencher o e-mail (se não houver customer_id) |
| pass_fees_to_customer | boolean | Não | Adicionar taxas de processamento e serviço ao total do cliente |
| metadata | object | Não | Pares de valor de chave personalizados |
| collect_shipping_address | boolean | Não | Recolha um endereço de envio |
| billing_address_collection | string | Não | auto ou necessário |
| shipping_countries | string[] | Não | Países de destino permitidos do ISO-2 |
| shipping_options | array | Não | Selos e montantes de envio na unidade monetária mais pequena |
Campos de itens de linha
| Campo | Tipo | Requerido | Designação das mercadorias |
|---|---|---|---|
| price_id | string | Não | Stripe Price ID existente |
| amount | number | Não | Quantidade personalizada em cêntimos |
| currency | string | Não | Obrigatório com montante |
| name | string | Não | Obrigatório com montante |
| quantity | number | Sim. | Quantidade |
Fornecer qualquer um dos price_id ou amount+currency+name por item de linha.
Which line-item form should I use?
Utilização price_id line items to sell products from your HandyPay catalog, and amount + currency + name line items for amounts computed at request time. Both forms work for every HandyPay account: HandyPay decides where each session is hosted so card payments always work, with the same fees and payout flow as hosted payment links. Before August 29, 2026, accounts paid by cross-border payout could see "No valid payment method types for this Checkout Session" on price_id sessions; that is fixed, and no request changes are needed.
{CHECKOUT_SESSION_ID} no URL de sucesso. Consulte que ID com o mesmo comerciante e o mesmo modo de chave live/test que o criou. A sessão continua questionável após a conclusão, mas seu webhook assinado ainda deve conduzir o cumprimento da fatura.Pagamentos Incorporados
Crie um PaymentIntent no seu servidor quando quiser renderizar o Stripe Elements na sua própria página de checkout. A chave da API HandyPay permanece no servidor; envie ao navegador apenas a chave publicável retornada, o ID da conta conectada e o segredo de cliente de curta duração.
| Método | Localização | Designação das mercadorias |
|---|---|---|
| POST | /v1/payment-intents | Criar um PaymentIntent integrado |
const intent = await handypay("/payment-intents", {
method: "POST",
body: JSON.stringify({
amount: 5000,
currency: "ttd",
description: "Order #1042",
customer_email: "buyer@example.com",
pass_fees_to_customer: true,
metadata: { order_id: "1042" },
}),
});
// Pass these values to Stripe.js/Elements. Never pass HANDYPAY_API_KEY.
return {
clientSecret: intent.client_secret,
publishableKey: intent.publishable_key,
stripeAccount: intent.stripe_account,
};| Campo | Tipo | Requerido | Designação das mercadorias |
|---|---|---|---|
| amount | number | Sim. | Número inteiro positivo na unidade monetária mais pequena |
| currency | string | Sim. | ISO 4217 código de moeda de três letras |
| description | string | Não | Designação do pagamento |
| customer_email | string | Não | Email do cliente para recibos e reconciliação |
| pass_fees_to_customer | boolean | Não | Reembolso do valor para que o cliente cubra as taxas |
| metadata | object | Não | Identificadores de sua encomenda ou fatura |
Montante das restituições
Reembolso de um pagamento de propriedade do comerciante autenticado. O HandyPay verifica a propriedade do pagamento e o saldo disponível antes de criar a inversão. Omitir amount para um reembolso total.
| Método | Localização | Designação das mercadorias |
|---|---|---|
| POST | /v1/refunds | Criar um reembolso total ou parcial |
const refund = await handypay("/refunds", {
method: "POST",
body: JSON.stringify({
session_id: "cs_live_...",
amount: 2500,
reason: "requested_by_customer",
}),
});
console.log(refund.id, refund.status);| Campo | Tipo | Requerido | Designação das mercadorias |
|---|---|---|---|
| session_id | string | Condicional | ID da Checkout Session (cs_...). Use este campo ou payment_intent |
| payment_intent | string | Condicional | ID do PaymentIntent (pi_...). Use este campo ou session_id |
| amount | number | Não | Montante parcial da restituição na unidade monetária mais pequena |
| reason | string | Não | duplicate, fraudulent ou requested_by_customer |
Um pagamento contestado, totalmente reembolsado, de troca cruzada ou insuficiente é rejeitado sem criar um reembolso.
Litígios
Reveja os encargos para o comerciante conectado e fornecer evidências antes da data de vencimento.
| Método | Localização | Designação das mercadorias |
|---|---|---|
| GET | /v1/disputes | Listar litígios |
| GET | /v1/disputes/:id | Obter uma disputa e seu status de evidência |
| POST | /v1/disputes/:id/evidence | Actualizar ou apresentar elementos de prova |
const dispute = await handypay("/disputes/dp_123/evidence", {
method: "POST",
body: JSON.stringify({
evidence: {
customer_email_address: "buyer@example.com",
product_description: "Annual software subscription",
customer_communication: "https://files.example.com/evidence/1042.pdf",
},
submit: false,
}),
});| Campo | Tipo | Requerido | Designação das mercadorias |
|---|---|---|---|
| evidence | object | Não | Stripe disputa campos de evidência como valores de string |
| submit | boolean | Não | Definir o valor verdadeiro apenas quando a evidência estiver completa e pronta para revisão |
Assinaturas
Crie produtos recorrentes e gerencie assinaturas.
Produtos de assinatura
| Método | Localização | Designação das mercadorias |
|---|---|---|
| POST | /v1/subscription-products | Criar um produto de subscrição |
| GET | /v1/subscription-products | Listar produtos de assinatura |
Sessões de Assinatura & Gestão
| Método | Localização | Designação das mercadorias |
|---|---|---|
| POST | /v1/subscription-sessions | Criar a verificação da subscrição |
| GET | /v1/subscriptions | Listar as assinaturas activas |
| PATCH | /v1/subscriptions/:id/quantity | Mudar de assento com pronunciação explícita |
| POST | /v1/subscriptions/:id/cancel | Cancelar no final do período de faturamento |
Choose the right session form
Both forms work for every HandyPay account: HandyPay decides where the checkout is hosted so card payments always work, exactly like hosted subscription links. Use a price_id to sell a subscription product from your catalog; this form also supports trials, fee passing, and saved customers. Use the inline form (amount_cents + currency + interval) when the amount or schedule is computed at request time. Before August 29, 2026, accounts paid by cross-border payout could see "No valid payment method types for this Checkout Session" on price_id sessions; that is fixed, and no request changes are needed.
Intervalos de faturamento suportados
Criar um produto de subscrição
const subProduct = await handypay("/subscription-products", {
method: "POST",
body: JSON.stringify({
name: "Pro Plan",
description: "Monthly pro access",
amount: 1999,
currency: "usd",
interval: "monthly",
trial_period_days: 14,
}),
});
console.log(subProduct.price.id); // Use this price_id for subscription sessionsexemplo cURL
curl -X POST https://api.handypay.me/api/v1/subscription-products \
-H "Authorization: Bearer hp_live_..." \
-H "Content-Type: application/json" \
-d '{
"name": "Pro Plan",
"description": "Monthly pro access",
"amount": 1999,
"currency": "usd",
"interval": "monthly",
"trial_period_days": 14
}'Organismo de pedido
| Campo | Tipo | Requerido | Designação das mercadorias |
|---|---|---|---|
| name | string | Sim. | Denominação do produto |
| description | string | Não | Descrição do produto |
| amount | number | Sim. | Preço na unidade monetária mais pequena |
| currency | string | Sim. | ISO 4217 código monetário |
| interval | string | Sim. | Um dos intervalos suportados |
| trial_period_days | number | Não | Duração da experiência gratuita em dias |
| metadata | object | Não | Pares de valor de chave personalizados |
Create checkout with a saved price
const session = await handypay("/subscription-sessions", {
method: "POST",
body: JSON.stringify({
price_id: subProduct.price.id,
quantity: 5,
customer_email: signedInUser.email, // Prefills the subscriber's email
trial_period_days: 14,
success_url: "https://example.com/success",
cancel_url: "https://example.com/plans",
}),
});
// Redirect the customer to session.urltrial_period_days, pass_fees_to_customer, e customer_id apply only to price_id sessions.
Prefill the subscriber's email
For API-created sessions, send customer_email from your server. Checkout opens with the address already filled, and the same address is used for receipts. If you provide customer_id, HandyPay uses that existing customer instead. Keep your HandyPay API key on the server.
Reusable hosted subscription links can also prefill email without an API request. Add the email query parameter with URLSearchParams before redirecting the customer:
const checkoutUrl = new URL("YOUR_HANDYPAY_SUBSCRIPTION_LINK");
// URLSearchParams safely encodes the email address.
checkoutUrl.searchParams.set("email", signedInUser.email);
window.location.assign(checkoutUrl.toString());Prefer server-created sessions when possible. Query parameters can appear in browser history and logs, so only add an email address the customer has already provided to your application.
Create a subscription checkout (inline pricing)
// Inline pricing - use when the amount or schedule is computed at
// request time instead of coming from a saved subscription product.
const session = await handypay("/subscription-sessions", {
method: "POST",
body: JSON.stringify({
amount_cents: 1999,
currency: "ttd",
interval: "month", // day | week | month | year
interval_count: 1, // e.g. 3 with "month" = quarterly
name: "Pro Plan",
quantity: 1,
customer_email: signedInUser.email, // Prefills the subscriber's email
success_url: "https://example.com/success?session_id={CHECKOUT_SESSION_ID}",
cancel_url: "https://example.com/plans",
}),
});Request body (inline form)
| Campo | Tipo | Requerido | Designação das mercadorias |
|---|---|---|---|
| amount_cents | number | Sim. | Recurring price in the smallest currency unit |
| currency | string | Sim. | ISO 4217 code. USD, TTD, JMD, XCD, and other supported settlement currencies |
| interval | string | Sim. | day, week, month, or year |
| interval_count | number | Não | Billing every N intervals, 1-52 (default 1) |
| name | string | Não | Product name shown at checkout |
| quantity | number | Não | Seats from 1 to 1,000 (default 1) |
| customer_email | string | Não | Pre-fill the customer email |
| success_url | string | Sim. | Redirect URL after checkout |
| cancel_url | string | Sim. | Redirect URL if the customer cancels |
| metadata | object | Não | Custom key-value pairs, echoed on webhooks |
Mudar de lugar numa subscrição activa
Quantidade deve ser um inteiro de 1 a 1.000. Escolha como o ajuste de faturamento é tratado em vez de confiar em um padrão implícito.
const updated = await handypay("/subscriptions/sub_123/quantity", {
method: "PATCH",
body: JSON.stringify({
quantity: 8,
proration_behavior: "create_prorations",
}),
});| Campo | Tipo | Requerido | Designação das mercadorias |
|---|---|---|---|
| quantity | number | Sim. | Nova contagem de assentos de 1 a 1.000 |
| proration_behavior | string | Não | create_prorations, always_invoice ou none |
| item_id | string | Não | Rubrica específica da subscrição quando uma subscrição tem vários produtos |
Webhooks
Receba notificações de eventos em tempo real através do HTTP POST para seus objetivos.
| Método | Localização | Designação das mercadorias |
|---|---|---|
| POST | /v1/webhook-endpoints | Registar um ponto final |
| GET | /v1/webhook-endpoints | Endpoints da lista |
| DELETE | /v1/webhook-endpoints/:id | Desactivar um ponto final |
- Os pontos de extremidade devem usar o HTTPS.
- Endpoints Webhook registrados com um
hp_test_A chave recebe apenas os eventos de teste. Os destinos vivos e de ensaio são armazenados separadamente. - Cada endpoint ativo subscrito a um evento recebe uma entrega independente assinada com o segredo próprio desse endpoint. Não reutilize o segredo de um ponto final para outro.
- Retorne uma resposta de 2xx em 10 segundos. Armazenar cada evento
idantes de efeitos secundários, por isso, as entregas duplicadas são seguras. - Após 10 falhas consecutivas de entrega, um ponto final é automaticamente desativado.
Tipos de eventos suportados
- payment_intent.succeeded
- payment_intent.payment_failed
- checkout.session.completed
- checkout.session.expired
- checkout.session.async_payment_succeeded
- checkout.session.async_payment_failed
- customer.subscription.created
- customer.subscription.updated
- customer.subscription.deleted
- charge.refunded
- charge.dispute.created
- charge.dispute.closed
payment_intent.payment_failed o evento identifica o PaymentIntent em data.id; use seus metadados (por exemplo order_id) para conciliá-lo. Utilização checkout.session.expired para a expiração da sessão e os eventos assinc para os métodos de pagamento atrasados.Verificando assinaturas do webhook
Cada entrega inclui uma X-HandyPay-Signature cabeçalho no formato sha256={hex}. Verifique computando o HMAC-SHA256 do corpo de solicitação bruto usando o segredo de assinatura do seu endpoint:
import { createHmac, timingSafeEqual } from "node:crypto";
function verifySignature(
payload: string | Buffer,
secret: string,
signature: string
): boolean {
const prefix = "sha256=";
if (!signature.startsWith(prefix)) return false;
const hex = signature.slice(prefix.length);
if (!/^[0-9a-f]{64}$/i.test(hex)) return false;
const expected = createHmac("sha256", secret).update(payload).digest();
const received = Buffer.from(hex, "hex");
return received.length === expected.length && timingSafeEqual(received, expected);
}Manipulador de rota de API do Next.js
import { NextRequest, NextResponse } from "next/server";
import { createHmac, timingSafeEqual } from "node:crypto";
export const runtime = "nodejs";
const SECRET = process.env.HANDYPAY_WEBHOOK_SECRET;
if (!SECRET) throw new Error("HANDYPAY_WEBHOOK_SECRET is not configured");
function hasValidSignature(payload: string, signature: string): boolean {
const prefix = "sha256=";
if (!signature.startsWith(prefix)) return false;
const hex = signature.slice(prefix.length);
if (!/^[0-9a-f]{64}$/i.test(hex)) return false;
const expected = createHmac("sha256", SECRET).update(payload).digest();
const received = Buffer.from(hex, "hex");
return received.length === expected.length && timingSafeEqual(received, expected);
}
export async function POST(req: NextRequest) {
const body = await req.text();
const signature = req.headers.get("x-handypay-signature") ?? "";
if (!hasValidSignature(body, signature)) {
return NextResponse.json({ error: "Invalid signature" }, { status: 401 });
}
let event: { id: string; type: string; data: unknown };
try {
event = JSON.parse(body);
} catch {
return NextResponse.json({ error: "Invalid JSON" }, { status: 400 });
}
// Persist event.id before side effects so redeliveries can be ignored safely.
switch (event.type) {
case "checkout.session.completed":
// Fulfill an immediate payment.
break;
case "checkout.session.async_payment_succeeded":
// Fulfill a delayed payment.
break;
case "charge.refunded":
// Mark the matching order as refunded.
break;
}
return NextResponse.json({ received: true });
}Manipulador Express.js
// Register this route BEFORE app.use(express.json()).
import express from "express";
import { createHmac, timingSafeEqual } from "node:crypto";
const router = express.Router();
const SECRET = process.env.HANDYPAY_WEBHOOK_SECRET;
if (!SECRET) throw new Error("HANDYPAY_WEBHOOK_SECRET is not configured");
function hasValidSignature(payload: Buffer, signature: string): boolean {
const prefix = "sha256=";
if (!signature.startsWith(prefix)) return false;
const hex = signature.slice(prefix.length);
if (!/^[0-9a-f]{64}$/i.test(hex)) return false;
const expected = createHmac("sha256", SECRET).update(payload).digest();
const received = Buffer.from(hex, "hex");
return received.length === expected.length && timingSafeEqual(received, expected);
}
router.post(
"/handypay",
express.raw({ type: "application/json" }),
(req, res) => {
const signature = String(req.headers["x-handypay-signature"] ?? "");
if (!hasValidSignature(req.body, signature)) {
return res.status(401).json({ error: "Invalid signature" });
}
const event = JSON.parse(req.body.toString("utf8"));
// Persist event.id before side effects so redeliveries are idempotent.
console.log("Verified HandyPay event", event.id, event.type);
return res.json({ received: true });
}
);
export default router;Formato de carga útil Webhook
{
"id": "evt_abc123",
"type": "payment_intent.succeeded",
"created": 1706745600,
"data": { ... }
}Conta
Leia a carga e disponibilidade de pagamento do comerciante conectado, além da conta bancária de pagamento padrão. Os números de banco e roteamento são mascarados; apenas seus últimos quatro dígitos são devolvidos.
| Método | Localização | Designação das mercadorias |
|---|---|---|
| GET | /v1/account | Obter conta conectada e detalhes de pagamento mascarados |
const account = await handypay("/account");
console.log({
chargesEnabled: account.chargesEnabled,
payoutsEnabled: account.payoutsEnabled,
bank: account.bankAccount?.bankName,
last4: account.bankAccount?.last4,
});Códigos de Erros
| Código | HTTP | Designação das mercadorias |
|---|---|---|
| unauthorized | 401 | Chave do API em falta ou inválida |
| key_revoked | 401 | Chave API foi revogada |
| key_expired | 401 | A chave do API expirou |
| rate_limit_exceeded | 429 | Muitos pedidos |
| validation_error | 400 | A validação do corpo da solicitação falhou |
| invalid_url | 400 | success_url ou cancel_url inválido |
| invalid_interval | 400 | Intervalo de faturamento não suportado |
| product_not_found | 404 | O produto não existe |
| customer_not_found | 404 | O cliente não existe |
| session_not_found | 404 | A sessão de saída não existe |
| payment_not_found | 404 | O pagamento está faltando ou não é propriedade deste comerciante |
| subscription_not_found | 404 | A assinatura não existe |
| refund_not_allowed | 400 | O pagamento é contestado e não pode ser reembolsado |
| already_refunded | 400 | O pagamento já está totalmente reembolsado |
| refund_amount_too_large | 400 | Montante superior ao saldo remanescente reembolsável |
| insufficient_balance | 400 | O saldo disponível não pode cobrir a restituição |
| balance_verification_failed | 400 | Não foi possível verificar a propriedade ou disponibilidade de saldos |
| endpoint_not_found | 404 | Endpoint do API desconhecido |
| stripe_error | 502 | Stripe API retornou um erro |
| internal_error | 500 | Erro inesperado no servidor |
| payload_too_large | 413 | O organismo de solicitação excede 1MB |
| prohibited_content | 400 | O conteúdo viola a política de uso aceitável |
| webhook_url_must_be_https | 400 | Webhook URL deve usar HTTPS |
| key_creation_rate_exceeded | 429 | Muitas chaves criadas na janela de tempo |
| max_keys_reached | 400 | Teclas API máximas ativas alcançadas (25) |
Segurança
- Manter
hp_live_ehp_test_chaves no seu servidor. Nunca coloque-os no navegador JavaScript, aplicativos móveis, URLs, logs ou controle de fonte. - Todas as respostas incluem
X-Content-Type-Options: nosniff,X-Frame-Options: DENY, eStrict-Transport-SecurityCabeçalhos. - Solicitar limite do corpo: 1 MiB, incluindo pedidos em fluxo ou em blocos.
- Os terminais Webhook devem usar o HTTPS.
- Verifique assinaturas do webhook contra os bytes brutos exatos e compare digestos em tempo constante.
- Os nomes e descrições dos produtos são analisados contra uma lista de bloqueio de conteúdo proibida.
- Mais 5 violações de conteúdo em 24 horas suspenderá suas chaves do API.
Limites de chaves de API
- Max 3 chaves criadas por janela de 10 minutos.
- Max 10 chaves criadas por janela de 1 hora.
- Max 25 chaves activas por comerciante.