
Security News
OpenCode User Hit with Hostile Backlash After Reporting Free AI Loophole
An OpenCode user faced harassment after reporting a free AI usage loophole, drawing a bitter backlash in a GitHub thread that has since been deleted.
ownpay-nodejs
Advanced tools
Official Node.js SDK for the OwnPay Payment Gateway API. A zero-dependency, TypeScript-first SDK for seamless payment integration.
op_)npm install ownpay-nodejs
yarn add ownpay-nodejs
pnpm add ownpay-nodejs
import OwnPay from 'ownpay-nodejs';
// Simple initialization
const client = new OwnPay('op_your_api_key_here');
// With configuration options
const client = new OwnPay({
apiKey: 'op_your_api_key_here',
timeout: 30000, // Request timeout in ms (default: 30000)
maxRetries: 2, // Max retry attempts (default: 2)
baseUrl: 'https://api.ownpay.com', // Custom API URL (optional)
});
const payment = await client.payments.create({
amount: '100.00',
currency: 'BDT',
customer_email: 'customer@example.com',
customer_name: 'John Doe',
callback_url: 'https://your-app.com/webhook',
redirect_url: 'https://your-app.com/success',
cancel_url: 'https://your-app.com/cancel',
reference: 'ORDER-12345',
metadata: {
order_id: '12345',
product: 'Widget',
},
});
console.log('Payment ID:', payment.payment_id);
console.log('Checkout URL:', payment.checkout_url);
console.log('Status:', payment.status);
// Redirect customer to payment.checkout_url
const paymentDetails = await client.payments.get('payment-uuid-here');
console.log('Status:', paymentDetails.status);
console.log('Amount:', paymentDetails.amount);
console.log('Currency:', paymentDetails.currency);
if (paymentDetails.status === 'completed') {
console.log('Payment completed!');
}
client.payments.create(params, options?)Creates a new payment intent.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
amount | string | number | ✅ | Payment amount (positive number) |
currency | string | ✅ | 3-letter ISO currency code (e.g., 'BDT', 'USD') |
callback_url | string | ❌ | Webhook notification URL |
redirect_url | string | ❌ | Success redirect URL |
cancel_url | string | ❌ | Cancel redirect URL |
customer_email | string | ❌ | Customer email address |
customer_name | string | ❌ | Customer name (max 150 chars) |
customer_phone | string | ❌ | Customer phone (max 30 chars) |
reference | string | ❌ | Merchant reference ID |
gateway | string | ❌ | Preferred payment gateway |
metadata | Record<string, unknown> | ❌ | Custom key-value metadata |
Returns: Promise<PaymentIntent>
interface PaymentIntent {
payment_id: string; // Unique payment UUID
token: string; // Payment intent token
checkout_url: string; // URL for customer payment
status: string; // Current status
}
client.payments.get(paymentId, options?)Retrieves payment details by ID.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
paymentId | string | ✅ | Payment UUID |
Returns: Promise<Payment>
client.transactions.list(params?, options?)Lists transactions with optional filtering and pagination.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
page | number | ❌ | Page number (default: 1) |
per_page | number | ❌ | Items per page (default: 25, max: 100) |
status | string | ❌ | Filter by status |
gateway | string | ❌ | Filter by gateway |
from | string | ❌ | Start date (ISO format) |
to | string | ❌ | End date (ISO format) |
Returns: Promise<PaginatedList<Transaction>>
const result = await client.transactions.list({
page: 1,
per_page: 50,
status: 'completed',
from: '2024-01-01',
to: '2024-01-31',
});
console.log('Transactions:', result.items);
console.log('Total:', result.meta.total);
console.log('Pages:', result.meta.total_pages);
client.transactions.get(trxId, options?)Retrieves a transaction by ID (OwnPay reference or gateway ID).
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
trxId | string | ✅ | Transaction ID (e.g., 'OP-ABC123') |
Returns: Promise<Transaction>
client.refunds.create(params, options?)Creates a refund for a transaction.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
transaction_id | string | number | ✅* | Transaction ID |
trx_id | string | number | ✅* | OwnPay transaction reference |
amount | string | number | ❌ | Refund amount (partial refund) |
reason | string | ❌ | Refund reason |
*Either transaction_id or trx_id is required
Returns: Promise<Refund>
// Full refund
const refund = await client.refunds.create({
transaction_id: 'OP-ABC123',
reason: 'Customer request',
});
// Partial refund
const refund = await client.refunds.create({
transaction_id: 'OP-ABC123',
amount: '50.00',
reason: 'Partial return',
});
client.refunds.list(params?, options?)Lists refunds with optional filtering.
Returns: Promise<PaginatedList<Refund>>
client.refunds.get(trxId, options?)Retrieves refund details by transaction reference.
Returns: Promise<Refund>
client.customers.create(params, options?)Creates a new customer.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | ✅ | Customer name (max 150 chars) |
email | string | ❌ | Email address |
phone | string | ❌ | Phone number |
Returns: Promise<{ id: number; uuid: string }>
const customer = await client.customers.create({
name: 'Jane Smith',
email: 'jane@example.com',
phone: '+8801712345678',
});
console.log('Customer ID:', customer.id);
console.log('Customer UUID:', customer.uuid);
client.customers.list(params?, options?)Lists customers with pagination.
Returns: Promise<PaginatedList<Customer>>
client.customers.get(identifier, options?)Retrieves a customer by email or phone.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
identifier | string | ✅ | Email or phone number |
Returns: Promise<Customer>
// By email
const customer = await client.customers.get('jane@example.com');
// By phone
const customer = await client.customers.get('+8801712345678');
Note: API key operations require an API key with both
writeandadminscopes, and must include theX-Super-Admin-Emailheader.
client.apiKeys.list(options?)Lists all API keys for the merchant.
Returns: Promise<ApiKey[]>
const keys = await client.apiKeys.list({
headers: { 'X-Super-Admin-Email': 'admin@example.com' },
});
client.apiKeys.generate(params?, options?)Generates a new API key.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | ❌ | Key name/label |
scopes | string[] | ❌ | Permission scopes: ['read', 'write', 'admin'] |
Returns: Promise<GeneratedApiKey>
const result = await client.apiKeys.generate(
{
name: 'Production Key',
scopes: ['read', 'write'],
},
{
headers: { 'X-Super-Admin-Email': 'admin@example.com' },
}
);
// IMPORTANT: Store this key securely! It cannot be retrieved again.
console.log('New API Key:', result.key);
console.log('Warning:', result.warning);
client.apiKeys.revoke(keyId, options?)Revokes an API key.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
keyId | number | ✅ | API key ID to revoke |
client.webhooks.test(options?)Sends a test webhook to the configured endpoint.
Returns: Promise<WebhookTestResult>
const result = await client.webhooks.test();
console.log('Status Code:', result.status_code);
console.log('Response Time:', result.response_time_ms, 'ms');
client.webhooks.deliveries(options?)Lists recent webhook deliveries.
Returns: Promise<WebhookDelivery[]>
client.health.check(options?)Performs a system health check.
Returns: Promise<HealthStatus>
const health = await client.health.check();
console.log('Status:', health.status); // 'healthy' or 'degraded'
console.log('Version:', health.version);
console.log('Database:', health.db); // 'connected' or 'error'
console.log('Gateways:', health.gateways);
console.log('Customers:', health.customers);
Always verify webhook signatures to ensure payloads are from OwnPay.
import { verifyWebhookSignature } from 'ownpay-nodejs/webhooks';
// Express.js example
app.post('/webhook', (req, res) => {
try {
const signature = req.headers['x-ownpay-signature'];
const timestamp = req.headers['x-ownpay-timestamp'];
const payload = req.body; // Raw body (string or Buffer)
verifyWebhookSignature({
payload,
signature,
secret: process.env.OWNPAY_WEBHOOK_SECRET,
timestamp,
tolerance: 300, // 5 minutes (default)
});
// Signature is valid, process the event
const event = JSON.parse(payload);
handleWebhookEvent(event);
res.status(200).json({ received: true });
} catch (error) {
console.error('Webhook verification failed:', error.message);
res.status(400).json({ error: 'Invalid signature' });
}
});
interface WebhookPayload {
event: string; // e.g., 'payment.completed'
transaction_id: string; // OwnPay transaction reference
gateway_trx_id: string; // Gateway transaction ID
amount: string; // Transaction amount
currency: string; // Currency code
fee: string; // Processing fee
gateway: string; // Gateway slug
gateway_type: string; // Gateway type
status: string; // Transaction status
customer: {
name: string;
email: string;
phone: string;
};
metadata: Record<string, unknown>;
timestamp: string; // ISO timestamp
}
function handleWebhookEvent(event: WebhookPayload) {
switch (event.event) {
case 'payment.completed':
console.log(`Payment ${event.transaction_id} completed`);
// Fulfill order, send confirmation email, etc.
break;
case 'payment.failed':
console.log(`Payment ${event.transaction_id} failed`);
// Notify customer, retry logic, etc.
break;
case 'refund.completed':
console.log(`Refund for ${event.transaction_id} completed`);
// Update records, notify customer
break;
default:
console.log(`Unhandled event: ${event.event}`);
}
}
The SDK provides a comprehensive error hierarchy for precise error handling.
import OwnPay, {
AuthenticationError,
PermissionError,
NotFoundError,
ValidationError,
RateLimitError,
IdempotencyError,
ApiError,
NetworkError,
AbortError,
} from 'ownpay-nodejs';
try {
const payment = await client.payments.create({
amount: '100.00',
currency: 'BDT',
});
} catch (error) {
if (error instanceof AuthenticationError) {
// Invalid or revoked API key
console.error('Authentication failed:', error.message);
} else if (error instanceof ValidationError) {
// Invalid parameters
console.error('Validation failed:', error.message);
console.error('Field errors:', error.getFieldErrors());
} else if (error instanceof NotFoundError) {
// Resource not found
console.error('Not found:', error.message);
} else if (error instanceof RateLimitError) {
// Rate limit exceeded
console.error(`Rate limited. Retry after ${error.retryAfter} seconds`);
} else if (error instanceof IdempotencyError) {
// Duplicate request
console.error('Idempotency conflict:', error.message);
} else if (error instanceof ApiError) {
// Server error (5xx)
console.error('API error:', error.message, 'Status:', error.status);
} else if (error instanceof NetworkError) {
// Connection failure
console.error('Network error:', error.message);
} else if (error instanceof AbortError) {
// Request timeout
console.error('Request timed out');
}
}
All errors have these common properties:
| Property | Type | Description |
|---|---|---|
message | string | Human-readable error message |
type | string | Error type identifier |
status | number | HTTP status code (if applicable) |
requestId | string | Request ID for debugging |
rawResponse | unknown | Raw API response |
ValidationError provides additional methods:
catch (error) {
if (error instanceof ValidationError) {
// Get all errors grouped by field
const fieldErrors = error.getFieldErrors();
// { amount: ['Must be positive'], currency: ['Required'] }
// Get first error for a specific field
const amountError = error.getFirstFieldError('amount');
}
}
All resource methods accept an optional RequestOptions parameter:
const payment = await client.payments.create(
{ amount: '100.00', currency: 'BDT' },
{
// Idempotency key for safe retries
idempotencyKey: 'unique-key-123',
// Custom headers for this request
headers: {
'X-Custom-Header': 'value',
},
// Request timeout override (ms)
timeout: 60000,
// AbortSignal for cancellation
signal: AbortSignal.timeout(10000),
}
);
Use idempotency keys for POST requests to safely retry without creating duplicates:
import { v4 as uuidv4 } from 'node:crypto';
const idempotencyKey = crypto.randomUUID();
const payment = await client.payments.create(
{ amount: '100.00', currency: 'BDT' },
{ idempotencyKey }
);
// Safe to retry with the same key if network error occurs
Use AbortSignal to cancel long-running requests:
const controller = new AbortController();
// Cancel after 5 seconds
setTimeout(() => controller.abort(), 5000);
try {
const payment = await client.payments.create(
{ amount: '100.00', currency: 'BDT' },
{ signal: controller.signal }
);
} catch (error) {
if (error instanceof AbortError) {
console.log('Request was cancelled');
}
}
For self-hosted or white-label deployments:
const client = new OwnPay({
apiKey: 'op_your_key',
baseUrl: 'https://your-domain.com',
});
Store your API key securely using environment variables:
const client = new OwnPay(process.env.OWNPAY_API_KEY!);
Add custom headers to all requests:
const client = new OwnPay({
apiKey: 'op_your_key',
headers: {
'X-App-Version': '1.0.0',
'X-Client-Id': 'your-app',
},
});
The SDK is built with TypeScript and provides comprehensive type definitions.
import OwnPay from 'ownpay-nodejs';
import type {
Payment,
Transaction,
Refund,
Customer,
WebhookPayload,
CreatePaymentParams,
ListTransactionsParams,
} from 'ownpay-nodejs';
// Types are automatically inferred
const client = new OwnPay('op_key');
const payment = await client.payments.create({
amount: '100.00',
currency: 'BDT',
});
// payment is typed as PaymentIntent
The SDK supports CommonJS for backward compatibility:
const OwnPay = require('ownpay-nodejs');
const client = new OwnPay('op_your_key');
Import only what you need for smaller bundle sizes:
// Import only the client
import OwnPay from 'ownpay-nodejs';
// Import only webhook utilities
import { verifyWebhookSignature } from 'ownpay-nodejs/webhooks';
// Import specific types
import type { Payment, Transaction } from 'ownpay-nodejs';
// Import specific errors
import { ValidationError, AuthenticationError } from 'ownpay-nodejs';
The SDK automatically retries failed requests for transient errors:
| Status Code | Retryable | Behavior |
|---|---|---|
| 429 | ✅ | Respects Retry-After header |
| 500 | ✅ | Exponential backoff |
| 502 | ✅ | Exponential backoff |
| 503 | ✅ | Exponential backoff |
| 504 | ✅ | Exponential backoff |
| 401 | ❌ | Immediate failure |
| 403 | ❌ | Immediate failure |
| 404 | ❌ | Immediate failure |
| 422 | ❌ | Immediate failure |
const client = new OwnPay({
apiKey: 'op_your_key',
maxRetries: 3, // Default: 2
timeout: 60000, // Default: 30000ms
});
import OwnPay from 'ownpay-nodejs';
const client = new OwnPay(process.env.OWNPAY_API_KEY!);
async function createOrder(amount: string, customerEmail: string) {
try {
// 1. Create customer (optional)
const customer = await client.customers.create({
name: 'Customer',
email: customerEmail,
});
// 2. Create payment
const payment = await client.payments.create({
amount,
currency: 'BDT',
customer_email: customerEmail,
customer_name: 'Customer',
callback_url: 'https://your-app.com/webhook',
redirect_url: 'https://your-app.com/success',
cancel_url: 'https://your-app.com/cancel',
reference: `ORDER-${Date.now()}`,
metadata: {
customer_id: customer.uuid,
},
});
// 3. Return checkout URL for customer redirect
return {
payment_id: payment.payment_id,
checkout_url: payment.checkout_url,
};
} catch (error) {
console.error('Order creation failed:', error);
throw error;
}
}
// Check payment status
async function checkPaymentStatus(paymentId: string) {
const payment = await client.payments.get(paymentId);
switch (payment.status) {
case 'completed':
return { success: true, message: 'Payment completed' };
case 'pending':
return { success: false, message: 'Payment pending' };
case 'failed':
return { success: false, message: 'Payment failed' };
default:
return { success: false, message: `Status: ${payment.status}` };
}
}
import express from 'express';
import OwnPay, { verifyWebhookSignature } from 'ownpay-nodejs';
const app = express();
const client = new OwnPay(process.env.OWNPAY_API_KEY!);
// IMPORTANT: Use raw body for webhook verification
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
try {
const signature = req.headers['x-ownpay-signature'] as string;
const timestamp = req.headers['x-ownpay-timestamp'] as string;
// Verify signature
verifyWebhookSignature({
payload: req.body,
signature,
secret: process.env.OWNPAY_WEBHOOK_SECRET!,
timestamp,
});
// Parse and handle event
const event = JSON.parse(req.body.toString());
switch (event.event) {
case 'payment.completed':
// Update order status, send confirmation, etc.
console.log(`Payment completed: ${event.transaction_id}`);
break;
case 'payment.failed':
// Handle failed payment
console.log(`Payment failed: ${event.transaction_id}`);
break;
}
res.status(200).json({ received: true });
} catch (error) {
console.error('Webhook error:', error);
res.status(400).json({ error: 'Invalid webhook' });
}
});
app.listen(3000);
async function getTransactionReport(startDate: string, endDate: string) {
const result = await client.transactions.list({
from: startDate,
to: endDate,
per_page: 100,
});
const totalAmount = result.items.reduce(
(sum, txn) => sum + parseFloat(txn.amount),
0
);
const totalFees = result.items.reduce(
(sum, txn) => sum + parseFloat(txn.fee),
0
);
return {
transactions: result.items,
total: result.meta.total,
totalAmount,
totalFees,
netAmount: totalAmount - totalFees,
};
}
Ensure your API key starts with op_ and is at least 12 characters long.
// ❌ Wrong
const client = new OwnPay('sk_live_...');
// ✅ Correct
const client = new OwnPay('op_abcdef123456...');
Your API key doesn't have the required permissions:
read scope: GET requestswrite scope: POST/PUT/PATCH/DELETE requestsadmin scope: API key management operationsEnable debug logging by checking error details:
try {
await client.payments.create({ amount: '100.00', currency: 'BDT' });
} catch (error) {
console.error('Error:', error.toJSON());
// {
// name: 'ValidationError',
// type: 'VALIDATION_ERROR',
// message: '...',
// status: 422,
// requestId: 'req-...'
// }
}
| Resource | Methods |
|---|---|
client.payments | create(), get() |
client.transactions | list(), get() |
client.refunds | create(), list(), get() |
client.customers | create(), list(), get() |
client.apiKeys | list(), generate(), revoke() |
client.webhooks | test(), deliveries() |
client.health | check() |
This project is licensed under the MIT License - see the LICENSE file for details.
Contributions are welcome! Please read our Contributing Guide for details.
See CHANGELOG.md for a list of changes.
FAQs
Official Node.js SDK for the OwnPay Payment Gateway API
The npm package ownpay-nodejs receives a total of 0 weekly downloads. As such, ownpay-nodejs popularity was classified as not popular.
We found that ownpay-nodejs demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
An OpenCode user faced harassment after reporting a free AI usage loophole, drawing a bitter backlash in a GitHub thread that has since been deleted.

Threat Research
/Security News
319 browser extensions installed by 13.4 million users hijack searches, capture queries, and collect referral payments from Yahoo and Bing.

Threat Research
Malicious Firefox extensions mimic Phantom, Jupiter, and Bitget wallets to steal recovery phrases and private keys, with one fetching its payload remotely.