AY Payments SDK
SDK TypeScript/JavaScript oficial para a API da AY Payments.
Docs completas: https://aypayments.undernouzen.com.br/docs/
Instalar
npm install @undernouzen/ay-payments-sdkpnpm add @undernouzen/ay-payments-sdkCliente
import { createAYPaymentsClient } from "@undernouzen/ay-payments-sdk";
const ay = createAYPaymentsClient({
baseUrl: "https://aypayments.undernouzen.com.br",
apiKey: process.env.AYP_API_KEY,
language: "pt-BR",
});O endpoint publico continua sendo:
https://aypayments.undernouzen.com.br/api/v1
v3 e o contrato atual de dados da plataforma. A URL publica permanece /api/v1.
Idioma
O SDK envia x-ay-language e Accept-Language quando language e configurado.
const ay = createAYPaymentsClient({
apiKey: "ayp_secret",
language: "pt-BR",
});
await ay.language("en-US").products.list();
await ay.idioma("pt-BR").products.list();
await ay.checkouts.create(payload, {
headers: { "x-ay-language": "pt-BR" },
});Erros
Todos os erros da API retornam code estavel e error humano.
import { isApiError } from "@undernouzen/ay-payments-sdk";
const result = await ay.products.get("product_id");
if (isApiError(result)) {
console.log(result.code, result.error);
}Produtos v3
Produtos usam type: "single" | "variant" e sempre possuem pricing, inventory e availability.
const product = await ay.products.createGlobal({
projectId: "project_id",
connectedAccountId: "acct_connected",
type: "variant",
sku: "guild-vip",
name: "VIP Guild",
pricing: {
defaultCurrency: "BRL",
prices: [
{
currency: "BRL",
value: "29.90",
compareAtValue: "39.90",
promotion: { enabled: true, label: "Lancamento" },
},
{ currency: "USD", value: "7.99" },
],
},
inventory: {
trackStock: true,
stockQuantity: 500,
maxQuantityPerOrder: 5,
},
availability: {
availableFrom: Date.now(),
},
variants: [
{
externalId: "base",
sku: "guild-vip-base",
name: "Base",
isDefault: true,
pricing: { mode: "base", prices: [] },
inventory: { mode: "inherit" },
availability: { mode: "inherit" },
},
{
externalId: "premium",
sku: "guild-vip-premium",
name: "Premium",
pricing: {
mode: "absolute",
prices: [{ currency: "BRL", value: "49.90" }],
},
inventory: {
mode: "override",
trackStock: true,
stockQuantity: 100,
},
availability: { mode: "inherit" },
},
],
metadata: { guildId: "832320430277918720" },
mediaGallery: [{ type: "image", url: "https://cdn.example.com/vip.png" }],
});Produtos salvos nao aceitam override de preco no checkout. O preco e a moeda sao resolvidos pelo produto, variante e price selecionados.
Categorias
await ay.categories.createGlobal({
projectId: "project_id",
name: "Discord",
icon: "https://cdn.example.com/category.png",
metadata: { source: "panel" },
});Contas de provedores
name identifica a conta global reutilizavel do merchant. alias identifica o nome custom dessa conta dentro de um projeto.
await ay.accounts.updateProjects("provider-account-id", {
projectIds: ["project_id"],
alias: "Mercado Pago - Loja Discord",
});
await ay.projects.accounts.update("project_id", "connection_id", {
alias: "Mercado Pago - Loja Discord",
});O campo legado name ainda e aceito em conexoes de projeto para compatibilidade, mas novas integracoes devem usar alias.
Cupons v3
Cupons usam discount, targets, limits e availability.
await ay.coupons.create({
projectId: "project_id",
name: "Promocao VIP",
code: "VIP10",
discount: {
type: "percentage",
value: "10",
maxDiscountAmount: "25.00",
},
targets: [
{ type: "product", id: "product_id" },
{ type: "product_category", id: "category_id" },
{ type: "subscription_plan", id: "plan_id" },
],
limits: {
minimumAmount: "20.00",
maxRedemptions: 500,
maxRedemptionsPerCustomer: 1,
},
availability: {
availableFrom: Date.now(),
},
});Checkouts
Um checkout pode ter multiplos itens, inclusive do mesmo produto/variante. Todos os itens devem resolver para a mesma currency.
const checkout = await ay.checkouts.create({
projectId: "project_id",
provider: "stripe",
currency: "BRL",
commissionProfileKey: "default_sale",
idempotencyKey: "guild-832320430277918720-order-001",
customer: {
email: "cliente@example.com",
name: "Luis",
},
items: [
{
productId: "product_id",
variantId: "premium",
quantity: 2,
metadata: { slot: "discord-role" },
},
],
couponCodes: ["VIP10"],
metadata: {
guildId: "832320430277918720",
},
webhookEndpoints: [
{
name: "Backend principal",
url: "https://merchant.example.com/webhooks/aypayments",
secret: "secret_opcional",
events: ["order.created", "payment.paid", "refund.succeeded"],
},
],
}, {
idempotencyKey: "guild-832320430277918720-order-001",
});Tambem e possivel usar commissionProfileId. Se nenhum profile for enviado, a API usa o default compativel quando existir; policies obrigatorias sem profile explicito/default bloqueiam o calculo.
Checkout de assinatura ainda nao esta habilitado. Planos de assinatura podem ser cadastrados, mas a criacao de checkout recorrente sera ligada em uma fase futura.
Payments, refunds e finance
await ay.payments.list({ projectId: "project_id", status: "paid" });
await ay.payments.sync("payment_id");
await ay.refunds.create({
orderId: "order_id",
amount: "10.00",
reason: "customer_request",
idempotencyKey: "refund-order-001",
});
await ay.finance.ledger.list({ projectId: "project_id" });
await ay.finance.auditLogs.list({ resourceType: "order" });
await ay.finance.providerEvents.reprocess("provider_event_id");Refund parcial e previsto pelo contrato. Quando o provider nao suportar ou a credencial ainda nao permitir a operacao, a API retorna erro claro com code.
Webhook endpoints e deliveries
Configure destinos com webhookEndpoints. O secret nunca volta na resposta; use hasSecret.
await ay.webhookEndpoints.createForProject("project_id", {
name: "Projeto",
url: "https://merchant.example.com/webhooks/project",
secret: "secret_opcional",
events: ["payment.paid"],
});
await ay.webhookEndpoints.createForProduct("product_id", {
name: "Produto VIP",
url: "https://merchant.example.com/webhooks/product-vip",
events: ["payment.paid", "refund.succeeded"],
});
const { webhookEndpoints } = await ay.webhookEndpoints.listForProject("project_id");Webhooks enviados pela AY Payments ficam em webhooks.deliveries.
await ay.webhooks.deliveries.list({ status: "failed" });
await ay.webhooks.deliveries.get("delivery_id");
await ay.webhooks.deliveries.retry("delivery_id");
await ay.webhooks.retryMany({ ids: ["delivery_id"] });Eventos recebidos de Stripe/Mercado Pago ficam em finance.providerEvents.
Subscription plans
Planos de assinatura estao disponiveis para cadastro e preparacao de catalogo.
await ay.subscriptionPlans.create({
projectId: "project_id",
slug: "premium-monthly",
name: "Premium mensal",
interval: "month",
intervalCount: 1,
prices: [{ currency: "BRL", value: "29.90" }],
features: [
{ key: "support", label: "Suporte prioritario", included: true },
],
});Raw
const response = await ay.raw<{ ok: boolean }>({
method: "GET",
url: "/projects",
});