SelectwinSelectwin

SDK da Selectwin para Node.js

O SDK oficial da Selectwin para Node.js e TypeScript (@selectwin/sdk): pagamentos (cartão de crédito, Pix, boleto), assinaturas, carteiras, webhooks e mais.

Shell
npm install @selectwin/sdk

Primeiros passos

TypeScript
import { Selectwin, CardError } from '@selectwin/sdk';

const sw = new Selectwin(process.env.SELECTWIN_API_KEY!); // sk_test_… / sk_live_…

// Crie uma transação Pix (valores em centavos). Atalho conciso: passe o corpo direto
const tx = await sw.transactions.create({ amount: 9990, payment: { method: 'pix', currency: 'BRL' } });

// Atalhos com id + corpo / só com id:
await sw.subscriptions.pause('subs_…');
await sw.subscriptions.cancel('subs_…', { /* … */ });
const one = await sw.transactions.retrieve('tra_…');

// Erros tipados: decida pela classe ou pelo error.code, nunca pela mensagem
try {
  await sw.transactions.create({ /* … */ });
} catch (err) {
  if (err instanceof CardError) {
    console.log(err.displayMessage, err.reversible); // texto ao comprador + se pode repetir
  }
}

Cada recurso é um namespace com atalhos concisos (create, retrieve, update, list, delete, além de verbos do recurso, como sw.subscriptions.pause('subs_…')). A API gerada inteira (todos os métodos por operationId) continua ao alcance pelo .raw:

TypeScript
await sw.transactions.raw.createTransaction({ /* … */ });

Paginação

Os métodos list() de primeiro nível paginam sozinhos. O valor devolvido serve ao await (a primeira página) e ao for await (todos os itens, de todas as páginas):

TypeScript
// percorre todas as transações, de todas as páginas
for await (const tx of sw.transactions.list({ limit: 100 })) {
  // …
}

const firstPage = await sw.transactions.list({ limit: 20 }); // { data, hasMore, offset, … }
const all = await sw.customers.list().toArray();             // ou .toArray(500), com teto
for await (const page of sw.transactions.list().pages()) { /* page.data */ }

Para os endpoints que não ganharam paginação automática (as listas de sub-recursos, por exemplo), o auxiliar de baixo nível paginate funciona sobre qualquer função de listagem:

TypeScript
import { paginate } from '@selectwin/sdk';
for await (const item of paginate((p) => sw.subscriptions.raw.listSubscriptionItems({ subscriptionId: 'subs_…', ...p }), { limit: 100 })) { /* … */ }

Webhooks

O constructEvent confere a assinatura e devolve uma união discriminada sobre todo o catálogo de eventos: o switch (event.type) estreita o event.payload.object para o formato do recurso correspondente:

TypeScript
// rawBody PRECISA ser exatamente os bytes/a string recebidos (não serialize de novo)
const event = sw.webhooks.constructEvent(
  rawBody,
  req.headers['x-selectwin-signature'],
  process.env.SELECTWIN_WEBHOOK_SECRET!, // whsec_…
);

switch (event.type) {
  case 'transaction.approved':
    event.payload.object.id; // tipado com o formato da leitura da transação
    break;
  case 'subscription.paused':
    event.payload.object; // tipado com o formato da leitura da assinatura
    break;
}

O event.type completa todos os valores do catálogo (WebhookEventType). O próprio catálogo é exportado para validação, com o WEBHOOK_EVENT_TYPES (tupla somente leitura) e o isWebhookEventType(x), junto com os grupos por recurso (TransactionEventType, SubscriptionEventType, …) e o mapa WebhookEventObjectMap (tipo → objeto). Quer afirmar você mesmo o formato do objeto? Passe um argumento de tipo: constructEvent<MyType>(rawBody, sig, secret).

O que o SDK acrescenta ao cliente gerado

O pacote é um núcleo gerado (da especificação OpenAPI v2.0.0) mais uma camada de conveniência escrita à mão:

  • Cliente tipado: new Selectwin(key) → sw.transactions, sw.subscriptions, sw.customers, …
  • Atalhos concisos por recurso (.create/.retrieve/.update/.list/.delete e verbos próprios), que chamam os métodos gerados com os tipos exatos. O CRUD comum é achatado, create(body), retrieve(id), update(id, body), e os métodos mais complexos (sub-recursos com vários ids, listagens) ficam na forma de objeto. O .raw expõe toda a superfície gerada.
  • Erros tipados pelo status HTTP e pelo error.code: CardError (402, displayMessage/reversible), ValidationError (params), RateLimitError (retryAfter), AuthenticationError, PermissionError, NotFoundError, ConflictError, ApiError, ApiConnectionError.
  • Novas tentativas automáticas (429, 5xx e falha de rede), com backoff exponencial e respeitando o Retry-After.
  • Idempotência: toda operação de escrita leva um X-Idempotency-Key (para usar o seu, passe nos headers).
  • Tempo limite (AbortController).
  • Paginação automática: o list() de primeiro nível devolve um AutoPager (await = a primeira página, for await = todos os itens, .toArray(), .pages()); e há o auxiliar de baixo nível paginate(listFn, params).
  • Verificação de webhook e eventos tipados: o constructEvent (HMAC-SHA256 do corpo bruto, em tempo constante) devolve uma união discriminada sobre o catálogo de eventos, e o switch (event.type) estreita o event.payload.object. O catálogo é gerado da especificação, então nunca fica defasado.

A autenticação vai no header SelectKey; o ambiente (sandbox ou produção) sai do prefixo da chave (sk_test_ / sk_live_).

Arquitetura

Texto
src/
  generated/        # saída do openapi-generator typescript-fetch — NÃO edite; vem do selectwin-sdks
  namespaces.ts     # GERADO: wrappers tipados (gen-namespaces.mjs) — NÃO edite
  webhook-events.ts # GERADO: catálogo de eventos tipado + união discriminada — NÃO edite
  http.ts           # fetch próprio (tentativas/tempo limite) + middleware (idempotência, erros)
  errors.ts         # hierarquia de erros tipados
  webhooks.ts       # constructEvent (verificação da assinatura)
  pagination.ts     # paginate() + AutoPager
  client.ts         # Selectwin: liga uma Configuration a todos os namespaces
  index.ts          # exports públicos

O que vale para todas as chamadas entra uma vez só na Configuration gerada (fetchApi + middleware): todo endpoint herda, e endpoint novo funciona sozinho quando o núcleo é gerado de novo.

Desenvolvimento

Shell
npm run sync:core         # traz o núcleo gerado do selectwin-sdks e refaz namespaces e eventos
npm run gen:namespaces    # refaz o src/namespaces.ts a partir do núcleo gerado
npm run gen:webhook-events # refaz o src/webhook-events.ts (catálogo de eventos tipado)
npm run typecheck         # tsc --noEmit (src + test; confere também as asserções de tipo)
npm test                  # vitest (errors, webhooks, webhook-events, pagination, http, client)
npm run test:integration  # suíte de integração no sandbox (veja abaixo)
npm run build             # tsup → ESM/CJS e d.ts em dist/

O sync:core já roda o gen:namespaces e o gen:webhook-events. O núcleo é gerado da especificação OpenAPI no selectwin-sdks; a camada de conveniência em src/ (menos os gerados namespaces.ts e webhook-events.ts) é mantida à mão.

Testes de integração (sandbox)

O test/integration/** roda contra a API de sandbox de verdade e se protege sozinho: toda suíte é pulada (o npm test nunca vai à rede) a menos que haja uma chave de sandbox. Passe uma e rode a suíte à parte:

Shell
SELECTWIN_SANDBOX_KEY=sk_test_... npm run test:integration
# SELECTWIN_API_KEY também vale, mas só se começar com sk_test_ (nunca uma chave de produção).
# SELECTWIN_BASE_URL troca o host, se preciso (sandbox ou produção sai do prefixo da chave).

Cobertura: um teste rápido só de leitura (autenticação, envelope das listas e paginação automática em vários recursos), o mapa de erros tipados (chave inválida → AuthenticationError) e uma volta completa de cliente (criar → consultar → excluir), mais a repetição com a mesma chave de idempotência. As escritas são só no sandbox e se desfazem no afterAll.

Documentação

Os guias completos e a referência da API ficam em selectwin.io/docs.

Atualizado em 21 de outubro de 2026

Preferências de cookies

Hoje o site usa só cookies essenciais: nenhuma ferramenta de medição ou de anúncios está ligada, e nada é compartilhado com terceiros. Se isso mudar, você decide aqui antes de qualquer coisa ser carregada.

  • Mantêm o site funcionando: segurança, a sua escolha sobre cookies e preferências como a versão da documentação. Não dependem de consentimento.

    Sempre ativos