GridlinePOS Solutions

Loyalty API (SoPoints)

Gridline integrates with SoPoints to provide a full loyalty rewards system. Earn points on purchases, redeem for rewards, and track customer loyalty history.

Note: The Loyalty API is a wrapper around the SoPoints external service. All loyalty operations are processed through the SoPoints platform and synced back to Gridline in real-time.

Earn Points

POST/v1/loyalty/earn

Award points to a customer based on a transaction. Points are calculated using the merchant's earn rate configuration.

Request Body
{
  "customer_id": "cus_xyz789",
  "order_id": "ord_a1b2c3d4",
  "amount": 2499,
  "currency": "CAD",
  "metadata": {
    "source": "pos_terminal",
    "location_id": "loc_001"
  }
}
Response
{
  "id": "txn_pts_001",
  "type": "earn",
  "customer_id": "cus_xyz789",
  "points_earned": 25,
  "balance_after": 350,
  "earn_rate": "1 point per $1",
  "order_id": "ord_a1b2c3d4",
  "created_at": "2024-01-15T10:31:00Z"
}

Status Codes

  • 200Points earned successfully
  • 400Invalid request or duplicate order
  • 404Customer not found

Redeem Points

POST/v1/loyalty/redeem

Redeem points for a discount on an order. Validates that the customer has sufficient balance before processing.

Request Body
{
  "customer_id": "cus_xyz789",
  "points": 100,
  "order_id": "ord_e5f6g7h8",
  "reward_id": "rwd_free_drink"
}
Response
{
  "id": "txn_pts_002",
  "type": "redeem",
  "customer_id": "cus_xyz789",
  "points_redeemed": 100,
  "balance_after": 250,
  "discount_amount": 500,
  "discount_currency": "CAD",
  "reward": {
    "id": "rwd_free_drink",
    "name": "Free Drink",
    "points_cost": 100
  },
  "order_id": "ord_e5f6g7h8",
  "created_at": "2024-01-15T12:00:00Z"
}

Status Codes

  • 200Points redeemed successfully
  • 400Insufficient points balance
  • 404Customer or reward not found

Get Balance

GET/v1/loyalty/balance/:customer_id

Retrieve the current points balance and tier status for a customer.

Response
{
  "customer_id": "cus_xyz789",
  "points_balance": 350,
  "lifetime_points": 1250,
  "tier": {
    "name": "Gold",
    "multiplier": 1.5,
    "next_tier": "Platinum",
    "points_to_next_tier": 750
  },
  "available_rewards": [
    {
      "id": "rwd_free_drink",
      "name": "Free Drink",
      "points_cost": 100
    },
    {
      "id": "rwd_10_off",
      "name": "$10 Off",
      "points_cost": 200
    }
  ]
}

Transaction History

GET/v1/loyalty/history/:customer_id

Retrieve the points transaction history for a customer, including all earn and redeem events.

Response
{
  "data": [
    {
      "id": "txn_pts_002",
      "type": "redeem",
      "points": -100,
      "balance_after": 250,
      "description": "Redeemed: Free Drink",
      "created_at": "2024-01-15T12:00:00Z"
    },
    {
      "id": "txn_pts_001",
      "type": "earn",
      "points": 25,
      "balance_after": 350,
      "description": "Order #ord_a1b2c3d4",
      "created_at": "2024-01-15T10:31:00Z"
    }
  ],
  "pagination": {
    "total": 48,
    "page": 1,
    "per_page": 20,
    "has_more": true
  }
}

Loyalty Webhook Events

Subscribe to these events to receive real-time notifications about loyalty activity:

EventDescription
points.earnedPoints awarded to a customer after purchase
points.redeemedPoints redeemed for a reward or discount
points.expiredPoints expired due to inactivity
tier.upgradedCustomer moved up to a higher loyalty tier

SoPoints Integration Guide

Follow these steps to configure SoPoints loyalty in your Gridline integration:

  1. Enable Loyalty — Navigate to Dashboard > Settings > Loyalty and activate SoPoints integration
  2. Configure Earn Rate — Set your points-per-dollar ratio (default: 1 point per $1 spent)
  3. Define Rewards — Create redeemable rewards with point costs
  4. Set Up Webhooks — Subscribe to loyalty events for real-time sync
  5. Test in Sandbox — Use test API keys to verify the flow before going live
loyalty-integration.tsTypeScript
import { Gridline } from '@gridline/sdk';

const client = new Gridline({ apiKey: process.env.GRIDLINE_API_KEY });

// After a successful order, earn points
async function handleOrderPaid(order: Order) {
  const result = await client.loyalty.earn({
    customer_id: order.customer_id,
    order_id: order.id,
    amount: order.total,
    currency: order.currency,
  });

  console.log(`Customer earned ${result.points_earned} points`);
  console.log(`New balance: ${result.balance_after}`);
}

// At checkout, redeem points
async function redeemAtCheckout(customerId: string, rewardId: string, orderId: string) {
  const balance = await client.loyalty.getBalance(customerId);

  const reward = balance.available_rewards.find(r => r.id === rewardId);
  if (!reward) throw new Error('Reward not available');

  if (balance.points_balance < reward.points_cost) {
    throw new Error('Insufficient points');
  }

  return client.loyalty.redeem({
    customer_id: customerId,
    points: reward.points_cost,
    order_id: orderId,
    reward_id: rewardId,
  });
}