Skip to main content

Overview

The Offergrid Provider API lets you automate offer management and order fulfillment by integrating directly with your existing systems.

Getting Started

1. Get Your API Key

Generate a Team API Key from your dashboard:
  1. Sign in to offergrid.io
  2. Navigate to SettingsAPI Keys
  3. Click Generate New Key
  4. Save the key securely
See Authentication for detailed instructions.

2. Choose Your Integration Approach

Option A: Direct API Calls
  • Use HTTP requests from your application
  • Full control and flexibility
  • Best for custom integrations
Option B: Webhooks
  • Receive real-time notifications
  • Event-driven architecture
  • Best for order automation
Option C: Scheduled Sync
  • Poll API periodically
  • Simple to implement
  • Best for batch processing

Common Integration Patterns

Pattern 1: Automated Offer Sync

Sync your internal product catalog to Offergrid:
// Example: Daily sync of offers from your CRM
async function syncOffers() {
  const internalOffers = await fetchFromCRM();

  for (const offer of internalOffers) {
    const offergridOffer = transformToOffergridFormat(offer);

    // Check if offer exists
    const existing = await findOfferBySKU(offer.sku);

    if (existing) {
      // Update existing offer
      await updateOffer(existing.id, offergridOffer);
    } else {
      // Create new offer
      await createOffer(offergridOffer);
    }
  }
}

// Transform your internal format to Offergrid format
function transformToOffergridFormat(internalOffer) {
  return {
    name: internalOffer.productName,
    category: mapCategory(internalOffer.type),
    sku: internalOffer.sku,
    monthlyPrice: internalOffer.price,
    status: internalOffer.isActive ? 'active' : 'inactive',
    description: internalOffer.description,
    serviceSpecificData: {
      // Map category-specific fields
    },
  };
}
Run this sync:
  • Daily: For frequently changing catalogs
  • Hourly: For dynamic pricing
  • On-demand: When products update in your system

Pattern 2: Real-Time Order Processing

Use webhooks to process orders immediately:
// Example: Webhook endpoint to receive new orders
app.post('/webhooks/offergrid/orders', async (req, res) => {
  const { event, orderId, itemId } = req.body;

  if (event === 'order.created') {
    // Fetch full order details
    const order = await fetchOrderFromOffergrid(itemId);

    // Check service availability
    const available = await checkServiceability(order.serviceAddress);

    if (available) {
      // Auto-accept and create work order in your system
      await acceptOrder(itemId);
      await createWorkOrder(order);

      // Schedule customer contact
      await scheduleCustomerCall(order);
    } else {
      // Reject with reason
      await rejectOrder(itemId, 'Service not available at this address');
    }
  }

  res.status(200).send('OK');
});

Pattern 3: Status Sync from Fulfillment System

Update Offergrid when your internal status changes:
// Example: Update Offergrid when your CRM updates order status
async function onWorkOrderStatusChange(workOrder) {
  const statusMap = {
    scheduled: 'scheduled',
    in_progress: 'in_progress',
    completed: 'completed',
    failed: 'failed',
  };

  await updateOffergridOrderStatus(workOrder.offergridItemId, {
    status: statusMap[workOrder.status],
    providerNotes: workOrder.notes,
    scheduledFor: workOrder.appointmentDate,
    metadata: {
      workOrderId: workOrder.id,
      technicianId: workOrder.technicianId,
    },
  });
}

// Hook into your CRM's status change events
crmSystem.on('workorder.status_changed', onWorkOrderStatusChange);

Core API Operations

Managing Offers

POST /provider/offers
{
  "name": "High-Speed Internet 1000 Mbps",
  "category": "internet",
  "status": "active",
  "monthlyPrice": 59.99
}
Returns the created offer with assigned ID.
GET /provider/offers
Returns array of all offers for your team.
PATCH /provider/offers/{id}
{
  "monthlyPrice": 49.99,
  "status": "active"
}
Updates only the fields provided.
DELETE /provider/offers/{id}
Permanently removes the offer.

Managing Orders

GET /provider/orders?status=pending
Filter by status to get orders needing attention.
GET /provider/orders/{itemId}
Returns full order details including customer info and service address.
PATCH /provider/orders/{itemId}/status
{
  "status": "accepted",
  "providerNotes": "Order accepted. Customer will be contacted within 24 hours.",
  "metadata": {}
}
Updates order status and adds notes for reseller.

Error Handling

Implement robust error handling:
async function safeApiCall(apiFunction, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      return await apiFunction();
    } catch (error) {
      if (error.status === 401) {
        // Authentication error - don't retry
        throw new Error('Invalid API key');
      }

      if (error.status === 429) {
        // Rate limited - wait and retry
        await sleep(2 ** i * 1000);
        continue;
      }

      if (error.status >= 500) {
        // Server error - retry
        await sleep(2 ** i * 1000);
        continue;
      }

      // Client error (4xx) - don't retry
      throw error;
    }
  }

  throw new Error('Max retries exceeded');
}

Rate Limiting

Be mindful of rate limits:
  • Burst: 100 requests per minute
  • Sustained: 10,000 requests per hour
Best practices:
  • Implement exponential backoff
  • Cache responses when appropriate
  • Batch operations where possible
  • Use webhooks instead of polling

Security Best Practices

Use environment variables or secure key management:
// ✅ Good
const apiKey = process.env.OFFERGRID_API_KEY;

// ❌ Bad
const apiKey = 'pk_live_abc123...'; // Never hardcode!
Always use https:// endpoints, never http://.
Verify webhook requests actually come from Offergrid:
function verifyWebhook(req) {
  const signature = req.headers['x-offergrid-signature'];
  const payload = JSON.stringify(req.body);
  const expected = createHmac('sha256', webhookSecret)
    .update(payload)
    .digest('hex');

  return signature === expected;
}
Don’t let API calls hang indefinitely:
const response = await fetch(url, {
  headers: { 'x-api-key': apiKey },
  signal: AbortSignal.timeout(10000), // 10 second timeout
});

Testing Your Integration

1. Use Draft Offers

Test with status: "draft" offers that won’t be visible to resellers:
{
  "name": "Test Offer - Do Not Order",
  "status": "draft",
  "monthlyPrice": 0.01
}

2. Create Test Orders

Work with support to create test orders for validation.

3. Monitor Logs

Watch your integration logs for errors:
const logger = createLogger({
  level: 'info',
  format: format.json(),
});

logger.info('Order accepted', {
  orderId: order.id,
  offerId: order.offerId,
  status: 'accepted',
});

Example Integration

Full example of a provider integration:
import { OffergridClient } from '@offergrid/node-sdk';

const client = new OffergridClient({
  apiKey: process.env.OFFERGRID_API_KEY,
});

// Sync offers daily
cron.schedule('0 2 * * *', async () => {
  await syncOffersToOffergrid();
});

// Process new orders via webhook
app.post('/webhooks/offergrid', async (req, res) => {
  const { event, itemId } = req.body;

  if (event === 'order.created') {
    await processNewOrder(itemId);
  }

  res.sendStatus(200);
});

// Update Offergrid when internal status changes
async function onInternalStatusChange(workOrder) {
  await client.orders.updateStatus(workOrder.offergridItemId, {
    status: workOrder.status,
    providerNotes: workOrder.notes,
  });
}

Next Steps