Skip to main content
Pulses are webhook notifications that allow you to receive real-time HTTP POST requests when specific events occur in your Chariow store. Instead of constantly polling the API, Pulses push event data to your configured endpoint URL as soon as something happens, enabling you to build responsive integrations and automations.

How Pulses Work

1

Event Occurs

An event happens in your store (e.g., a sale is completed).
2

Pulse Triggered

Chariow sends an HTTP POST request to your configured endpoint.
3

Process the Event

Your server receives the payload and processes it.
4

Acknowledge Receipt

Your server returns a 2xx status code to confirm receipt.

Setting Up Pulses

You can configure Pulses in several ways:

Via Store Dashboard

  1. Go to AutomationPulses
  2. Click Add Pulse
  3. Enter your webhook endpoint URL (must be HTTPS)
  4. Select the events you want to receive
  5. Optionally select specific products (leave empty for all products)
  6. Save your Pulse
Your Pulse endpoint must be accessible via HTTPS. HTTP endpoints are not supported for security reasons.

Pulse Events

Pulses support the following events. When an event fires, the webhook payload contains an event field with the event value.

Sale Events

Event ValueLabelDescription
successful.saleSuccessful SaleTriggers when a sale is completed
abandoned.saleAbandoned SaleTriggers when a sale is abandoned
failed.saleFailed SaleTriggers when a sale fails

License Events

Event ValueLabelDescription
license.activatedLicense ActivatedTriggers when a license is activated
license.expiredLicense ExpiredTriggers when a license expires
license.issuedLicense IssuedTriggers when a license is issued to a customer
license.revokedLicense RevokedTriggers when a license is revoked

Affiliate Events

Event ValueLabelDescription
affiliate.joinedAffiliate JoinedTriggers when a new affiliate joins your store
You can configure multiple events for a single Pulse URL. When any of the selected events occur, Chariow will send a webhook notification to your endpoint with the corresponding event value.

Pulse Payload

When a configured event occurs, Chariow sends an HTTP POST request to your webhook URL with event data in the request body. The exact payload structure depends on the event type.
Pulse payloads contain comprehensive event data, including details about the entity (sale, license, etc.), customer information, product details, and store context. The payload structure varies by event type to provide relevant information for each event.

Successful Sale Example

When a successful sale occurs, Chariow sends a webhook with the successful.sale event:
{
  "event": "successful.sale",
  "sale": {
    "id": "sal_xyz789abc",
    "amount": {
      "amount": 9900,
      "formatted": "$99.00",
      "currency": "USD"
    },
    "original_amount": {
      "amount": 9900,
      "formatted": "$99.00",
      "currency": "USD"
    },
    "discount_amount": {
      "amount": 0,
      "formatted": "$0.00",
      "currency": "USD"
    },
    "settlement": {
      "amount": {
        "amount": 8910,
        "formatted": "$89.10",
        "currency": "USD"
      },
      "due_at": "2025-01-22T10:30:00+00:00",
      "done_at": null,
      "service_fee": {
        "amount": 495,
        "formatted": "$4.95",
        "currency": "USD"
      },
      "payment_fee": {
        "amount": 495,
        "formatted": "$4.95",
        "currency": "USD"
      },
      "fee": {
        "amount": 990,
        "formatted": "$9.90",
        "currency": "USD"
      }
    },
    "status": "completed",
    "created_at": "2025-01-15T10:30:00+00:00",
    "custom_fields": null,
    "custom_metadata": {"order_ref": "ORD-123"},
    "completed_at": "2025-01-15T10:32:00+00:00",
    "abandoned_at": null,
    "failed_at": null
  },
  "product": {
    "id": "prd_def456",
    "name": "Premium Course",
    "url": "https://mystore.mychariow.com/p/premium-course",
    "price": {
      "amount": 9900,
      "formatted": "$99.00",
      "currency": "USD"
    }
  },
  "customer": {
    "id": "cus_abc123",
    "name": "John Doe",
    "first_name": "John",
    "last_name": "Doe",
    "email": "[email protected]",
    "phone": "+1234567890",
    "country": "US"
  },
  "affiliate": null,
  "store": {
    "id": "str_xyz789",
    "name": "My Digital Store",
    "url": "https://mystore.mychariow.com"
  },
  "checkout": {
    "url": "https://mystore.mychariow.com/checkout/sal_xyz789abc"
  }
}

License Activated Example

When a license is activated, Chariow sends a webhook with the license.activated event:
{
  "event": "license.activated",
  "license": {
    "id": "lic_ghi789def",
    "key": "ABCD-1234-EFGH-5678",
    "status": "active",
    "source_type": "sale",
    "activation_count": 1,
    "max_activations": 5,
    "activated_at": "2025-01-15T10:35:00+00:00",
    "expires_at": "2026-01-15T10:35:00+00:00",
    "expired_at": null,
    "revoked_at": null,
    "created_at": "2025-01-15T10:30:00+00:00"
  },
  "product": {
    "id": "prd_def456",
    "name": "Pro Software License",
    "url": "https://mystore.mychariow.com/p/pro-software"
  },
  "customer": {
    "id": "cus_abc123",
    "name": "John Doe",
    "first_name": "John",
    "last_name": "Doe",
    "email": "[email protected]",
    "phone": "+1234567890",
    "country": "US"
  },
  "store": {
    "id": "str_xyz789",
    "name": "My Digital Store",
    "url": "https://mystore.mychariow.com"
  }
}

Affiliate Joined Example

When a new affiliate joins your store, Chariow sends a webhook with the affiliate.joined event:
{
  "event": "affiliate.joined",
  "affiliate": {
    "id": "saff_xyz789abc",
    "account": {
      "id": "aff_abc123def",
      "code": "CREATOR123",
      "pseudo": "creative_studio",
      "email": "[email protected]",
      "first_name": "John",
      "last_name": "Doe",
      "name": "John Doe",
      "country": {
        "code": "US",
        "name": "United States"
      },
      "phone": {
        "country_code": "US",
        "formatted": "+1 234 567 890"
      }
    },
    "source": "invitation",
    "status": "active",
    "joined_at": "2025-01-15T10:40:00+00:00"
  },
  "store": {
    "id": "str_xyz789",
    "name": "My Digital Store",
    "url": "https://mystore.mychariow.com"
  }
}
The exact payload structure may include additional fields depending on the event type and context. Always check the actual payload received at your endpoint for the complete data structure.

Handling Pulses

Basic Example (Node.js/Express)

const express = require('express');
const app = express();

app.post('/webhooks/chariow', express.json(), (req, res) => {
  const payload = req.body;
  const event = payload.event;

  switch (event) {
    case 'successful.sale':
      handleSuccessfulSale(payload.sale, payload.product, payload.customer, payload.store);
      break;
    case 'abandoned.sale':
      handleAbandonedSale(payload.sale, payload.store);
      break;
    case 'failed.sale':
      handleFailedSale(payload.sale, payload.store);
      break;
    case 'license.activated':
      handleLicenseActivated(payload.license, payload.product, payload.customer);
      break;
    case 'license.expired':
      handleLicenseExpired(payload.license, payload.customer);
      break;
    case 'license.issued':
      handleLicenseIssued(payload.license, payload.product, payload.customer);
      break;
    case 'license.revoked':
      handleLicenseRevoked(payload.license, payload.customer);
      break;
    case 'affiliate.joined':
      handleAffiliateJoined(payload.affiliate, payload.store);
      break;
    default:
      console.log(`Unhandled event type: ${event}`);
  }

  // Always return 200 to acknowledge receipt
  res.status(200).send('OK');
});

function handleSuccessfulSale(sale, store) {
  console.log(`Sale completed: ${sale.id} in store ${store.name}`);
  // Add customer to CRM, send confirmation email, grant access, etc.
}

function handleLicenseActivated(license, customer) {
  console.log(`License activated: ${license.key} for ${customer.email}`);
  // Log activation, update internal records, notify customer, etc.
}

function handleAffiliateJoined(affiliate, store) {
  console.log(`New affiliate joined: ${affiliate.account.code} in store ${store.name}`);
  // Send welcome email, create affiliate dashboard access, notify team, etc.
}

app.listen(3000, () => console.log('Webhook server running on port 3000'));

PHP Example

<?php

// Read the raw POST data
$payload = file_get_contents('php://input');
$data = json_decode($payload, true);

$event = $data['event'] ?? null;

switch ($event) {
    case 'successful.sale':
        handleSuccessfulSale($data['sale'], $data['product'], $data['customer'], $data['store']);
        break;
    case 'abandoned.sale':
        handleAbandonedSale($data['sale'], $data['store']);
        break;
    case 'failed.sale':
        handleFailedSale($data['sale'], $data['store']);
        break;
    case 'license.activated':
        handleLicenseActivated($data['license'], $data['product'], $data['customer']);
        break;
    case 'license.expired':
        handleLicenseExpired($data['license'], $data['customer']);
        break;
    case 'license.issued':
        handleLicenseIssued($data['license'], $data['product'], $data['customer']);
        break;
    case 'license.revoked':
        handleLicenseRevoked($data['license'], $data['customer']);
        break;
    case 'affiliate.joined':
        handleAffiliateJoined($data['affiliate'], $data['store']);
        break;
    default:
        error_log("Unhandled event type: " . $event);
}

// Always return 200 to acknowledge receipt
http_response_code(200);
echo 'OK';

function handleSuccessfulSale($sale, $store) {
    error_log("Sale completed: {$sale['id']} in store {$store['name']}");
    // Add customer to CRM, send confirmation email, grant access, etc.
}

function handleLicenseActivated($license, $customer) {
    error_log("License activated: {$license['key']} for {$customer['email']}");
    // Log activation, update internal records, notify customer, etc.
}

function handleAffiliateJoined($affiliate, $store) {
    error_log("New affiliate joined: {$affiliate['account']['code']} in store {$store['name']}");
    // Send welcome email, create affiliate dashboard access, notify team, etc.
}

Retry Policy

If your endpoint doesn’t respond with a 2xx status code, Chariow will retry the Pulse:
AttemptDelay
1st retry1 minute
2nd retry5 minutes
3rd retry30 minutes
4th retry2 hours
5th retry24 hours
After 5 failed attempts, the Pulse is marked as failed.
Ensure your Pulse endpoint responds quickly (within 30 seconds). Long-running processes should be handled asynchronously.

Best Practices

Return a 200 response immediately, then process the Pulse asynchronously to avoid timeouts:
app.post('/webhooks/chariow', (req, res) => {
  // Acknowledge receipt immediately
  res.status(200).send('OK');

  // Process asynchronously (e.g., queue job, background worker)
  queuePulseProcessing(req.body);
});
Due to retry logic, Pulses may be sent multiple times. Implement idempotency by tracking processed events:
const processedEvents = new Set();

async function processPulse(payload) {
  // Create unique identifier from pulse data
  const uniqueId = `${payload.event}_${payload.sale?.id || payload.license?.id || payload.affiliate?.id}`;

  if (processedEvents.has(uniqueId)) {
    console.log('Duplicate pulse, skipping');
    return;
  }

  processedEvents.add(uniqueId);
  // Process the pulse...
}
Always use HTTPS for your Pulse endpoint to ensure data is encrypted in transit. Chariow will reject HTTP endpoints for security reasons.
Monitor your Pulse endpoint for failures and errors. Check your store dashboard regularly for failed Pulse deliveries and investigate the root cause.
For high-volume stores, consider creating separate Pulses for different products to make processing more efficient and organised.

Testing Pulses

Use the Pulse testing feature in your dashboard:
  1. Go to AutomationPulses
  2. Click on your Pulse
  3. Click Send Test Event
  4. Select an event type
  5. Check your endpoint received the test payload
For local development, use a service like ngrok to expose your local server to the internet.

Managing Pulses via API

You can programmatically manage your Pulses using the Chariow Public API:

List All Pulses

curl -X GET "https://api.chariow.com/v1/pulses" \
  -H "Authorization: Bearer YOUR_API_KEY"

Get a Specific Pulse

curl -X GET "https://api.chariow.com/v1/pulses/pulse_abc123xyz" \
  -H "Authorization: Bearer YOUR_API_KEY"

Filter Pulses

You can filter pulses by URL or event type using the search parameter:
curl -X GET "https://api.chariow.com/v1/pulses?search=successful_sale" \
  -H "Authorization: Bearer YOUR_API_KEY"
For complete API documentation, see the List Pulses and Get Pulse endpoints.