npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@sahabaplus/moyasar

v0.2.6

Published

A comprehensive TypeScript SDK for integrating with the Moyasar payment gateway

Readme

Moyasar SDK

A comprehensive TypeScript SDK for integrating with the Moyasar payment gateway. This SDK provides type-safe access to Moyasar's APIs for payments, invoices, and webhook management.

Features

  • Type-safe: Full TypeScript support with comprehensive type definitions
  • Event-driven: Advanced event system for webhook handling
  • Modular: Clean architecture with separation of concerns
  • Multi-platform: Support for web, mobile wallets (Apple Pay, Google Pay, Samsung Pay), and STC Pay
  • Payment Methods: Credit cards, tokenized payments, and digital wallets
  • Invoice Management: Create, update, and manage invoices
  • Webhook Support: Real-time event notifications with built-in validation
  • Well-tested: Comprehensive test suite with high coverage

Installation

npm install @sahabaplus/moyasar

Quick Start

import { MoyasarClient } from "@sahabaplus/moyasar";

const moyasar = new MoyasarClient({
  apiKey: "sk_your_api_key"
});

// Create a payment
const payment = await moyasar.payment.create({
  amount: 1000, // Amount in smallest currency unit (e.g., halalas for SAR)
  currency: "SAR",
  description: "Test payment",
  callback_url: "https://your-app.com/callback",
  source: {
    type: "creditcard",
    name: "John Doe",
    number: "4111111111111111",
    month: 12,
    year: 2025,
    cvc: "123"
  }
});

console.log("Payment created:", payment.id);

API Reference

MoyasarClient

The main client class that provides access to all Moyasar services.

const moyasar = new MoyasarClient({
  apiKey: "sk_your_api_key",
  baseUrl: "https://api.moyasar.com", // Optional, defaults to production
  timeout: 30000 // Optional, defaults to 30 seconds
});

Client Methods

  • ping() - Test API connectivity
  • getClientInfo() - Get client version and configuration info

Payment Service

Handle payment operations including creation, capture, refund, and more.

Create Payment

// Credit Card Payment
const payment = await moyasar.payment.create({
  amount: 1000,
  currency: "SAR",
  description: "Order #12345",
  callback_url: "https://your-app.com/callback",
  source: {
    type: "creditcard",
    name: "Ahmed Mohammed",
    number: "4111111111111111",
    month: 12,
    year: 2025,
    cvc: "123",
    "3ds": true, // Enable 3D Secure
    manual: false // Auto-capture
  },
  metadata: {
    order_id: "12345",
    customer_id: "cust_123"
  }
});

// Apple Pay Payment
const applePayPayment = await moyasar.payment.create({
  amount: 1000,
  currency: "SAR",
  description: "Apple Pay Purchase",
  callback_url: "https://your-app.com/callback",
  source: {
    type: "applepay",
    token: "apple_pay_token_here"
  }
});

// STC Pay Payment
const stcPayPayment = await moyasar.payment.create({
  amount: 1000,
  currency: "SAR",
  description: "STC Pay Purchase",
  callback_url: "https://your-app.com/callback",
  source: {
    type: "stcpay",
    mobile: "966501234567"
  }
});

Payment Operations

// Retrieve payment details
const payment = await moyasar.payment.retrieve("pay_123");

// List payments
const payments = await moyasar.payment.list({
  limit: 10,
  offset: 0,
  status: "paid"
});

// Update payment
const updated = await moyasar.payment.update({
  paymentId: "pay_123",
  update: {
    description: "Updated description",
    metadata: { updated: true }
  }
});

// Capture authorized payment
const captured = await moyasar.payment.capture({
  paymentId: "pay_123",
  capture: {
    amount: 1000 // Optional, captures full amount if not specified
  }
});

// Refund payment
const refunded = await moyasar.payment.refund({
  paymentId: "pay_123",
  refund: {
    amount: 500, // Partial refund
    reason: "Customer requested refund"
  }
});

// Void payment
const voided = await moyasar.payment.void("pay_123");

Advanced Payment Queries

// Get payments by status
const paidPayments = await moyasar.payment.getPaid({ limit: 10 });
const failedPayments = await moyasar.payment.getFailed({ limit: 10 });
const authorizedPayments = await moyasar.payment.getAuthorized({ limit: 10 });

// Search by metadata
const payments = await moyasar.payment.searchByMetadata({
  metadata: { order_id: "12345" },
  options: { limit: 10 }
});

// Get by card last 4 digits
const cardPayments = await moyasar.payment.getByCardLast4({
  last4: "1111",
  options: { limit: 10 }
});

// Get by RRN (Retrieval Reference Number)
const rrnPayments = await moyasar.payment.getByRRN({
  rrn: "123456789012",
  options: { limit: 10 }
});

// Check payment capabilities
const capabilities = await moyasar.payment.getPaymentCapabilities("pay_123");
console.log("Can refund:", capabilities.canRefund);
console.log("Max refund amount:", capabilities.maxRefundAmount);

Invoice Service

Manage invoices and billing.

Create Invoice

const invoice = await moyasar.invoice.create({
  amount: 1000,
  currency: "SAR",
  description: "Monthly subscription",
  callback_url: "https://your-app.com/callback",
  metadata: {
    subscription_id: "sub_123"
  }
});

// Bulk create invoices
const invoices = await moyasar.invoice.createBulk({
  invoices: [
    {
      amount: 1000,
      currency: "SAR",
      description: "Invoice 1",
      callback_url: "https://your-app.com/callback"
    },
    {
      amount: 2000,
      currency: "SAR",
      description: "Invoice 2",
      callback_url: "https://your-app.com/callback"
    }
  ]
});

Invoice Operations

// Retrieve invoice details
const invoice = await moyasar.invoice.retrieve("inv_123");

// List invoices
const invoices = await moyasar.invoice.list({
  limit: 10,
  offset: 0,
  status: "paid"
});

// Update invoice
const updated = await moyasar.invoice.update("inv_123", {
  description: "Updated description"
});

// Cancel invoice
await moyasar.invoice.cancel("inv_123");

Advanced Invoice Queries

// Get invoices by status
const paidInvoices = await moyasar.invoice.getPaid({ limit: 10 });
const expiredInvoices = await moyasar.invoice.getExpired({ limit: 10 });

// Search by metadata
const invoices = await moyasar.invoice.searchByMetadata(
  { subscription_id: "sub_123" },
  { limit: 10 }
);

Webhook Service

Handle real-time event notifications from Moyasar.

Webhook Management

// Create webhook
const webhook = await moyasar.webhook.create({
  url: "https://your-app.com/webhooks/moyasar",
  http_method: "post",
  events: ["payment_paid", "payment_failed", "payment_refunded"]
});

// List webhooks
const webhooks = await moyasar.webhook.list();

// Retrieve webhook details
const webhook = await moyasar.webhook.retrieve("webhook_123");

// Update webhook
const updated = await moyasar.webhook.update("webhook_123", {
  events: ["payment_paid", "payment_failed"]
});

// Delete webhook
await moyasar.webhook.delete("webhook_123");

// Get available webhook events
const events = await moyasar.webhook.availableEvents();
console.log("Available events:", events);

Webhook Attempts

// List webhook attempts
const attempts = await moyasar.webhook.attempts.list({
  limit: 10,
  offset: 0
});

// Retrieve specific attempt
const attempt = await moyasar.webhook.attempts.retrieve("attempt_123");

Processing Webhooks

The SDK provides a robust processWebhook() method that handles parsing, validation, and signature verification:

import { MoyasarClient } from "@sahabaplus/moyasar";

const moyasar = new MoyasarClient({
  apiKey: "sk_your_api_key"
});

// In your webhook endpoint (e.g., Express.js)
app.post("/webhooks/moyasar", async (req, res) => {
  try {
    // Process and verify webhook
    const payload = await moyasar.webhook.processWebhook(
      req.body, // Can be string, Buffer, or parsed object
      {
        signature: req.headers["x-moyasar-signature"],
        secret: "your_webhook_secret"
      }
    ); // If succeeded, all `moyasar.webhook.on*` events will be triggered when matched with the webhook event.


    console.log("Webhook event:", payload.type);
    console.log("Webhook data:", payload.data);

    res.status(200).send("OK");
  } catch (error) {
    console.error("Webhook processing failed:", error);
    res.status(400).send("Invalid webhook");
  }
});

Event Handling

The SDK provides a type-safe event emitter for handling webhook events:

// Listen to specific events
moyasar.webhook.onPaymentEvent("payment_paid", (payload) => {
  console.log("Payment successful:", payload.data);
});

moyasar.webhook.onPaymentEvent("payment_failed", (payload) => {
  console.log("Payment failed:", payload.data);
});

// Listen to all payment events
moyasar.webhook.onAnyPaymentEvent((payload) => {
  console.log("Payment event:", payload.type, payload.data);
});

// Using standard event emitter syntax
moyasar.webhook.on("payment_paid", (payload) => {
  console.log("Payment received:", payload);
});

Available Events

  • payment_paid - Payment completed successfully
  • payment_failed - Payment failed
  • payment_authorized - Payment authorized (manual capture)
  • payment_captured - Payment captured
  • payment_refunded - Payment refunded
  • payment_voided - Payment voided
  • payment_abandoned - Payment abandoned
  • payment_verified - Payment verified
  • payment_canceled - Payment canceled
  • payment_expired - Payment expired
  • balance_transferred - Balance transferred
  • payout_initiated - Payout initiated
  • payout_paid - Payout completed
  • payout_failed - Payout failed
  • payout_canceled - Payout canceled
  • payout_returned - Payout returned

Payment Methods

Credit Cards

Supports all major card schemes:

  • Visa
  • Mastercard
  • American Express
  • Mada (Saudi domestic cards)
const payment = await moyasar.payment.create({
  amount: 1000,
  currency: "SAR",
  description: "Credit card payment",
  callback_url: "https://your-app.com/callback",
  source: {
    type: "creditcard",
    name: "Card Holder Name",
    number: "4111111111111111",
    month: 12,
    year: 2025,
    cvc: "123",
    "3ds": true, // Enable 3D Secure
    manual: false, // Auto-capture
    save_card: true // Save card for future use
  }
});

Digital Wallets

Apple Pay

const payment = await moyasar.payment.create({
  amount: 1000,
  currency: "SAR",
  description: "Apple Pay payment",
  callback_url: "https://your-app.com/callback",
  source: {
    type: "applepay",
    token: "apple_pay_token_from_client"
  }
});

Google Pay

const payment = await moyasar.payment.create({
  amount: 1000,
  currency: "SAR",
  description: "Google Pay payment",
  callback_url: "https://your-app.com/callback",
  source: {
    type: "googlepay",
    token: "google_pay_token_from_client"
  }
});

Samsung Pay

const payment = await moyasar.payment.create({
  amount: 1000,
  currency: "SAR",
  description: "Samsung Pay payment",
  callback_url: "https://your-app.com/callback",
  source: {
    type: "samsungpay",
    token: "samsung_pay_token_from_client"
  }
});

STC Pay

Saudi Telecom's digital wallet service.

const payment = await moyasar.payment.create({
  amount: 1000,
  currency: "SAR",
  description: "STC Pay payment",
  callback_url: "https://your-app.com/callback",
  source: {
    type: "stcpay",
    mobile: "966501234567",
    cashier_id: "cashier_123", // Optional
    branch: "branch_456" // Optional
  }
});

Tokenized Payments

Use saved payment methods for recurring payments.

const payment = await moyasar.payment.create({
  amount: 1000,
  currency: "SAR",
  description: "Token payment",
  callback_url: "https://your-app.com/callback",
  source: {
    type: "token",
    token: "token_1234567890abcdef",
    cvc: "123" // Optional for saved cards
  }
});

Error Handling

The SDK provides comprehensive error handling with specific error types:

import {
  MoyasarError,
  PaymentError,
  InvoiceError,
  WebhookError,
  WebhookValidationError
} from "@sahabaplus/moyasar";

try {
  const payment = await moyasar.payment.create({
    // payment data
  });
} catch (error) {
  if (error instanceof PaymentError) {
    console.log("Payment error:", error.message);
    console.log("HTTP status:", error.statusCode);
  } else if (error instanceof InvoiceError) {
    console.log("Invoice error:", error.message);
  } else if (error instanceof WebhookError) {
    console.log("Webhook error:", error.message);
  } else if (error instanceof MoyasarError) {
    console.log("API error:", error.message);
  } else {
    console.log("Unexpected error:", error);
  }
}

Configuration

Environment Options

const moyasar = new MoyasarClient({
  apiKey: "sk_your_api_key",
  baseUrl: "https://api.moyasar.com", // Production (default)
  // baseUrl: "https://sandbox.moyasar.com", // Sandbox
  timeout: 30000, // Request timeout in milliseconds
  retries: 3, // Number of retries for failed requests
  retryDelay: 1000 // Delay between retries in milliseconds
});

TypeSafe Metadata

You can safely define your metadata type to guarantee type safety during development. Furthermore, your can pass a custom metadata validator to ensure runtime safety for your metadata.

import { MoyasarClient } from "@sahabaplus/moyasar";

type MyMetadata = {
  order_id: string;
  customer_id: string;
  internal_ref: number;
};

const moyasar = new MoyasarClient<MyMetadata>({
  apiKey: "sk_your_api_key"
});

const payment = await moyasar.payment.create({
  amount: 1000,
  currency: "SAR",
  description: "Order payment",
  callback_url: "https://your-app.com/callback",
  source: { type: "creditcard", /* ... */ },
  metadata: { order_id: "12345", customer_id: "cust_123" } // <- Type error, missing `internal_ref` property
});

You can also use a custom metadata validator to ensure runtime safety for your metadata.

import { MoyasarClient } from "@sahabaplus/moyasar";
import { z } from "zod";

// Define your metadata schema
const MyMetadataSchema = z.object({
  order_id: z.string(),
  customer_id: z.string(),
  internal_ref: z.number().optional()
});

type MyMetadata = z.infer<typeof MyMetadataSchema>;

const moyasar = new MoyasarClient<MyMetadata>({
  apiKey: "sk_your_api_key",
  metadataValidator: {
    parse: (data) => MyMetadataSchema.parse(data)
  }
});


// Now all metadata is type-safe
const payment = await moyasar.payment.create({
  amount: 1000,
  currency: "SAR",
  description: "Order payment",
  callback_url: "https://your-app.com/callback",
  source: { type: "creditcard", /* ... */ },
  metadata: {
    order_id: "12345",
    customer_id: "cust_123",
    internal_ref: 999
  }
});

Testing

# Run tests
npm test

# Run tests with coverage
npm run test:coverage

# Run integration tests
npm run test:integration

Examples

Complete Payment Flow with Error Handling

import { MoyasarClient, PaymentError } from "@sahabaplus/moyasar";

const moyasar = new MoyasarClient({
  apiKey: "sk_your_api_key"
});

async function processPayment() {
  try {
    // Create payment
    const payment = await moyasar.payment.create({
      amount: 10000, // 100.00 SAR
      currency: "SAR",
      description: "Order #12345",
      callback_url: "https://myapp.com/callback",
      source: {
        type: "creditcard",
        name: "Ahmed Mohammed",
        number: "4111111111111111",
        month: 12,
        year: 2025,
        cvc: "123",
        "3ds": true
      }
    });

    console.log("Payment created:", payment.id);

    // Check capabilities
    const capabilities = await moyasar.payment.getPaymentCapabilities(payment.id);

    if (capabilities.canRefund) {
      // Perform partial refund
      const refunded = await moyasar.payment.refund({
        paymentId: payment.id,
        refund: {
          amount: 2000, // Refund 20.00 SAR
          reason: "Partial order cancellation"
        }
      });
      console.log("Refund successful:", refunded.refunded_amount);
    }

  } catch (error) {
    if (error instanceof PaymentError) {
      console.error("Payment failed:", error.message);
    } else {
      console.error("Unexpected error:", error);
    }
  }
}

processPayment();

Webhook Server Example (Express.js)

import express from "express";
import { MoyasarClient, WebhookError } from "@sahabaplus/moyasar";

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

const moyasar = new MoyasarClient({
  apiKey: "sk_your_api_key"
});

// Setup event listeners
moyasar.webhook.onPaymentEvent("payment_paid", async (payload) => {
  console.log("Payment received:", payload.data.id);
  // Update your database, send confirmation email, etc.
});

moyasar.webhook.onPaymentEvent("payment_failed", async (payload) => {
  console.log("Payment failed:", payload.data.id);
  // Notify customer, log failure, etc.
});

// Webhook endpoint
app.post("/webhooks/moyasar", async (req, res) => {
  try {
    const signature = req.headers["x-moyasar-signature"];

    // Process webhook with automatic validation
    await moyasar.webhook.processWebhook(req.body, {
      signature: signature as string,
      secret: process.env.WEBHOOK_SECRET!
    });

    res.status(200).send("OK");
  } catch (error) {
    console.error("Webhook error:", error);
    res.status(400).send("Invalid webhook");
  }
});

app.listen(3000, () => {
  console.log("Webhook server running on port 3000");
});

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

MIT License - see the LICENSE file for details.

Support

Changelog

See CHANGELOG.md for version history and updates.