---
title: Order fulfillment
description: Automate provisioning and delivery of telecommunications services after order completion using API workflows
---

Automate the complete order fulfillment process from order submission to service activation. This use case covers the workflows needed to provision telecommunications services, handle payments, and activate subscriptions for customers.

## Prerequisites

You need all of these before you start:

- **Order management**: Understanding of order creation and submission flows
- **Payment processing**: Integration with payment collection systems
- **Service provisioning**: Access to subscription and license management endpoints
- **Inventory management**: Phone number inventory for mobile services

## Overview

Order fulfillment encompasses the complete process after order creation:

1. Submit orders for processing
2. Handle payment collection and validation
3. Provision services and create subscriptions
4. Activate services and manage inventory
5. Monitor fulfillment status and handle exceptions

## Step-by-step implementation

### Step 1: Submit Order for Fulfillment

Transform draft orders into submitted orders ready for processing:

```bash
# Submit order for fulfillment
curl -X POST "{BASE_URL}/orders/{orderId}/submit" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json"

# Monitor order status
curl -X GET "{BASE_URL}/orders/{orderId}" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json"
```

### Step 2: Handle payment collection

Create payment sessions to collect payment for orders:

```bash
# Create payment session
curl -X POST "{BASE_URL}/payment-sessions" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "orderId": "296af5b6-f3b3-4128-b307-5ddc9190502f",
    "paymentProvider": "STRIPE",
    "hosted": true,
    "returnUrl": "https://yourstore.com/success",
    "cancelUrl": "https://yourstore.com/cancel"
  }'

# Check payment status
curl -X GET "{BASE_URL}/payment-sessions/{paymentSessionId}" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json"
```

### Step 3: Reserve phone numbers (for mobile services)

Reserve phone numbers from inventory before service activation:

```bash
# Lease phone numbers
curl -X POST "{BASE_URL}/inventory/lease-numbers" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "quantity": 1,
    "region": "SE",
    "numberType": "mobile",
    "preferences": {
      "areaCode": "08"
    }
  }'
```

### Step 4: Activate subscriptions

Activate subscription services after successful payment:

```bash
# List subscriptions for order
curl -X GET "{BASE_URL}/subscriptions?orderId={orderId}" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json"

# Activate subscription
curl -X POST "{BASE_URL}/subscriptions/{subscriptionId}/activate" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "activationDate": "2024-01-15T10:00:00Z"
  }'
```

## Error handling and retry logic

Handle common fulfillment scenarios with proper error handling:
```javascript
// Comprehensive error handling for fulfillment
const handleFulfillmentError = async (error, orderId, step) => {
  console.error(`Fulfillment error at step ${step}:`, error.message);

  const errorHandling = {
    payment_failed: {
      action: 'retry_payment',
      message: 'Payment collection failed - customer needs to retry payment',
    },
    inventory_unavailable: {
      action: 'wait_inventory',
      message: 'Phone numbers unavailable - waiting for inventory replenishment',
    },
    activation_failed: {
      action: 'manual_review',
      message: 'Service activation failed - requires manual intervention',
    },
    network_error: {
      action: 'retry_with_backoff',
      message: 'Network connectivity issue - will retry automatically',
    },
  };

  const handling = errorHandling[error.code] || {
    action: 'escalate',
    message: 'Unknown error - escalating to support',
  };

  // Log error for monitoring
  await logFulfillmentError(orderId, step, error, handling);

  // Take appropriate action
  switch (handling.action) {
    case 'retry_payment':
      return await createPaymentSession(orderId);
    case 'wait_inventory':
      return await retryWithBackoff(() => processStep(orderId, step));
    case 'retry_with_backoff':
      return await retryWithBackoff(() => processStep(orderId, step));
    case 'manual_review':
      return await escalateToSupport(orderId, error);
    default:
      throw error;
  }
};

// Retry with exponential backoff
const retryWithBackoff = async (operation, maxRetries = 3) => {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await operation();
    } catch (error) {
      if (attempt === maxRetries) throw error;

      const delay = Math.pow(2, attempt) * 1000; // Exponential backoff
      console.log(`Retry attempt ${attempt} failed, waiting ${delay}ms`);
      await new Promise((resolve) => setTimeout(resolve, delay));
    }
  }
};
```

## Webhook Integration

Set up webhooks to handle asynchronous fulfillment events:
```javascript
// Webhook handler for fulfillment events
const handleFulfillmentWebhook = (event) => {
  switch (event.type) {
    case 'order.submitted':
      console.log('Order submitted:', event.data.orderId);
      // Start fulfillment process
      return initiateFulfillment(event.data.orderId);

    case 'payment.completed':
      console.log('Payment completed:', event.data.paymentId);
      // Proceed with service activation
      return processServiceActivation(event.data.orderId);

    case 'subscription.activated':
      console.log('Subscription activated:', event.data.subscriptionId);
      // Send welcome notifications
      return sendActivationNotification(event.data);

    case 'fulfillment.completed':
      console.log('Fulfillment completed:', event.data.orderId);
      // Final cleanup and customer notification
      return completeFulfillmentNotification(event.data);

    case 'fulfillment.failed':
      console.error('Fulfillment failed:', event.data);
      // Handle fulfillment failure
      return handleFulfillmentFailure(event.data);

    default:
      console.log('Unknown webhook event:', event.type);
  }
};

// Express webhook endpoint example
app.post('/webhooks/connect', express.raw({ type: 'application/json' }), (req, res) => {
  const event = JSON.parse(req.body);

  try {
    handleFulfillmentWebhook(event);
    res.status(200).send('OK');
  } catch (error) {
    console.error('Webhook handling failed:', error);
    res.status(500).send('Internal Server Error');
  }
});
```

## Complete fulfillment workflow

Put the steps together in one fulfillment orchestrator:
```javascript
// Complete fulfillment orchestrator
class OrderFulfillmentOrchestrator {
  async processOrder(orderId) {
    try {
      console.log(`Starting fulfillment for order: ${orderId}`);

      // Step 1: Submit order
      const submittedOrder = await this.submitOrder(orderId);

      // Step 2: Handle payment
      const paymentSession = await this.createPaymentSession(orderId);
      await this.waitForPaymentCompletion(paymentSession.paymentSessionId);

      // Step 3: Reserve resources
      const resources = await this.reserveResources(submittedOrder);

      // Step 4: Activate services
      const subscriptions = await this.activateServices(orderId);

      // Step 5: Complete fulfillment
      await this.completeFulfillment(orderId, subscriptions);

      console.log(`Fulfillment completed successfully for order: ${orderId}`);
      return { success: true, subscriptions };
    } catch (error) {
      console.error(`Fulfillment failed for order ${orderId}:`, error);
      await this.handleFulfillmentError(error, orderId);
      throw error;
    }
  }

  async waitForPaymentCompletion(paymentSessionId, timeout = 300000) {
    const startTime = Date.now();

    while (Date.now() - startTime < timeout) {
      const session = await this.checkPaymentStatus(paymentSessionId);

      if (session.status === 'completed') {
        return session;
      } else if (session.status === 'failed' || session.status === 'cancelled') {
        throw new Error(`Payment ${session.status}: ${session.failureReason}`);
      }

      // Poll every 5 seconds
      await new Promise((resolve) => setTimeout(resolve, 5000));
    }

    throw new Error('Payment completion timeout');
  }

  async reserveResources(order) {
    const resources = {};

    // Reserve phone numbers for mobile services
    for (const lineItem of order.lineItems) {
      if (lineItem.productType === 'mobile') {
        const phoneNumber = await this.leasePhoneNumbers({
          quantity: 1,
          region: order.customer.region,
        });
        resources[lineItem.lineItemId] = phoneNumber;
      }
    }

    return resources;
  }
}

// Usage example
const fulfillmentOrchestrator = new OrderFulfillmentOrchestrator();

// Process order fulfillment
fulfillmentOrchestrator
  .processOrder('296af5b6-f3b3-4128-b307-5ddc9190502fe4567-e89b-12d3-a456-426614174000')
  .then((result) => console.log('Fulfillment successful:', result))
  .catch((error) => console.error('Fulfillment failed:', error));
```

## Best practices

### Fulfillment monitoring

- Log every fulfillment step.
- Set up alerts for failed fulfillments or unusual delays
- Track fulfillment metrics (completion time, success rate, failure reasons)
- Use correlation IDs to trace orders through the entire process

### Resource management

- Reserve inventory (phone numbers) early in the process
- Implement inventory validation before order submission
- Handle inventory exhaustion gracefully with customer communication
- Clean up reserved resources if fulfillment fails

### Payment handling

- Validate payment completion before service activation
- Implement payment retry mechanisms for failed transactions
- Handle partial payments appropriately
- Secure payment session data and comply with PCI standards

## Next steps

After implementing order fulfillment:

- [Customer self-service](/developer-guide/use-cases/self-management.md) — A customer manages their own subscriptions and services
- [Payment processing](/developer-guide/use-cases/payment-processing.md) — Set up recurring billing and ongoing payment management

## Common questions

**Q: How long does typical fulfillment take?**
A: The fulfillment time depends on the service type. A mobile service activates in 15 to 30 minutes. A specialized service can take longer.

**Q: What happens if payment fails during fulfillment?**
A: The order remains in a pending state. Payment sessions can be retried, or new payment methods can be collected.

**Q: Can I customize the fulfillment workflow?**
A: Yes, you can implement custom fulfillment logic using webhooks and the various API endpoints to match your business requirements.
