Developer overview
Implementation guides18 minute readAPI v1

Sage and Pastel API integration guide

A practical polling, webhook and hybrid recipe for connecting SalesPro Hub orders and inventory to Sage or Pastel.

Browse developer docs

This guide provides an implementation recipe for Sage 50cloud Pastel, Sage Business Cloud Accounting, or Sage 300 (Pastel Evolution). It requires a Sage SDK script, scheduled task, or integration middleware; SalesPro Hub does not claim a one-click native Sage/Pastel connector. The same REST/JSON building blocks can be mapped to other ERP/accounting systems.

Overview

The integration lets you:

  • Pull orders from SalesPro Hub into Sage — Sales reps capture orders on the road, your office staff processes them in Sage.
  • Push stock levels from Sage to SalesPro Hub — Keep your sales team's stock counts accurate.
  • Receive real-time order notifications — Get webhooks when orders are placed so Sage can process them immediately.

Architecture Options

Your Sage system runs a scheduled task that periodically checks SalesPro Hub for new orders and syncs stock levels.

text
Every 5-15 minutes:
  1. GET /api/v1/orders?status=pending&acknowledged=false
  2. For each new order → create Sales Order in Sage
  3. POST /api/v1/orders/{orderNumber}/acknowledge (with Sage reference)
  4. PUT /api/v1/orders/{orderNumber}/status → "confirmed"

Daily (or as needed):
  5. Export stock levels from Sage
  6. POST /api/v1/inventory/bulk (update SalesPro Hub stock)

Pros: Simple, reliable, works behind firewalls. Cons: 5-15 minute delay on order processing.

Option B: Webhook-Driven (Real-Time)

SalesPro Hub pushes events to your system as they happen. Best if you have a publicly accessible endpoint.

text
When order.submitted fires:
  1. Receive webhook POST with order details
  2. Create Sales Order in Sage
  3. POST /api/v1/orders/{orderNumber}/acknowledge
  4. PUT /api/v1/orders/{orderNumber}/status → "confirmed"

Pros: Near-instant order processing. Cons: Requires a publicly accessible HTTPS endpoint.

Option C: Hybrid

Use webhooks for orders (time-sensitive) and polling for stock sync (daily).


Step-by-Step Setup

Step 1: Create an API Key

  1. Log into SalesPro Hub as an admin.
  2. Go to Settings > API Keys.
  3. Click Create API Key.
  4. Name it "Sage Integration".
  5. Select the permissions required by your chosen data flows:
    • orders:read
    • orders:write
    • inventory:read
    • inventory:write
    • customers:read
    • customers:write
  6. Click Create and copy the key.

Store the key securely (e.g., in Sage's integration settings or your server's environment variables).

Step 2: Match Your Products

Ensure product SKUs in SalesPro Hub match the item codes in Sage. The API uses SKUs to identify products.

To check: paginate through GET /api/v1/inventory?per_page=100 to retrieve products with their SKUs. Compare these against your Sage item codes.

Step 3: Set Up Order Polling

Create a scheduled script that runs every 5-15 minutes.

PowerShell Example (Windows / Sage 50cloud)

powershell
$apiKey = "sk_your_api_key_here"
$baseUrl = "https://portal.salesrepsoftware.co.za/api/v1"
$headers = @{
    "X-API-Key" = $apiKey
    "Accept" = "application/json"
    "Content-Type" = "application/json"
}

# 1. Get unacknowledged pending orders
$response = Invoke-RestMethod -Uri "$baseUrl/orders?status=pending&acknowledged=false" `
    -Headers $headers -Method Get

foreach ($order in $response.data) {
    Write-Host "Processing order: $($order.order_number)"

    # 2. Create the order in Sage (your Sage SDK logic here)
    # $sageRef = Create-SageOrder -Order $order
    $sageRef = "SAGE-" + (Get-Date -Format "yyyyMMdd") + "-001"  # placeholder

    # 3. Acknowledge the order in SalesPro Hub
    $ackBody = @{ external_reference = $sageRef } | ConvertTo-Json
    Invoke-RestMethod -Uri "$baseUrl/orders/$($order.order_number)/acknowledge" `
        -Headers $headers -Method Post -Body $ackBody

    # 4. Mark as confirmed
    $statusBody = @{ status = "confirmed"; external_reference = $sageRef } | ConvertTo-Json
    Invoke-RestMethod -Uri "$baseUrl/orders/$($order.order_number)/status" `
        -Headers $headers -Method Put -Body $statusBody

    Write-Host "Order $($order.order_number) processed as $sageRef"
}

Save as SalesRepSync.ps1 and schedule with Windows Task Scheduler to run every 10 minutes.

PHP Example

php
<?php

$apiKey = 'sk_your_api_key_here';
$baseUrl = 'https://portal.salesrepsoftware.co.za/api/v1';

function apiRequest(string $method, string $url, ?array $data = null): array
{
    global $apiKey;

    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        "X-API-Key: {$apiKey}",
        'Accept: application/json',
        'Content-Type: application/json',
    ]);

    if ($method === 'POST') {
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data ?? []));
    } elseif ($method === 'PUT') {
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data ?? []));
    }

    $response = curl_exec($ch);
    curl_close($ch);

    return json_decode($response, true);
}

// 1. Get unacknowledged pending orders
$orders = apiRequest('GET', "{$baseUrl}/orders?status=pending&acknowledged=false");

foreach ($orders['data'] as $order) {
    echo "Processing: {$order['order_number']}\n";

    // 2. Create order in your accounting system
    // $sageRef = createSageOrder($order);
    $sageRef = 'SAGE-' . date('Ymd') . '-001'; // placeholder

    // 3. Acknowledge in SalesPro Hub
    apiRequest('POST', "{$baseUrl}/orders/{$order['order_number']}/acknowledge", [
        'external_reference' => $sageRef,
    ]);

    // 4. Mark as confirmed
    apiRequest('PUT', "{$baseUrl}/orders/{$order['order_number']}/status", [
        'status' => 'confirmed',
        'external_reference' => $sageRef,
    ]);

    echo "Done: {$order['order_number']} → {$sageRef}\n";
}

Run with cron: */10 * * * * php /path/to/salesrep-sync.php

Step 4: Set Up Stock Sync

Run daily to push stock levels from Sage to SalesPro Hub.

cURL Example

bash
curl -X POST "https://portal.salesrepsoftware.co.za/api/v1/inventory/bulk" \
  -H "X-API-Key: sk_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "products": [
      {"sku": "WDG-001", "stock_qty": 150},
      {"sku": "WDG-002", "stock_qty": 80},
      {"sku": "WDG-003", "stock_qty": 0}
    ],
    "reference": "SAGE-SYNC-2026-02-09"
  }'

Sage Pastel SDK (VB.NET / C#)

If you're using the Sage Pastel SDK, export stock levels and call the SalesPro Hub API:

csharp
using System.Net.Http;
using System.Text.Json;

public async Task SyncStockToSalesRep()
{
    var apiKey = "sk_your_api_key_here";
    var baseUrl = "https://portal.salesrepsoftware.co.za/api/v1";

    // Get stock from Sage (your SDK logic)
    var sageProducts = GetSageStockLevels();

    var products = sageProducts.Select(p => new {
        sku = p.ItemCode,
        stock_qty = p.QtyOnHand
    }).ToList();

    var payload = new {
        products = products,
        reference = $"SAGE-SYNC-{DateTime.Now:yyyy-MM-dd}"
    };

    using var client = new HttpClient();
    client.DefaultRequestHeaders.Add("X-API-Key", apiKey);
    client.DefaultRequestHeaders.Add("Accept", "application/json");

    var content = new StringContent(
        JsonSerializer.Serialize(payload),
        System.Text.Encoding.UTF8,
        "application/json"
    );

    var response = await client.PostAsync($"{baseUrl}/inventory/bulk", content);
    var result = await response.Content.ReadAsStringAsync();

    Console.WriteLine($"Stock sync result: {result}");
}

Step 5: Set Up Webhooks (Optional)

If you want real-time order notifications instead of polling:

  1. Go to Settings > Webhooks.
  2. Click Add Endpoint.
  3. Enter your endpoint URL (must be publicly accessible HTTPS).
  4. Select order.submitted (and any other events you need).
  5. Copy the signing secret.

Your endpoint receives a POST with the full order details the moment a sales rep submits it.

See the Webhooks guide for payload formats and signature verification.


Mapping SalesPro Hub Data to Sage

Customer Mapping

The order payload includes customer details:

json
"customer": {
    "name": "ABC Trading (Pty) Ltd",
    "contact_person": "John Smith",
    "email": "john@abctrading.co.za",
    "phone": "0821234567"
}

Map customer.name to your Sage customer account. If the customer doesn't exist in Sage, you may want to create them automatically or flag for manual review.

Item Mapping

Order items include SKUs:

json
"items": [
    {
        "sku": "WDG-001",
        "name": "Widget A",
        "quantity": 50,
        "unit_price": "200.00",
        "discount_percent": "0.00",
        "line_total": "10000.00"
    }
]

Map sku to your Sage item code. Ensure SKUs match between systems.

VAT

SalesPro Hub calculates VAT at the South African rate (15%):

json
"subtotal": "10000.00",
"vat_rate": "15.00",
"vat_amount": "1500.00",
"total": "11500.00"

Map these to the appropriate tax fields in Sage.

Amounts

All monetary values are strings formatted to 2 decimal places in South African Rand (ZAR). Convert to your accounting system's numeric format as needed.


Order Lifecycle

Here's how an order flows through both systems:

text
SalesPro Hub                           Sage
─────────                          ────
1. Sales rep creates order
   (status: draft)

2. Sales rep submits order
   (status: pending)
         ─── API poll or webhook ──→
                                    3. Create Sales Order
                                    4. POST /acknowledge
         ←── acknowledged ─────────
                                    5. PUT /status → confirmed
         ←── status: confirmed ────
                                    6. Process & dispatch

                                    7. PUT /status → delivered
         ←── status: delivered ────

8. Commission calculated
   Stock deducted

Troubleshooting

Orders not appearing in API

  • Check that orders have been submitted (status pending). Draft orders are not visible via the API.
  • Verify your API key has orders:read permission.
  • Check your filter parameters — ?acknowledged=true would hide unacknowledged orders.

Stock sync not reflecting in SalesPro Hub

  • Verify your API key has inventory:write permission.
  • Check the API response for errors — invalid SKUs are listed in the errors array.
  • Ensure SKUs match exactly (case-sensitive).

Webhook not receiving events

  • Verify the endpoint URL is publicly accessible.
  • Check the delivery history in Settings > Webhooks > View Deliveries.
  • If the endpoint was auto-disabled (10 failures), re-enable it.
  • Test with the "Send Test" button.

Rate limiting

Professional plan allows 5,000 API calls per day. A typical integration uses:

  • 96 order polls/day (every 15 min) = ~100 calls
  • 1 daily stock sync = 1 call
  • Order acknowledges = depends on volume

You're unlikely to hit the limit unless doing very frequent polling or large bulk operations.

Build against the real API

Professional API features are included in the 14-day trial.