Plugin Architecture

How courier plugins are structured, loaded, and executed within Deliverty Hub.

What Are Courier Plugins?

Courier plugins are NestJS-compatible TypeScript modules that implement the ICourierPlugin interface. Unlike Option A (where Deliverty Hub calls your external API), plugins run within the Deliverty Hub backend process itself, giving you full control over how your courier service integrates with the platform.

When a plugin is deployed, it becomes a first-class part of the Deliverty Hub backend. The system loads your plugin, calls its methods at the appropriate lifecycle points, and your code handles the communication with your own external services.

When to Choose Option B

Build a plugin when you need fine-grained control over the integration logic, want to handle complex data transformations, or need to interact with multiple external services as part of a single delivery operation. For simpler integrations, Option A (API Integration) is usually sufficient.

Plugin Lifecycle

A plugin goes through a well-defined lifecycle from initialization to active use. Understanding this lifecycle helps you write a plugin that integrates smoothly.

1

Initialize

When Deliverty Hub loads your plugin for an organization, it calls initialize(config) with the organization's configuration (API keys, base URLs, custom settings). Use this to set up HTTP clients, validate credentials, and prepare any resources your plugin needs.

2

Active Operations

Once initialized, Deliverty Hub calls your plugin's task management methods as deliveries flow through the system:

  • createTask(taskData) — dispatch a new delivery to your service
  • cancelTask(externalTrackingId) — cancel a previously dispatched delivery
  • getTracking(externalTrackingId) — poll for the current delivery status
3

Health Checks

Deliverty Hub periodically calls healthCheck() to verify that your plugin and its dependencies are operational. If a health check fails, the system can flag the courier as unavailable.

Webhook Handling

When your external courier service sends status updates to Deliverty Hub via webhooks, the system routes those payloads through your plugin for processing. This happens in two steps:

Step 1: Validate the Webhook

validateWebhook(payload, signature?) is called first to verify that the incoming webhook is authentic. This typically involves checking an HMAC signature or verifying a shared secret. If validation fails, the webhook is rejected.

Validation Example
async validateWebhook(payload: any, signature?: string): Promise<boolean> {
  if (!signature) return false;

  const expected = crypto
    .createHmac('sha256', this.webhookSecret)
    .update(JSON.stringify(payload))
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected),
  );
}

Step 2: Parse the Webhook

parseWebhook(payload) is called after successful validation. It converts your courier's proprietary webhook format into Deliverty Hub's standardized IWebhookPayload format. This is where you map your status names, extract tracking IDs, and normalize location data.

Parsing Example
async parseWebhook(payload: any): Promise<IWebhookPayload> {
  return {
    externalTrackingId: payload.delivery_id,
    event: payload.event_type,
    status: this.mapStatus(payload.current_status),
    location: payload.driver_location
      ? { lat: payload.driver_location.lat, lng: payload.driver_location.lng }
      : undefined,
    timestamp: new Date(payload.timestamp),
  };
}

Feature Querying

Not all courier services support the same capabilities. The supportsFeature(feature) method allows Deliverty Hub to query your plugin's capabilities at runtime, so it can adapt its behavior accordingly.

For example, if your plugin returns false for 'cancellation', Deliverty Hub knows not to offer the cancel option to organizations using your courier. If you return true for 'realtime-tracking', the platform can show a live map for deliveries handled by your service.

Feature String Description
'realtime-tracking' Live GPS location updates for deliveries in transit.
'cancellation' Ability to cancel a delivery after it has been dispatched.
'proof-of-delivery' Capture of delivery confirmation (photo, signature, etc.).
'scheduling' Ability to schedule deliveries for a specific future date/time.
'multi-stop' Support for deliveries with multiple pickup or dropoff points.
Feature Support Example
private readonly SUPPORTED_FEATURES = new Set([
  'realtime-tracking',
  'cancellation',
  'proof-of-delivery',
]);

supportsFeature(feature: string): boolean {
  return this.SUPPORTED_FEATURES.has(feature);
}

Deployment

Since plugins run within the Deliverty Hub backend process, deployment is handled by the Deliverty team. Your workflow is:

1

Develop Your Plugin

Write your plugin as a TypeScript class implementing ICourierPlugin. Test it thoroughly against your courier service's API.

2

Compile the Code

Compile your TypeScript to JavaScript. Ensure all dependencies are listed and compatible with the Deliverty Hub runtime environment.

3

Deliver to Deliverty

Provide your compiled plugin code to the Deliverty team along with any configuration documentation (required config keys, webhook setup instructions, etc.).

4

Deployment by Deliverty

The Deliverty team reviews, integrates, and deploys your plugin into the backend. Once deployed, organizations can activate your courier service.

Keep Dependencies Minimal

Since your plugin runs inside the Deliverty Hub backend, keep your external dependencies to a minimum. Use axios or the built-in fetch for HTTP calls. Avoid pulling in large frameworks or libraries that could conflict with the host application.

Next Steps

See the full ICourierPlugin Interface reference for detailed method signatures and a complete example plugin implementation. For deployment instructions, see Deployment.