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.
npm install @selectwin/sdkPrimeiros passos
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:
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):
// 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:
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:
// 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/.deletee 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.rawexpõ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 umAutoPager(await= a primeira página,for await= todos os itens,.toArray(),.pages()); e há o auxiliar de baixo nívelpaginate(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 oswitch (event.type)estreita oevent.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
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úblicosO 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
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:
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