Animica Pay docs 2.00% per successful payment

Build

Testing and test mode

What test mode guarantees, what you can exercise offline, and a pre-launch checklist.

Test mode exists so you can build the whole integration without moving real ANM, and the guard that enforces it fails closed.

What test mode guarantees #

js
// src/api/keys.js — the guard itself
function assertCanMoveRealFunds(subject) {
  if (isTestMode(subject)) throw new KeyError('test-mode key cannot move real ANM');
}

Switching modes #

Use the test pair while building, the live pair when you are ready:

PublishableSecret
Testapk_test_…ask_test_…
Liveapk_live_…ask_live_…

Nothing else changes — no separate base URL, no separate account.

What you can exercise without a chain #

Two things are worth testing directly, because they are where integrations actually break:

  1. Your webhook verifier. Sign a body yourself with your endpoint secret and POST it at your own handler. The signed string is v1:<ts>:<event_id>:<raw_body> — the Webhooks page has a complete Node and PHP verifier.
  2. Your idempotency behaviour. POST the same Idempotency-Key twice with the same body (expect a replay) and then with a different body (expect 409 idempotency_key_reused). Race two requests on one key and confirm the loser’s 429 rate_limited makes you retry the same key rather than mint a new one. Then deliver the same webhook event id twice and confirm your order is fulfilled once.
js
// Produce a valid signature for your own handler, using only node:crypto.
const crypto = require('node:crypto');

const body = JSON.stringify({ id: 'evt_test_1', type: 'payment.confirmed', created: Math.floor(Date.now() / 1000), data: { payment_intent: 'pay_test', merchant_order_id: '1' } });
const event = JSON.parse(body);
const signed = `v1:${event.created}:${event.id}:${body}`;
const sig = crypto.createHmac('sha256', process.env.ANIMICA_WEBHOOK_SECRET).update(signed, 'utf8').digest('hex');

await fetch('http://localhost:3000/webhooks/animica', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Animica-Signature': `v1=${sig}`,
    'Animica-Event-ID': event.id,
    'Animica-Timestamp': String(event.created),
  },
  body,
});

A checklist before you go live #

Then read Going live.