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

pickup-mtaani-sdk

v1.0.0

Published

Official Node.js/TypeScript SDK for Pickup Mtaani API - Kenya's leading delivery platform

Readme

Pickup Mtaani Node.js SDK

Official Node.js/TypeScript SDK for the Pickup Mtaani API - Kenya's leading delivery platform.

npm version CI License: MIT TypeScript Node.js

Features

✅ Full TypeScript support with complete type definitions
✅ Promise-based API with async/await
✅ Comprehensive error handling
✅ Built-in request validation
✅ Automatic retries and timeouts
✅ M-Pesa payment integration
✅ Real-time webhook support
✅ Complete test coverage
✅ Detailed documentation and examples

Installation

npm install pickup-mtaani-sdk
# or
yarn add pickup-mtaani-sdk
# or
pnpm add pickup-mtaani-sdk

Quick Start

import { PickupMtaaniClient } from 'pickup-mtaani-sdk';

const client = new PickupMtaaniClient({
  apiKey: 'your-api-key-here'
});

// Get your business details
const business = await client.business.get();
console.log('Business:', business.name);

Authentication

Get your API key from Pickup Mtaani API Portal

const client = new PickupMtaaniClient({
  apiKey: 'your-api-key',
  timeout: 30000,  // Optional: request timeout in ms (default: 30000)
  debug: false     // Optional: enable debug logging (default: false)
});

Core Services

Business Management

// Get business information
const business = await client.business.get();

// Update business
await client.business.update({
  name: 'New Business Name',
  phone_number: '0712345678',
  category_id: 5
});

// Get categories with pagination
const categories = await client.business.getCategories({
  pageNumber: 0,
  pageSize: 20
});

// Delete business
await client.business.delete();

Locations

// Get all zones
const zones = await client.locations.getZones();

// Get all areas
const areas = await client.locations.getAreas();

// Search for locations
const locations = await client.locations.getLocations({
  searchKey: 'westlands',
  zoneId: 1,
  areaId: 2
});

// Get doorstep destinations
const destinations = await client.locations.getDoorstepDestinations({
  areaId: 2,
  searchKey: 'cbd'
});

Agents

// Get all agents
const agents = await client.agents.list();

// Filter agents by location
const localAgents = await client.agents.list({
  locationId: 245
});

// Search agents by business name
const results = await client.agents.list({
  searchKey: 'kikuyu'
});

Delivery Charges

// Calculate agent-to-agent delivery fee
const agentFee = await client.deliveryCharge.getAgentPackageFee({
  senderAgentID: 362,
  receiverAgentID: 454
});
console.log('Agent delivery fee:', agentFee.price);

// Calculate doorstep delivery fee
const doorstepFee = await client.deliveryCharge.getDoorstepPackageFee({
  senderAgentID: 517,
  doorstepDestinationID: 541
});
console.log('Doorstep delivery fee:', doorstepFee.price);

Error Handling

The SDK provides comprehensive error types for different scenarios:

import {
  ValidationError,
  NotFoundError,
  AuthenticationError,
  InternalServerError
} from 'pickup-mtaani-sdk';

try {
  const business = await client.business.get();
} catch (error) {
  if (error instanceof ValidationError) {
    console.error('Validation failed:', error.validationErrors);
  } else if (error instanceof NotFoundError) {
    console.error('Resource not found:', error.message);
  } else if (error instanceof AuthenticationError) {
    console.error('Invalid API key');
  } else if (error instanceof InternalServerError) {
    console.error('Server error:', error.message);
  }
}

TypeScript Support

The SDK is fully typed for excellent IDE support:

import { Business, Zone, Agent } from 'pickup-mtaani-sdk';

const business: Business = await client.business.get();
const zones: Zone[] = await client.locations.getZones();
const agents: Agent[] = await client.agents.list();

Development Status

✅ Implemented

  • [x] Business management
  • [x] Location services
  • [x] Agent discovery
  • [x] Delivery charge calculation
  • [x] Core types and error handling
  • [x] HTTP client with interceptors

✅ Complete Implementation

  • [x] Agent package management (CRUD operations)
  • [x] Doorstep package management (CRUD operations)
  • [x] Express deliveries with rider matching
  • [x] M-Pesa payment integration
  • [x] Webhook registration
  • [x] Input validation (phone numbers, package values)
  • [x] Complete TypeScript definitions

Package Management

Agent Packages

// Create agent-to-agent package
const package = await client.agentPackages.create(businessId, {
  senderAgentId: 362,
  receiverAgentId: 454,
  customerName: 'John Doe',
  customerPhoneNumber: '0712345678',
  packageName: 'Electronics',
  packageValue: 5000,
  paymentOption: 'vendor',
  on_delivery_balance: 500
});

// Get package details
const details = await client.agentPackages.get(package.id, businessId);

// Update package
await client.agentPackages.update(package.id, {
  customerName: 'Jane Smith',
  packageValue: 6000
});

// List packages with filters
const packages = await client.agentPackages.list(businessId, {
  state: 'in_transit',
  pageNumber: 0,
  pageSize: 10
});

// Delete package
await client.agentPackages.delete(package.id);

// Get unpaid packages
const unpaid = await client.agentPackages.getUnpaid(businessId);

Doorstep Packages

// Create doorstep delivery
const package = await client.doorstepPackages.create(businessId, {
  senderAgentID_id: 517,
  customerName: 'Jane Doe',
  customerPhoneNumber: '0723456789',
  packageName: 'Groceries',
  packageValue: 3000,
  paymentOption: 'vendor',
  doorstepDestinationId: 541,
  locationDescription: 'Near the supermarket',
  lat: -1.2921,
  lng: 36.8219
});

// Get, update, list, delete operations similar to agent packages
const details = await client.doorstepPackages.get(package.id, businessId);
await client.doorstepPackages.update(package.id, { packageValue: 3500 });
const packages = await client.doorstepPackages.list(businessId);
await client.doorstepPackages.delete(package.id);

Express Deliveries

// Get directions and pricing
const directions = await client.expressDeliveries.getDirections(businessId, {
  coordinates: [
    [36.81443, -1.27365],  // departure [lng, lat]
    [36.84224, -1.29124]   // destination [lng, lat]
  ],
  rider_type_id: 2
});
console.log(directions.price); // 560

// Create express delivery
const express = await client.expressDeliveries.create(businessId, {
  customer_name: 'Alice Johnson',
  customer_phone_number: '0745678901',
  package_value: 2000,
  package_name: 'Electronics',
  departure: [36.8219, -1.2921],
  destination: [36.8422, -1.2912],
  exact_location: 'Burma Market',
  payment_option: 'vendor',
  from: 'Westlands',
  to: 'CBD'
});

// Find nearby rider
const riders = await client.expressDeliveries.findRider(express.id);
console.log(riders[0].name); // "Brian Rider"

// Get delivery modes
const modes = await client.expressDeliveries.getDeliveryModes();
// [{ id: 1, name: "Motorbike", description: "..." }]

Payments with M-Pesa

// Get unpaid packages
const unpaidPackages = await client.agentPackages.getUnpaid(businessId);

// Initiate STK Push payment
const paymentResult = await client.payments.payWithSTK(businessId, {
  packages: unpaidPackages.map(pkg => ({
    id: pkg.id,
    type: pkg.type
  })),
  phone: '0712345678'
});
console.log(paymentResult.message); // "Payment initiated"

// Verify payment
const verification = await client.payments.verifyPayment(businessId, {
  packages: unpaidPackages.map(pkg => ({
    id: pkg.id,
    type: pkg.type
  })),
  transcode: 'SH123XYZ789'  // M-Pesa transaction code
});
console.log(verification.message); // "Payment verified"

Webhooks

// Register webhook URL
await client.webhooks.register({
  webhook_url: 'https://yourdomain.com/webhooks/pickup-mtaani'
});

// Handle webhook events in your server
import { WebhookEvent } from 'pickup-mtaani-sdk';

app.post('/webhooks/pickup-mtaani', (req, res) => {
  const event: WebhookEvent = req.body;
  
  switch(event.event_type) {
    case 'package.created':
      console.log('New package:', event.data.receipt_no);
      break;
    case 'package.state_changed':
      console.log('Package state:', event.data.state);
      break;
    case 'package.delivered':
      console.log('Package delivered:', event.data.track_id);
      break;
  }
  
  res.status(200).send('OK');
});

Validation

The SDK includes built-in validators:

import {
  validateKenyanPhoneNumber,
  validatePackageValue,
  formatKenyanPhoneNumber
} from 'pickup-mtaani-sdk';

// Validate phone number
try {
  validateKenyanPhoneNumber('0712345678'); // Valid
  validateKenyanPhoneNumber('0612345678'); // Throws ValidationError
} catch (error) {
  console.error(error.message);
}

// Format phone number
const formatted = formatKenyanPhoneNumber('0712345678');
console.log(formatted); // "+254712345678"

// Validate package value
validatePackageValue(5000); // Valid
validatePackageValue(2000000); // Throws ValidationError

Testing

This SDK includes comprehensive test coverage with both unit and integration tests.

Running Tests

# Run all tests
npm test

# Run only unit tests
npm run test:unit

# Run only integration tests (requires API credentials)
npm run test:integration

# Run tests in watch mode
npm run test:watch

# Generate coverage report
npm run test:coverage

Integration Tests Setup

Integration tests require actual API credentials. To run them:

  1. Copy .env.example to .env.local:

    cp .env.example .env.local
  2. Add your credentials to .env.local:

    PICKUP_MTAANI_API_KEY=your_actual_api_key
    PICKUP_MTAANI_BUSINESS_ID=your_business_id
    TEST_PHONE=0712345678
  3. Run integration tests:

    npm run test:integration

Note: .env.local is gitignored and will never be committed to version control. Integration tests will automatically skip if credentials are not configured.

For detailed testing documentation, see TESTING.md and tests/integration/README.md.

API Reference

See API Documentation for complete API reference.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT

Support