JavaScript/TypeScript library with full TypeScript support for Node.js (and browser use where applicable). Create payment links, manage transactions, and verify webhooks.
Full API documentation: arnipay/gateway-documentation (Español)
npm install gw-sdkRepository: github.com/arnipay/sdk-js
import { Arnipay, GatewayError } from 'gw-sdk';
// Third argument `true` enables sandbox
const arni = new Arnipay('CLIENT_ID', 'PRIVATE_KEY', true);
// Local / custom API:
// arni.getClient().setBaseUrl('http://arnipay.local/api/v1', false);
try {
const url = await arni.payment()
.title('Pizza Order')
.amount(50000)
.reference('ORDER-123')
.description('Two large pizzas')
.redirect('https://site.com/thanks', 'https://site.com/oops')
.createUrl();
console.log('Pay here:', url);
const methods = await arni.getPaymentMethods();
// [{ code: 'qr', name: 'Código QR' }, ...]
} catch (error) {
if (error instanceof GatewayError) {
console.error(error.message, error.statusCode, error.errors);
}
}Omit payment methods so the link offers whatever is enabled for your commerce (including newly added ones). You can use .allow(['qr', 'card']) when you need to restrict methods for a specific link.
import express from 'express';
import { Arnipay, GatewayError } from 'gw-sdk';
const arni = new Arnipay('CLIENT_ID', 'PRIVATE_KEY');
const app = express();
app.post('/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
try {
await arni.webhook('WEBHOOK_SECRET').handle(req, (event) => {
if (event.isPaid()) {
// event.get('reference') — same reference you set on create
console.log('Paid:', event.get('payment_id'), event.get('amount'));
}
});
res.sendStatus(200);
} catch (error) {
res.sendStatus(error instanceof GatewayError ? error.statusCode || 400 : 400);
}
});For webhook configuration, payloads, and retries, see Webhook notifications in the API docs.
const txs = await arni.transaction().list({ link_payment_id: linkId });
const tx = await arni.transaction().get('transaction-uuid');
await arni.transaction().reverse('transaction-uuid', 'Customer requested refund');import { Client, PaymentLink } from 'gw-sdk';
const client = new Client('CLIENT_ID', 'PRIVATE_KEY');
const paymentLink = new PaymentLink(client);
const link = await paymentLink.create(150000, 'Premium Subscription', 'desc', {
reference: 'SUB-2026'
// Optional: payment_methods: ['qr', 'tigo'] to restrict methods for this link
});
await paymentLink.get(link.id);
await paymentLink.list();
await paymentLink.reverse(link.id, 'Out of stock');All API endpoints use signature-based authentication with your Commerce credentials:
X-Client-ID: Your Commerce client ID (UUID)X-Timestamp: Current Unix timestamp in seconds (UTC)X-Signature: HMAC-SHA256 signature using your private key
Requests expire 15 minutes after X-Timestamp.
The same canonical string is used for API requests and webhooks.
Canonical components:
- Uppercased HTTP method (e.g.
GET,POST) - Request URI (path + query only; no scheme/host)
- Unix timestamp (same as
X-Timestamp) - Stable identifier (same as
X-Client-ID) - Base64-encoded SHA-256 of the raw body:
base64(sha256(raw_body)). For requests without a body usebase64(sha256(""))
Join the components with newlines ("\n") and compute the signature:
canonical = join("\n", [METHOD, URI, TIMESTAMP, CLIENT_ID, base64(sha256(RAW_BODY))])
signature = HMAC-SHA256(canonical, PRIVATE_KEY)
Send JSON bodies as the exact raw bytes you sign (no extra escaping). The SDK signs the serialized request body it sends.
You can find your client ID and private key in your Commerce settings, or regenerate them if needed.
https://arnipay.com.py/api/v1/
The gateway can send real-time notifications when payment events occur. Configure your webhook URL in Commerce settings.
Webhook requests use the same canonical string and headers as API requests, plus X-Webhook-ID.
- Real-time notifications (completed, failed, pending)
- HMAC-SHA256 verification using the canonical string
- Configurable retries
- Detailed event payloads
See Webhook configuration and webhook examples in the API documentation.
- 60 requests per minute per client
- 1000 requests per day per client
Exceeding limits returns 429 Too Many Requests.
import { GatewayError } from 'gw-sdk';
try {
await arni.payment().title('x').amount(1).create();
} catch (error) {
if (error instanceof GatewayError) {
console.error(error.message, error.statusCode, error.errors);
}
}If you have any questions or need assistance integrating with our API, see gateway-documentation or contact our support team at info@arnipay.com.py.
cp .env.example tests/.env
# fill CLIENT_ID, PRIVATE_KEY, API_BASE_URL, WEBHOOK_SECRET
npm test- Unit tests always run
- Integration tests hit
API_BASE_URL(e.g.http://arnipay.local/api/v1) and skip if credentials are missing