| name | wompi-transactions |
| description | Full Wompi transaction lifecycle using @pulgueta/wompi. Covers getMerchant for acceptance_token, tokenizeCard and tokenizeNequi, getSignatureKey for SHA-256 integrity signature (amountInCents as-is, never multiplied), createTransaction with payment_method or payment_source_id, getTransaction, listTransactions with from_date/until_date/status filters, voidTransaction with nested data.transaction result, and pse.getFinancialInstitutions. Load when processing payments, tokenizing cards, computing signatures, or querying transaction history.
|
| type | core |
| library | @pulgueta/wompi |
| library_version | 3.0.0 |
| requires | ["wompi-client-setup"] |
| sources | ["pulgueta/wompi-node:packages/core/src/client/transactions/index.ts","pulgueta/wompi-node:packages/core/src/client/tokens/index.ts","pulgueta/wompi-node:packages/core/src/client/merchants/index.ts","pulgueta/wompi-node:packages/core/src/server.ts","pulgueta/wompi-node:packages/core/src/schemas.ts","pulgueta/wompi-node:packages/core/CHANGELOG.md"] |
This skill builds on wompi/client-setup. Read it first for key configuration and the error-first tuple pattern.
Setup
Complete card transaction: acceptance token → tokenize card → compute signature → create transaction.
import { WompiClient } from '@pulgueta/wompi';
import { getSignatureKey } from '@pulgueta/wompi/server';
const wompi = new WompiClient({
publicKey: process.env.WOMPI_PUBLIC_KEY!,
privateKey: process.env.WOMPI_PRIVATE_KEY!,
sandbox: process.env.NODE_ENV !== 'production',
});
const [merchantErr, merchant] = await wompi.merchants.getMerchant();
if (merchantErr) throw merchantErr;
const acceptanceToken = merchant.presigned_acceptance?.acceptance_token;
if (!acceptanceToken) throw new Error('Missing acceptance token');
const [tokenErr, token] = await wompi.tokens.tokenizeCard({
number: '4242424242424242',
cvc: '123',
exp_month: '12',
exp_year: '29',
card_holder: 'Pedro Pérez',
});
if (tokenErr) throw tokenErr;
const reference = `order-${Date.now()}`;
const amountInCents = 2_490_000;
const signature = await getSignatureKey({
reference,
amountInCents,
integrityKey: process.env.WOMPI_INTEGRITY_KEY!,
});
const [error, txn] = await wompi.transactions.createTransaction({
acceptance_token: acceptanceToken,
amount_in_cents: amountInCents,
currency: 'COP',
signature,
customer_email: 'buyer@example.com',
reference,
payment_method: { type: 'CARD', token: token.id, installments: 1 },
});
if (error) throw error;
console.log(txn.id, txn.status);
Core Patterns
Compute an integrity signature with optional expiration
Include expirationTime only when createTransaction also sets expiration_time. Both values must be identical — Wompi hashes them together.
import { getSignatureKey } from '@pulgueta/wompi/server';
const expirationTime = '2026-12-31T23:59:59.000Z';
const signature = await getSignatureKey({
reference: 'order-12345',
amountInCents: 2_490_000,
integrityKey: process.env.WOMPI_INTEGRITY_KEY!,
currency: 'COP',
expirationTime,
});
await wompi.transactions.createTransaction({
signature,
amount_in_cents: 2_490_000,
reference: 'order-12345',
expiration_time: expirationTime,
});
List and filter transactions
listTransactions requires privateKey. Dates must be YYYY-MM-DD (not ISO timestamps). page_size max is 200.
const [error, list] = await wompi.transactions.listTransactions({
from_date: '2024-01-01',
until_date: '2024-12-31',
status: 'APPROVED',
payment_method_type: 'CARD',
page: 1,
page_size: 50,
order: 'DESC',
});
if (error) throw error;
console.log(list.length, list[0]?.id);
Void a transaction and read the result
voidTransaction requires privateKey. The voided transaction is nested under data.transaction, not data directly. The response body may be empty (undefined) for a 201.
const [error, result] = await wompi.transactions.voidTransaction('txn-123', {
amount_in_cents: 2_490_000,
});
if (error) throw error;
const voided = result?.transaction;
console.log(voided?.id, voided?.status);
Tokenize Nequi and poll for status
Nequi tokenization is asynchronous. The token starts as PENDING and transitions to APPROVED or DECLINED.
const [tokenErr, nequiToken] = await wompi.tokens.tokenizeNequi({
phone_number: '3001234567',
});
if (tokenErr) throw tokenErr;
const [pollErr, updated] = await wompi.tokens.getNequiToken(nequiToken.id);
if (pollErr) throw pollErr;
console.log(updated.status);
Common Mistakes
CRITICAL Multiplying amountInCents by 100 before getSignatureKey
Wrong:
const priceInPesos = 24900;
const signature = await getSignatureKey({
reference,
amountInCents: priceInPesos * 100,
integrityKey: process.env.WOMPI_INTEGRITY_KEY!,
});
Correct:
const amountInCents = 2_490_000;
const signature = await getSignatureKey({
reference,
amountInCents,
integrityKey: process.env.WOMPI_INTEGRITY_KEY!,
});
In v1 the SDK multiplied internally (a bug). In v2 amountInCents is hashed exactly as given. Multiplying again produces a signature Wompi rejects silently — the transaction is declined.
Source: CHANGELOG v2.0.0, packages/core/test/server-utils.test.ts
CRITICAL Using positional arguments with getSignatureKey (v1 API)
Wrong:
const signature = await getSignatureKey(reference, amountInCents, integrityKey);
Correct:
import { getSignatureKey } from '@pulgueta/wompi/server';
const signature = await getSignatureKey({
reference,
amountInCents,
integrityKey: process.env.WOMPI_INTEGRITY_KEY!,
});
getSignatureKey was changed to a named-options object in v2.0.0. Positional calls fail at runtime or produce wrong signatures.
Source: CHANGELOG v2.0.0
HIGH Caching the acceptance token across multiple transactions
Wrong:
const merchant = await wompi.merchants.getMerchant();
const acceptanceToken = merchant[1]!.presigned_acceptance!.acceptance_token;
await wompi.transactions.createTransaction({ acceptance_token: acceptanceToken, ... });
Correct:
const [merchantErr, merchant] = await wompi.merchants.getMerchant();
if (merchantErr) throw merchantErr;
const acceptanceToken = merchant.presigned_acceptance?.acceptance_token;
if (!acceptanceToken) throw new Error('Missing acceptance token');
Source: packages/core/src/client/merchants/index.ts, README
HIGH expirationTime in signature must match expiration_time in transaction
Wrong:
const signature = await getSignatureKey({
reference, amountInCents, integrityKey,
expirationTime: '2026-01-01T00:00:00.000Z',
});
await wompi.transactions.createTransaction({
signature, reference, amount_in_cents: amountInCents,
});
Correct:
const expirationTime = '2026-01-01T00:00:00.000Z';
const signature = await getSignatureKey({ reference, amountInCents, integrityKey, expirationTime });
await wompi.transactions.createTransaction({
signature, reference, amount_in_cents: amountInCents,
expiration_time: expirationTime,
});
Source: packages/core/src/server.ts
HIGH Reading voidTransaction result from data instead of data.transaction
Wrong:
const [error, result] = await wompi.transactions.voidTransaction('txn-123');
console.log(result?.id);
console.log(result?.status);
Correct:
const [error, result] = await wompi.transactions.voidTransaction('txn-123');
if (error) throw error;
const voided = result?.transaction;
console.log(voided?.id, voided?.status);
voidTransaction wraps the outcome: data.status is the void result, data.transaction is the voided transaction. Breaking change in v2.0.0.
Source: CHANGELOG v2.0.0, packages/core/test/transactions.test.ts
MEDIUM Providing both payment_method and payment_source_id
Wrong:
await wompi.transactions.createTransaction({
payment_method: { type: 'CARD', token: 'tok_123', installments: 1 },
payment_source_id: 456,
});
Correct:
await wompi.transactions.createTransaction({
payment_method: { type: 'CARD', token: 'tok_123', installments: 1 },
});
await wompi.transactions.createTransaction({
payment_source_id: 456,
});
Source: packages/core/src/schemas.ts — CreateTransactionInputSchema .refine()
MEDIUM Wrong date format in listTransactions filters
Wrong:
await wompi.transactions.listTransactions({
from_date: '2024-01-01T00:00:00Z',
page_size: 500,
});
Correct:
await wompi.transactions.listTransactions({
from_date: '2024-01-01',
until_date: '2024-12-31',
page_size: 50,
});
Source: packages/core/src/schemas.ts — TransactionListParamsSchema
HIGH Calling private-key methods without providing privateKey
Wrong:
const wompi = new WompiClient({ publicKey: '...' });
const [error] = await wompi.transactions.listTransactions();
Correct:
const wompi = new WompiClient({
publicKey: process.env.WOMPI_PUBLIC_KEY!,
privateKey: process.env.WOMPI_PRIVATE_KEY!,
});
listTransactions and voidTransaction require privateKey. Transactions using payment_source_id also require it.
Source: packages/core/src/client/transactions/index.ts
HIGH Tension: Signature amount must match transaction amount exactly
Computing the signature early and then modifying amount_in_cents (e.g. adding tax or shipping) produces a mismatched signature that Wompi rejects.
const signature = await getSignatureKey({ reference, amountInCents: 1_000_000, integrityKey });
const finalAmount = 1_000_000 + taxAmount;
await wompi.transactions.createTransaction({ signature, amount_in_cents: finalAmount, ... });
Compute amountInCents once, use it in both getSignatureKey and createTransaction.
See also: wompi-go-to-production/SKILL.md § Common Mistakes
See also
wompi-client-setup/SKILL.md — key types and error-tuple pattern
wompi-payment-sources/SKILL.md — recurring payments via payment_source_id
wompi-go-to-production/SKILL.md — production checklist including full worked example