Skip to content

volverjs/satispay-node-sdk

Repository files navigation

(Unofficial) Satispay GBusiness Node.js API SDK

npm version codecov TypeScript Zero Dependencies License: MIT

Universal (but unofficial) TypeScript SDK for Satispay GBusiness API integration. Zero external dependencies, compatible with Node.js, Deno, and Bun.

Features

  • Zero dependencies - Uses only native standard APIs (fetch, crypto)
  • Multi-runtime - Works with Node.js 18+, Deno 1.30+, and Bun 1.0+
  • Lightweight - Only 268KB bundle size
  • Type-safe - Complete TypeScript definitions
  • Modern - Fetch API, async/await, ES Modules
  • Secure - Native RSA-SHA256 encryption
  • Developer-friendly - Intuitive API with automatic conversions:
    • 💶 Use amount (euros) instead of amount_unit (cents)
    • 📅 Use Date objects instead of timestamp strings

Installation

Node.js

npm install @volverjs/satispay-node-sdk

Deno

import { Api, Payment } from "npm:@volverjs/satispay-node-sdk";

Or use deno.json:

{
  "imports": {
    "satispay": "npm:@volverjs/satispay-node-sdk"
  }
}

Bun

bun add @volverjs/satispay-node-sdk

Quick Start

Authentication

Get your credentials using the CLI tool with an activation token:

npx @volverjs/satispay-node-sdk YOUR_ACTIVATION_TOKEN

This will generate:

  • Public Key - RSA public key
  • Private Key - RSA private key (keep this secure!)
  • Key ID - Your authentication key ID

Where to get the activation token:

Options:

npx @volverjs/satispay-node-sdk YOUR_TOKEN              # Sandbox (default)
npx @volverjs/satispay-node-sdk YOUR_TOKEN --production # Production
npx @volverjs/satispay-node-sdk YOUR_TOKEN --sandbox    # Sandbox (explicit)

⚠️ Important: The activation token is single-use. Save the generated credentials securely!

Configure the SDK

Use the generated credentials to configure the SDK:

import { Api } from '@volverjs/satispay-node-sdk';

Api.setSandbox(true); // or false for production
Api.setPublicKey(process.env.SATISPAY_PUBLIC_KEY!);
Api.setPrivateKey(process.env.SATISPAY_PRIVATE_KEY!);
Api.setKeyId(process.env.SATISPAY_KEY_ID!);

Store credentials in .env:

SATISPAY_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\n..."
SATISPAY_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n..."
SATISPAY_KEY_ID="your-key-id"

API Reference

Payment Operations

Create Payment

// Using amount in euros (recommended)
const payment = await Payment.create({
  flow: 'MATCH_CODE',
  amount: 1.00, // Automatically converted to 100 cents
  currency: 'EUR',
  callback_url: 'https://your-site.com/callback',
  external_code: 'ORDER-123',
  metadata: { order_id: '12345' },
});

// Or using amount_unit in cents (still supported)
const payment2 = await Payment.create({
  flow: 'MATCH_CODE',
  amount_unit: 100, // Amount in cents
  currency: 'EUR',
  callback_url: 'https://your-site.com/callback',
  external_code: 'ORDER-123',
  metadata: { order_id: '12345' },
});

💡 Tip: Use amount (euros) for more intuitive code. The SDK automatically converts it to cents.

See examples/create-payment-with-amount.ts for more examples.

Get Payment

const payment = await Payment.get('PAYMENT_ID');
console.log('Status:', payment.status);

List Payments

const result = await Payment.all({
  limit: 20,
  status: 'ACCEPTED',
  from_date: '2024-01-01',
});

result.data.forEach(payment => {
  console.log(`${payment.id}: ${payment.status}`);
});
Filter by Date

You can filter payments using Date objects or timestamp strings:

// Using Date objects (recommended)
const yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1);

const recentPayments = await Payment.all({
  starting_after_timestamp: yesterday, // Date is automatically converted to milliseconds
  limit: 10,
});

// Or using timestamp string (milliseconds)
const timestampString = new Date('2024-01-01').getTime().toString();
const paymentsFromDate = await Payment.all({
  starting_after_timestamp: timestampString,
  limit: 10,
});

See examples/payment-date-filtering.ts for more examples.

Update Payment

// Using amount in euros
const payment = await Payment.update('PAYMENT_ID', {
  action: 'ACCEPT',
  amount: 5.50, // Automatically converted to 550 cents
});

// Or using amount_unit in cents
const payment2 = await Payment.update('PAYMENT_ID', {
  action: 'ACCEPT',
  amount_unit: 550,
});

Consumer Operations

import { Consumer } from '@volverjs/satispay-node-sdk';

const consumer = await Consumer.get('+393331234567');
console.log('Consumer:', consumer.name);

Daily Closure

import { DailyClosure } from '@volverjs/satispay-node-sdk';

// Today's closure
const closure = await DailyClosure.get();

// Specific date using Date object (recommended)
const yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1);
const closureByDate = await DailyClosure.get(yesterday);

// Or using YYYYMMDD string format
const closureByString = await DailyClosure.get('20240115');

console.log('Date:', closure.shop_daily_closure.id);
console.log('Total:', closure.shop_daily_closure.amount_unit / 100, closure.shop_daily_closure.currency);
console.log('Gross:', closure.shop_daily_closure.gross_amount_unit / 100);
console.log('Refunds:', closure.shop_daily_closure.refund_amount_unit / 100);

Pre-Authorized Payment Tokens

Pre-Authorized Payment Tokens allow consumers to authorize payments in advance:

import { PreAuthorizedPaymentToken } from '@volverjs/satispay-node-sdk';

// Create a pre-authorized payment token
const token = await PreAuthorizedPaymentToken.create({
  reason: 'Subscription payment',
  callback_url: 'https://your-site.com/callback',
  redirect_url: 'https://your-site.com/success',
});

console.log('Token ID:', token.id);
console.log('Token:', token.token);
console.log('Status:', token.status); // PENDING

// Get token details
const retrievedToken = await PreAuthorizedPaymentToken.get(token.id);

// Update token (e.g., cancel it)
const updatedToken = await PreAuthorizedPaymentToken.update(token.id, {
  status: 'CANCELED',
});

// Once the consumer accepts the token, you can use it to create payments:
const payment = await Payment.create({
  flow: 'PRE_AUTHORIZED',
  token: token.token,
  amount: 9.99,
  currency: 'EUR',
});

Important Notes:

  • The consumer must accept the token before it can be used for payments
  • Token status can be: PENDING, ACCEPTED, or CANCELED
  • Use the token field (not the id) when creating pre-authorized payments

Reports

⚠️ Special Authentication Required: Report APIs require special authentication keys. Contact tech@satispay.com to enable access.

import { Report } from '@volverjs/satispay-node-sdk';

// Create a new report
const report = await Report.create({
  type: 'PAYMENT_FEE',
  format: 'CSV', // or 'PDF', 'XLSX'
  from_date: '2025-11-01',
  to_date: '2025-11-30',
  columns: ['transaction_id', 'transaction_date', 'total_amount'], // Optional
});

// Get list of reports
const reports = await Report.all({
  limit: 10,
  starting_after: 'report-123',
});

// Get specific report
const reportDetails = await Report.get('report-123');

if (reportDetails.status === 'READY' && reportDetails.download_url) {
  console.log('Download URL:', reportDetails.download_url);
}

Important Notes:

  • Reports are extracted at merchant level (includes all shops)
  • Reports for the previous day should be generated at least 4 hours after midnight
  • Report status: PENDING, READY, or FAILED

Sessions (POS Integration)

Sessions are used for POS/device integration to manage fund lock payments incrementally:

import { Session } from '@volverjs/satispay-node-sdk';

// Open a session from a fund lock
const session = await Session.open({
  fund_lock_id: 'payment-fund-lock-123',
});

console.log('Session ID:', session.id);
console.log('Available amount:', session.residual_amount_unit);

// Add items to the session
await Session.createEvent(session.id, {
  operation: 'ADD',
  amount_unit: 500,
  currency: 'EUR',
  description: 'Coffee',
  metadata: { sku: 'COFFEE-001' },
});

// Remove items (e.g., discount)
await Session.createEvent(session.id, {
  operation: 'REMOVE',
  amount_unit: 200,
  currency: 'EUR',
  description: 'Discount',
});

// Get session details
const details = await Session.get(session.id);
console.log('Residual amount:', details.residual_amount_unit);

// Close the session
const closedSession = await Session.update(session.id, {
  status: 'CLOSE',
});

Meal Voucher & Fringe Benefits

Meal Voucher and Fringe Benefits payments use the same Payment API with additional parameters:

import { Payment } from '@volverjs/satispay-node-sdk';

// Create payment with Meal Voucher limits
const payment = await Payment.create({
  flow: 'MATCH_CODE',
  amount: 50.00,
  currency: 'EUR',
  meal_voucher_max_amount_unit: 4000, // Max 40 EUR with meal vouchers
  meal_voucher_max_quantity: 8, // Max 8 vouchers
});

// Update payment with Meal Voucher limits
const updated = await Payment.update(payment.id, {
  action: 'ACCEPT',
  meal_voucher_max_amount_unit: 3000,
  meal_voucher_max_quantity: 6,
});

Important Notes:

  • Meal Vouchers and Fringe Benefits are mutually exclusive
  • Meal Voucher refunds: Only on the same day, full amount only
  • Fringe Benefits refunds: Only within the same month, full amount only
  • Default limit: 8 meal vouchers per payment if not specified

Runtime-Specific Examples

Node.js Server

import express from 'express';
import { Api, Payment } from '@volverjs/satispay-node-sdk';

Api.setSandbox(true);
Api.setPublicKey(process.env.SATISPAY_PUBLIC_KEY);
Api.setPrivateKey(process.env.SATISPAY_PRIVATE_KEY);
Api.setKeyId(process.env.SATISPAY_KEY_ID);

const app = express();
app.use(express.json());

app.post('/create-payment', async (req, res) => {
  const payment = await Payment.create({
    flow: 'MATCH_CODE',
    amount_unit: req.body.amount,
    currency: 'EUR',
  });
  res.json(payment);
});

app.listen(3000);

Deno Server

import { serve } from "https://deno.land/std@0.208.0/http/server.ts";
import { Api, Payment } from "npm:@volverjs/satispay-node-sdk";

Api.setSandbox(true);
Api.setPublicKey(Deno.env.get("SATISPAY_PUBLIC_KEY")!);
Api.setPrivateKey(Deno.env.get("SATISPAY_PRIVATE_KEY")!);
Api.setKeyId(Deno.env.get("SATISPAY_KEY_ID")!);

serve(async (req) => {
  const url = new URL(req.url);
  
  if (url.pathname === "/create-payment" && req.method === "POST") {
    const body = await req.json();
    const payment = await Payment.create({
      flow: "MATCH_CODE",
      amount_unit: body.amount,
      currency: "EUR",
    });
    return Response.json(payment);
  }
  
  return Response.json({ error: "Not found" }, { status: 404 });
});

Bun Server

import { Api, Payment } from "@volverjs/satispay-node-sdk";

Api.setSandbox(true);
Api.setPublicKey(process.env.SATISPAY_PUBLIC_KEY!);
Api.setPrivateKey(process.env.SATISPAY_PRIVATE_KEY!);
Api.setKeyId(process.env.SATISPAY_KEY_ID!);

Bun.serve({
  port: 3000,
  async fetch(req) {
    const url = new URL(req.url);
    
    if (url.pathname === "/create-payment" && req.method === "POST") {
      const body = await req.json();
      const payment = await Payment.create({
        flow: "MATCH_CODE",
        amount_unit: body.amount,
        currency: "EUR",
      });
      return Response.json(payment);
    }
    
    return Response.json({ error: "Not found" }, { status: 404 });
  },
});

Custom Headers

import { Api, Request } from '@volverjs/satispay-node-sdk';

// Global headers
Api.setPlatformHeader('MyApp');
Api.setPlatformVersionHeader('1.0.0');
Api.setPluginNameHeader('my-plugin');
Api.setPluginVersionHeader('2.0.0');
Api.setTypeHeader('ONLINE_SHOP');
Api.setTrackingHeader('tracking-code-123');

// Per-request headers
const payment = await Payment.create(
  {
    flow: 'MATCH_CODE',
    amount_unit: 100,
    currency: 'EUR',
  },
  {
    [Request.HEADER_TRACKING_CODE]: 'custom-tracking-code',
    [Request.HEADER_IDEMPOTENCY_KEY]: 'unique-key-123',
  }
);

Environment Configuration

Sandbox Mode

Api.setSandbox(true); // Test environment
Api.setSandbox(false); // Production environment

Environment Variables

Store your credentials securely:

# .env
SATISPAY_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----..."
SATISPAY_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----..."
SATISPAY_KEY_ID="your-key-id"

Development

# Install dependencies
pnpm install

# Build
pnpm build

# Watch mode
pnpm build:watch

# Run tests
pnpm test

# Watch tests
pnpm test:watch

# Test with UI
pnpm test:ui

# Coverage report
pnpm test:coverage

# Lint
pnpm lint

# Format
pnpm format

Testing

This project uses Vitest for testing. The test suite includes:

  • Unit tests for all core modules (Api, Payment, Consumer, DailyClosure, etc.)
  • RSA Service tests for cryptographic operations
  • Mock-based tests for API interactions

Current test coverage: 94.82% (Statements: 93.83%, Branches: 89.65%, Functions: 100%, Lines: 95.8%)

Run tests:

pnpm test              # Run all tests
pnpm test:watch        # Watch mode for development
pnpm test:ui           # Interactive UI
pnpm test:coverage     # Generate coverage report

Examples

See the examples/ directory for complete examples:

  • auth-with-token.ts - Authentication with token
  • create-payment.ts - Create a payment
  • get-payment.ts - Get payment details
  • get-payments.ts - List payments
  • get-consumer.ts - Get consumer information
  • get-daily-closure.ts - Get daily closure

To run examples:

npm install
npm run build
cd examples
npx tsc
node dist/auth-with-token.js

Requirements

Runtime Minimum Version Native fetch Support
Node.js 18.0.0 Yes
Deno 1.30.0 Yes
Bun 1.0.0 Yes

No external dependencies required.

Technical Details

This SDK uses Web Standard APIs:

  • fetch API for HTTP requests (native in all supported runtimes)
  • crypto module for RSA-SHA256 signatures (Node.js crypto with compatibility layers for Deno/Bun)

Benefits:

  • Same code works across all runtimes
  • No polyfills needed
  • Native performance
  • Future-proof

Why Zero Dependencies?

  • No third-party vulnerability risks
  • Minimal bundle size (268KB)
  • Fast installation
  • No dependency conflicts
  • Uses only standard APIs

Error Handling

try {
  const payment = await Payment.create({
    flow: 'MATCH_CODE',
    amount_unit: 100,
    currency: 'EUR',
  });
} catch (error) {
  console.error('Payment creation failed:', error.message);
}

TypeScript Support

Full TypeScript support with complete type definitions included:

import type {
  PaymentCreate,
  PaymentResponse,
  ConsumerResponse,
  DailyClosureResponse,
} from '@volverjs/satispay-node-sdk';

License

MIT

Links