wompi-transactions

star 8

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.

pulgueta By pulgueta schedule Updated 6/2/2026

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

// 1. Fresh acceptance token — fetch for each transaction
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');

// 2. Tokenize the card
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;

// 3. Compute integrity signature — amountInCents is hashed as-is (already in cents)
const reference = `order-${Date.now()}`;
const amountInCents = 2_490_000; // COP 24,900 expressed in cents
const signature = await getSignatureKey({
  reference,
  amountInCents,
  integrityKey: process.env.WOMPI_INTEGRITY_KEY!,
});

// 4. Create the transaction
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); // 'txn-xxx', 'PENDING' | 'APPROVED'

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',          // optional, defaults to 'COP'
  expirationTime,            // only when transaction sets expiration_time
});

await wompi.transactions.createTransaction({
  signature,
  amount_in_cents: 2_490_000,
  reference: 'order-12345',
  expiration_time: expirationTime, // must match value passed to getSignatureKey
  // ...
});

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, // optional — omit to void the full amount
});
if (error) throw error;

const voided = result?.transaction; // nested under .transaction
console.log(voided?.id, voided?.status); // 'txn-123', 'VOIDED'

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;

// Poll until approved
const [pollErr, updated] = await wompi.tokens.getNequiToken(nequiToken.id);
if (pollErr) throw pollErr;
console.log(updated.status); // 'PENDING' | 'APPROVED' | 'DECLINED'

Common Mistakes

CRITICAL Multiplying amountInCents by 100 before getSignatureKey

Wrong:

const priceInPesos = 24900;
const signature = await getSignatureKey({
  reference,
  amountInCents: priceInPesos * 100, // 2,490,000,000 — wrong, double-multiplied
  integrityKey: process.env.WOMPI_INTEGRITY_KEY!,
});

Correct:

const amountInCents = 2_490_000; // COP 24,900 already in cents
const signature = await getSignatureKey({
  reference,
  amountInCents, // same value passed to amount_in_cents in createTransaction
  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:

// v1 positional API — does not exist in v2
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:

// Module-level cache — token expires and causes transaction rejections
const merchant = await wompi.merchants.getMerchant();
const acceptanceToken = merchant[1]!.presigned_acceptance!.acceptance_token;

// Later, in a route handler:
await wompi.transactions.createTransaction({ acceptance_token: acceptanceToken, ... });

Correct:

// Fetch a fresh token for each transaction
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:

// Signature includes expirationTime, but createTransaction omits expiration_time
const signature = await getSignatureKey({
  reference, amountInCents, integrityKey,
  expirationTime: '2026-01-01T00:00:00.000Z',
});
await wompi.transactions.createTransaction({
  signature, reference, amount_in_cents: amountInCents,
  // expiration_time missing — hash mismatch, transaction rejected
});

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, // must match exactly
});

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);     // undefined — wrong nesting
console.log(result?.status); // this is the VOID outcome, not the transaction

Correct:

const [error, result] = await wompi.transactions.voidTransaction('txn-123');
if (error) throw error;
const voided = result?.transaction; // voided transaction is nested here
console.log(voided?.id, voided?.status);  // 'txn-123', 'VOIDED'

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, // cannot provide both
  // ...
});
// Returns [WompiError, null] with "Invalid input" — no HTTP call made

Correct:

// Card token: use payment_method (authenticated with publicKey)
await wompi.transactions.createTransaction({
  payment_method: { type: 'CARD', token: 'tok_123', installments: 1 },
  // ...
});

// Saved source: use payment_source_id (authenticated with privateKey)
await wompi.transactions.createTransaction({
  payment_source_id: 456,
  // ...
});

Source: packages/core/src/schemas.tsCreateTransactionInputSchema .refine()


MEDIUM Wrong date format in listTransactions filters

Wrong:

await wompi.transactions.listTransactions({
  from_date: '2024-01-01T00:00:00Z', // ISO timestamp rejected
  page_size: 500,                     // max is 200
});

Correct:

await wompi.transactions.listTransactions({
  from_date: '2024-01-01', // YYYY-MM-DD only
  until_date: '2024-12-31',
  page_size: 50,           // 1–200
});

Source: packages/core/src/schemas.tsTransactionListParamsSchema


HIGH Calling private-key methods without providing privateKey

Wrong:

const wompi = new WompiClient({ publicKey: '...' });
const [error] = await wompi.transactions.listTransactions();
// error.message === "Private key is required" — no throw, silent failure

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.

// BAD: amount changes after signing
const signature = await getSignatureKey({ reference, amountInCents: 1_000_000, integrityKey });
const finalAmount = 1_000_000 + taxAmount; // differs from signed amount
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
Install via CLI
npx skills add https://github.com/pulgueta/wompi-node --skill wompi-transactions
Repository Details
star Stars 8
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator