npm.io
3.2.0 • Published 1m ago

@undernouzen/ay-payments-sdk

Licence
MIT
Version
3.2.0
Deps
1
Size
317 kB
Vulns
0
Weekly
416

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-sdk
pnpm add @undernouzen/ay-payments-sdk

Cliente

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",
});

Keywords