Demurly
@demurly/sdk v1.0.0

TypeScript SDK

The official TypeScript SDK for the Demurly API. Full type safety, autocomplete, and a clean interface for all operations.

Full TypeScript support
Node.js & Edge runtimes
Built-in retries

Installation

Install the SDK using your preferred package manager:

npm install @demurly/sdk

Requires Node.js 18+ or a modern Edge runtime.

Quick Start

Initialize the client with your API key and make your first request:

index.tstypescript
import { Demurly } from '@demurly/sdk';

// Initialize the client
const demurly = new Demurly({
  apiKey: process.env.DEMURLY_API_KEY!,
});

// List all records
const records = await demurly.records.list({
  status: 'pending_approval',
  limit: 20,
});

console.log(`Found ${records.data.length} records`);

Get your API key

Go to Settings → API Keys in your carrier dashboard to create an API key.

Records API

List Records

Retrieve demurrage records with optional filters for status, date range, terminal, and more.

// List records with filters
const records = await demurly.records.list({
  status: 'approved',
  terminalId: 'trm_abc123',
  startDate: '2024-01-01',
  endDate: '2024-01-31',
  page: 1,
  limit: 50,
});

// Iterate through results
for (const record of records.data) {
  console.log(`Record ${record.id}: $${record.demurrageAmount}`);
}

Get Record

Fetch a single record with full details including GPS points, photos, and metadata.

// Get a single record with full details
const record = await demurly.records.get('rec_abc123');

console.log({
  terminal: record.terminalName,
  driver: record.driverName,
  waitTime: record.waitTimeMinutes,
  amount: record.demurrageAmount,
  status: record.status,
});

Create Record

Start a new demurrage record when a driver arrives at a terminal.

// Create a new demurrage record
const record = await demurly.records.create({
  driverId: 'drv_456',
  terminalId: 'trm_789',
  arrivalTime: new Date().toISOString(),
  latitude: 29.7604,
  longitude: -95.3698,
});

console.log(`Created record: ${record.id}`);

Approve & Dispute

Approve records for payment or dispute them with a reason.

// Approve a record (customer only)
await demurly.records.approve('rec_abc123');

// Dispute a record
await demurly.records.dispute('rec_abc123', {
  reason: 'Incorrect arrival time',
  details: 'Driver arrived at 8:45 AM, not 8:30 AM',
});

Drivers API

Manage drivers in your organization — list, create, update, and deactivate.

// List all active drivers
const drivers = await demurly.drivers.list({
  status: 'active',
});

// Get a specific driver
const driver = await demurly.drivers.get('drv_123');

// Create a new driver
const newDriver = await demurly.drivers.create({
  firstName: 'John',
  lastName: 'Smith',
  phone: '+15551234567',
  email: 'john.smith@example.com',
});

// Deactivate a driver
await demurly.drivers.deactivate('drv_123');

Webhook Verification

Verify webhook signatures to ensure events are from Demurly. Always verify before processing!

webhook-handler.tstypescript
import { Demurly } from '@demurly/sdk';
import express from 'express';

const app = express();

// Use raw body for webhook verification
app.post('/webhooks/demurly',
  express.raw({ type: 'application/json' }),
  (req, res) => {
    const signature = req.headers['x-demurly-signature'] as string;
    const payload = req.body;

    try {
      // Verify the webhook signature
      const event = Demurly.webhooks.verify(
        payload,
        signature,
        process.env.DEMURLY_WEBHOOK_SECRET!
      );

      // Handle the event
      switch (event.type) {
        case 'record.approved':
          console.log('Record approved:', event.data.id);
          break;
        case 'payment.completed':
          console.log('Payment received:', event.data.amount);
          break;
        default:
          console.log('Unhandled event:', event.type);
      }

      res.json({ received: true });
    } catch (err) {
      console.error('Webhook verification failed:', err);
      res.status(400).json({ error: 'Invalid signature' });
    }
  }
);

Security

Always verify webhook signatures. Never trust unverified payloads.

Error Handling

The SDK provides typed error classes for different failure scenarios:

error-handling.tstypescript
import {
  Demurly,
  DemurlyError,
  AuthenticationError,
  RateLimitError,
  NotFoundError,
  ValidationError,
} from '@demurly/sdk';

const demurly = new Demurly({ apiKey: 'your_api_key' });

try {
  const record = await demurly.records.get('rec_invalid');
} catch (error) {
  if (error instanceof AuthenticationError) {
    // Invalid or expired API key
    console.error('Authentication failed. Check your API key.');
  } else if (error instanceof RateLimitError) {
    // Too many requests
    console.error(`Rate limited. Retry after ${error.retryAfter}s`);
  } else if (error instanceof NotFoundError) {
    // Resource not found
    console.error('Record not found');
  } else if (error instanceof ValidationError) {
    // Invalid request parameters
    console.error('Validation errors:', error.errors);
  } else if (error instanceof DemurlyError) {
    // Generic Demurly error
    console.error(`Error ${error.code}: ${error.message}`);
  } else {
    // Unknown error
    throw error;
  }
}
AuthenticationError

Invalid/expired API key

RateLimitError

Too many requests

NotFoundError

Resource not found

ValidationError

Invalid parameters

TypeScript Types

All types are exported for use in your application:

// All types are exported from the SDK
import type {
  Record,
  Driver,
  Terminal,
  Organization,
  Payment,
  WebhookEvent,
  RecordStatus,
  ListRecordsParams,
  CreateRecordParams,
} from '@demurly/sdk';

// TypeScript will enforce correct types
const params: ListRecordsParams = {
  status: 'approved',  // Type-checked!
  limit: 20,
};

const records: Record[] = await demurly.records.list(params);

Ready to integrate?

Get your API key and start building with the Demurly SDK.

SDK Documentation | Demurly