@tiqopay/sdk
v1.0.0
Published
Official Node.js SDK for the tiqopay API — escrow payments for Morocco
Maintainers
Readme
@tiqopay/sdk
Official Node.js SDK for the tiqopay API — escrow payments for Morocco.
tiqopay holds the buyer's payment in escrow until delivery is confirmed. The SDK wraps the REST API in a typed client and a webhook verifier.
Installation
npm install @tiqopay/sdk
# or
pnpm add @tiqopay/sdk
# or
yarn add @tiqopay/sdkRequires Node.js 18+ (native fetch and AbortController).
Quickstart
import { Tiqopay } from '@tiqopay/sdk';
const tiqopay = new Tiqopay({
apiKey: process.env.TIQOPAY_API_KEY!, // sk_test_... or sk_live_...
});
const tx = await tiqopay.transactions.create({
amount: 150000, // 1 500,00 DH in centimes
description: 'iPhone 13 Pro — used, very good condition',
delivery_deadline_days: 7,
seller: { email: '[email protected]' },
buyer: { email: '[email protected]', phone: '+212600000000' },
shipping_address: {
recipient_name: 'Aicha Benali',
phone: '+212600000000',
line1: '12 rue Tarik Ibn Ziad',
city: 'Casablanca',
},
});
console.log(tx.payment_url); // send this to the buyerConfiguration
new Tiqopay({
apiKey: 'sk_live_...', // required
baseUrl: 'https://tiqopay.com/api', // optional override
timeout: 30_000, // request timeout (ms)
maxRetries: 3, // retries on 429 and 5xx
});The client retries on 429 (respecting X-RateLimit-Reset / Retry-After) and
on 5xx with exponential backoff + jitter. 4xx errors other than 429 are
not retried — they're thrown as TiqopayError immediately.
Resources
Transactions
await tiqopay.transactions.create({ ... });
await tiqopay.transactions.list({ limit: 20 });
await tiqopay.transactions.retrieve('tx_...');
// Seller marks the order as delivered
await tiqopay.transactions.deliver('tx_...', {
carrier: 'AMANA',
tracking_number: 'AM123456789',
});
// Or for in-person / remote handover
await tiqopay.transactions.deliver('tx_...', {
delivery_proof: 'Handed over in Casablanca on 2026-05-21, witness: Karim',
});
await tiqopay.transactions.dispute('tx_...', {
reason_code: 'not_as_described',
description: 'Phone screen had a crack not shown in listing photos',
role: 'buyer',
});
await tiqopay.transactions.refund('tx_...');
await tiqopay.transactions.cancel('tx_...');Release is intentionally not in the SDK. Escrow release is buyer-driven (confirm-receipt token) or time-driven (auto-release after the dispute window). A seller-callable release would let a fraudulent merchant skip the dispute period.
Payment Links
const link = await tiqopay.paymentLinks.create({
title: 'Vintage Leica M6',
amount: 1800000, // 18 000,00 DH
delivery_deadline_days: 14,
is_reusable: false,
});
console.log(link.url); // https://tiqopay.com/p/abc123Webhooks
Webhook endpoints are managed via the API. Verify signatures with the
/webhooks subpath:
import { verifyWebhook, WebhookVerificationError } from '@tiqopay/sdk/webhooks';
import express from 'express';
const app = express();
app.post(
'/webhooks',
express.raw({ type: 'application/json' }),
(req, res) => {
try {
const event = verifyWebhook(
req.body.toString(),
req.headers['tiqopay-signature'] as string,
process.env.TIQOPAY_WEBHOOK_SECRET!,
);
switch (event.type) {
case 'transaction.funded':
// buyer paid, money is in escrow
break;
case 'transaction.delivered':
// seller marked as delivered, dispute window opens
break;
case 'transaction.released':
// funds released to seller's payable balance
break;
case 'transaction.disputed':
// dispute opened — admin will adjudicate
break;
}
res.json({ received: true });
} catch (err) {
if (err instanceof WebhookVerificationError) {
return res.status(400).send(err.message);
}
throw err;
}
},
);The verifier accepts multiple v1= signatures, so secret rotation is
zero-downtime: rotate the secret in the dashboard, deploy the new secret on
your side at your own pace.
Other resources
await tiqopay.account.retrieve();
await tiqopay.payouts.list();
await tiqopay.events.list({ type: 'transaction.funded' });
await tiqopay.notifications.list({ is_read: 'false' });
await tiqopay.webhookEndpoints.create({
url: 'https://example.com/webhooks',
enabled_events: ['transaction.funded', 'transaction.released'],
});Error handling
import { TiqopayError } from '@tiqopay/sdk';
try {
await tiqopay.transactions.retrieve('tx_does_not_exist');
} catch (err) {
if (err instanceof TiqopayError) {
console.log(err.status); // 404
console.log(err.code); // 'resource_not_found'
console.log(err.message); // human-readable
}
}API version pinning
Every request sends a Tiqopay-Version header pinned to the version this SDK
build was developed against. Upgrading the SDK package is what opts you into a
newer API version — the server will never silently shift behavior under you.
TypeScript
The SDK is written in TypeScript and ships its own types. All resource parameters and responses are fully typed:
import type {
Transaction,
CreateTransactionParams,
PaymentLink,
WebhookEvent,
} from '@tiqopay/sdk';Links
- Documentation — https://tiqopay.com/docs
- API reference — https://tiqopay.com/docs/api
- Dashboard — https://tiqopay.com/dashboard
- Issues — https://github.com/tiqopay/tiqopay-node/issues
License
MIT © tiqopay
