Skip to content

Code Examples

This page provides complete, production-ready code examples for integrating with the CRM M2M API in multiple programming languages and platforms.

Note: the language examples below call GET /products (the list endpoint) as a minimal smoke test. That endpoint is deprecated for catalog sync — for a real integration, use GET /products/search with syncToken, as shown in the WooCommerce section and the product sync guide.

Terminal window
npm install axios

Download: get-token.js

/**
* Get OAuth Access Token - Node.js Example
*/
import axios from 'axios';
// Configuration - Load from environment variables
const COGNITO_DOMAIN = process.env.OAUTH_COGNITO_DOMAIN;
const CLIENT_ID = process.env.OAUTH_CLIENT_ID;
const CLIENT_SECRET = process.env.OAUTH_CLIENT_SECRET;
const SCOPES = process.env.OAUTH_SCOPES || 'crm-api/products.read';
if (!COGNITO_DOMAIN || !CLIENT_ID || !CLIENT_SECRET) {
console.error('Missing required environment variables: OAUTH_COGNITO_DOMAIN, OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET');
process.exit(1);
}
async function getAccessToken() {
try {
const tokenUrl = `https://${COGNITO_DOMAIN}/oauth2/token`;
const params = new URLSearchParams({
grant_type: 'client_credentials',
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
scope: SCOPES,
});
const response = await axios.post(tokenUrl, params, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
});
const { access_token, token_type, expires_in } = response.data;
console.log('Access token obtained successfully');
console.log(`Token type: ${token_type}`);
console.log(`Expires in: ${expires_in} seconds (${expires_in / 60} minutes)`);
return access_token;
} catch (error) {
if (error.response) {
console.error('Token request failed:', error.response.data);
throw new Error(`Token error: ${error.response.data.error}`);
}
throw error;
}
}
export { getAccessToken };

Download: call-api.js

/**
* Call CRM API - Node.js Example
*/
import axios from 'axios';
import { getAccessToken } from './get-token.js';
const API_BASE_URL = process.env.API_BASE_URL;
if (!API_BASE_URL) {
console.error('Missing required environment variable: API_BASE_URL');
process.exit(1);
}
async function getProducts(accessToken, limit = 10) {
try {
const response = await axios.get(`${API_BASE_URL}/products`, {
params: { limit },
headers: { 'Authorization': `Bearer ${accessToken}` },
});
console.log(`Retrieved ${response.data.products.length} products`);
return response.data;
} catch (error) {
if (error.response) {
console.error('API request failed:', error.response.status, error.response.data);
throw new Error(`API error: ${error.response.data.message}`);
}
throw error;
}
}
async function main() {
try {
console.log('Obtaining access token...\n');
const accessToken = await getAccessToken();
console.log('\nFetching products...\n');
const productsData = await getProducts(accessToken, 5);
console.log('\nProducts:');
productsData.products.forEach(product => {
console.log(` - ${product.productCode}: ${product.description} (R${product.price})`);
});
console.log('\nAll API calls completed successfully!');
} catch (error) {
console.error('\nError:', error.message);
process.exit(1);
}
}
main();
Terminal window
# Run the example
node call-api.js
Terminal window
pip install requests

Download: get_token.py

"""
Get OAuth Access Token - Python Example
"""
import os
import requests
from typing import Dict
# Configuration - Load from environment variables
COGNITO_DOMAIN = os.environ['OAUTH_COGNITO_DOMAIN']
CLIENT_ID = os.environ['OAUTH_CLIENT_ID']
CLIENT_SECRET = os.environ['OAUTH_CLIENT_SECRET']
SCOPES = os.environ.get('OAUTH_SCOPES', 'crm-api/products.read')
def get_access_token() -> str:
"""Get an access token using client credentials."""
token_url = f"https://{COGNITO_DOMAIN}/oauth2/token"
data = {
"grant_type": "client_credentials",
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
"scope": SCOPES,
}
response = requests.post(
token_url,
data=data,
headers={"Content-Type": "application/x-www-form-urlencoded"},
)
if response.status_code != 200:
error_data = response.json()
raise requests.HTTPError(
f"Token request failed: {error_data.get('error')} - "
f"{error_data.get('error_description')}"
)
token_data = response.json()
access_token = token_data["access_token"]
expires_in = token_data["expires_in"]
print("✅ Access token obtained successfully")
print(f"Expires in: {expires_in} seconds ({expires_in / 60:.0f} minutes)")
return access_token
if __name__ == "__main__":
try:
token = get_access_token()
print(f"\n📋 Use this token in API requests:")
print(f"Authorization: Bearer {token[:50]}...")
except Exception as e:
print(f"❌ Error: {e}")
exit(1)

Download: call_api.py

"""
Call CRM API - Python Example
"""
import os
import requests
from typing import List, Dict, Optional
from get_token import get_access_token
API_BASE_URL = os.environ['API_BASE_URL']
def get_products(access_token: str, limit: int = 10) -> Dict:
"""Get products from the CRM API."""
response = requests.get(
f"{API_BASE_URL}/products",
params={"limit": limit},
headers={"Authorization": f"Bearer {access_token}"},
)
if response.status_code != 200:
error_data = response.json()
raise requests.HTTPError(
f"API request failed: {response.status_code} - "
f"{error_data.get('message', response.text)}"
)
data = response.json()
print(f"✅ Retrieved {len(data['products'])} products")
return data
def main():
"""Main example function"""
try:
# Step 1: Get access token
print("🔐 Obtaining access token...\n")
access_token = get_access_token()
# Step 2: Get products
print("\n📦 Fetching products...\n")
products_data = get_products(access_token, limit=5)
print("\nProducts:")
for product in products_data["products"]:
print(
f" - {product['productCode']}: {product['description']} "
f"(R{product['price']})"
)
print("\n✅ All API calls completed successfully!")
except Exception as e:
print(f"\n❌ Error: {e}")
exit(1)
if __name__ == "__main__":
main()
Terminal window
# Run the example
python call_api.py

Download: get-token.php

<?php
/**
* Get OAuth Access Token - PHP Example
*/
// Configuration - Load from environment variables
$cognitoDomain = getenv('OAUTH_COGNITO_DOMAIN');
$clientId = getenv('OAUTH_CLIENT_ID');
$clientSecret = getenv('OAUTH_CLIENT_SECRET');
$scopes = getenv('OAUTH_SCOPES') ?: 'crm-api/products.read';
if (!$cognitoDomain || !$clientId || !$clientSecret) {
fwrite(STDERR, "Missing required environment variables: OAUTH_COGNITO_DOMAIN, OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET\n");
exit(1);
}
function getAccessToken(): array
{
$cognitoDomain = getenv('OAUTH_COGNITO_DOMAIN');
$clientId = getenv('OAUTH_CLIENT_ID');
$clientSecret = getenv('OAUTH_CLIENT_SECRET');
$scopes = getenv('OAUTH_SCOPES') ?: 'crm-api/products.read';
$tokenUrl = 'https://' . $cognitoDomain . '/oauth2/token';
$data = [
'grant_type' => 'client_credentials',
'client_id' => $clientId,
'client_secret' => $clientSecret,
'scope' => $scopes,
];
$ch = curl_init($tokenUrl);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($data),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/x-www-form-urlencoded'],
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200) {
$errorData = json_decode($response, true);
throw new Exception(
"Token request failed: {$errorData['error']} - {$errorData['error_description']}"
);
}
$tokenData = json_decode($response, true);
echo "✅ Access token obtained successfully\n";
return $tokenData;
}
if (php_sapi_name() === 'cli') {
try {
$tokenData = getAccessToken();
echo "\n📋 Use this token in API requests:\n";
echo "Authorization: Bearer " . substr($tokenData['access_token'], 0, 50) . "...\n";
} catch (Exception $e) {
echo "❌ Error: {$e->getMessage()}\n";
exit(1);
}
}

Download: call-api.php

<?php
/**
* Call CRM API - PHP Example
*/
require_once __DIR__ . '/get-token.php';
$apiBaseUrl = getenv('API_BASE_URL');
if (!$apiBaseUrl) {
fwrite(STDERR, "Missing required environment variable: API_BASE_URL\n");
exit(1);
}
function getProducts(string $accessToken, int $limit = 10): array
{
$apiBaseUrl = getenv('API_BASE_URL');
$url = $apiBaseUrl . '/products?' . http_build_query(['limit' => $limit]);
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer {$accessToken}"],
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200) {
$errorData = json_decode($response, true);
throw new Exception(
"API request failed: {$httpCode} - " . ($errorData['message'] ?? $response)
);
}
$data = json_decode($response, true);
echo "✅ Retrieved " . count($data['products']) . " products\n";
return $data;
}
if (php_sapi_name() === 'cli') {
try {
echo "🔐 Obtaining access token...\n\n";
$tokenData = getAccessToken();
echo "\n📦 Fetching products...\n\n";
$productsData = getProducts($tokenData['access_token'], 5);
echo "\nProducts:\n";
foreach ($productsData['products'] as $product) {
echo " - {$product['productCode']}: {$product['description']} (R{$product['price']})\n";
}
echo "\n✅ All API calls completed successfully!\n";
} catch (Exception $e) {
echo "\n❌ Error: {$e->getMessage()}\n";
exit(1);
}
}
Terminal window
# Run the example
php call-api.php

Download: examples.sh

#!/bin/bash
# Configuration - Load from environment variables
: "${OAUTH_TOKEN_ENDPOINT:?Missing required env var OAUTH_TOKEN_ENDPOINT}"
: "${OAUTH_CLIENT_ID:?Missing required env var OAUTH_CLIENT_ID}"
: "${OAUTH_CLIENT_SECRET:?Missing required env var OAUTH_CLIENT_SECRET}"
SCOPES="${OAUTH_SCOPES:-crm-api/products.read}"
TOKEN_RESPONSE=$(curl -s -X POST "${OAUTH_TOKEN_ENDPOINT}" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=${OAUTH_CLIENT_ID}" \
-d "client_secret=${OAUTH_CLIENT_SECRET}" \
-d "scope=${SCOPES}")
ACCESS_TOKEN=$(echo "$TOKEN_RESPONSE" | grep -o '"access_token":"[^"]*' | sed 's/"access_token":"//')
echo "Access token obtained: ${ACCESS_TOKEN:0:50}..."
Terminal window
: "${API_BASE_URL:?Missing required env var API_BASE_URL}"
PRODUCTS_RESPONSE=$(curl -s -X GET "${API_BASE_URL}/products?limit=5" \
-H "Authorization: Bearer ${ACCESS_TOKEN}")
echo "$PRODUCTS_RESPONSE" | jq '.'
Terminal window
SEARCH_RESPONSE=$(curl -s -X GET "${API_BASE_URL}/products/search?q=widget" \
-H "Authorization: Bearer ${ACCESS_TOKEN}")
echo "$SEARCH_RESPONSE" | jq '.'
Terminal window
PRODUCT_ID="prod-123"
PRODUCT_RESPONSE=$(curl -s -X GET "${API_BASE_URL}/products/${PRODUCT_ID}" \
-H "Authorization: Bearer ${ACCESS_TOKEN}")
echo "$PRODUCT_RESPONSE" | jq '.'
Terminal window
BRANDS_RESPONSE=$(curl -s -X GET "${API_BASE_URL}/brands?limit=20" \
-H "Authorization: Bearer ${ACCESS_TOKEN}")
echo "$BRANDS_RESPONSE" | jq '.'

The M2M API is read-only. There is no POST/PUT/DELETE for products or brands via M2M — those operations require an admin web-app session and return 403 for an M2M token. Use the read endpoints above to sync the CRM catalog into your own system.

WordPress example for syncing the CRM catalog into WooCommerce. The M2M API is read-only, so the supported direction is CRM → WooCommerce: read products from the CRM and upsert them as WooCommerce products. (To push WooCommerce products into the CRM you would need write access, which is not available to M2M clients.)

For the recommended incremental-sync pattern (updatedAfter + syncToken), see the M2M Product Sync Guide.

Download: functions.php

  • ✅ Pull the CRM catalog into WooCommerce (one-way, CRM → WooCommerce)
  • ✅ Upsert by productCode → WooCommerce SKU (create or update)
  • ✅ Paginated full sync via GET /products/search + syncToken
  • ✅ Token caching (cache until shortly before expires_in)
  • ✅ Scheduled background sync via WP-Cron
  • ✅ Error handling and admin notices

Add this code to your theme’s functions.php or create a custom plugin:

<?php
/**
* WooCommerce CRM Catalog Sync (CRM → WooCommerce, read-only)
*/
// Configuration (add to wp-config.php)
define('CRM_CLIENT_ID', 'your-client-id-here');
define('CRM_CLIENT_SECRET', 'your-client-secret-here');
define('CRM_API_BASE_URL', 'https://{api-base-url}');
define('CRM_TOKEN_URL', '{token-endpoint}');
define('CRM_SCOPES', 'crm-api/products.read');
/**
* Get CRM access token (with caching)
*/
function crm_get_access_token()
{
$cached_token = get_transient('crm_access_token');
if ($cached_token !== false) {
return $cached_token;
}
$response = wp_remote_post(CRM_TOKEN_URL, [
'headers' => ['Content-Type' => 'application/x-www-form-urlencoded'],
'body' => [
'grant_type' => 'client_credentials',
'client_id' => CRM_CLIENT_ID,
'client_secret' => CRM_CLIENT_SECRET,
'scope' => CRM_SCOPES,
],
'timeout' => 15,
]);
if (is_wp_error($response)) {
return $response;
}
$body = json_decode(wp_remote_retrieve_body($response), true);
$access_token = $body['access_token'];
// Cache for 50 minutes (new clients get 1-hour tokens)
set_transient('crm_access_token', $access_token, 50 * MINUTE_IN_SECONDS);
return $access_token;
}
/**
* Upsert a single CRM product into WooCommerce, keyed on productCode → SKU
*/
function crm_upsert_woo_product(array $crm_product)
{
$sku = $crm_product['productCode'] ?? null;
if (!$sku) {
return; // skip products without a stable code
}
$product_id = wc_get_product_id_by_sku($sku);
$product = $product_id ? wc_get_product($product_id) : new WC_Product_Simple();
$product->set_sku($sku);
$product->set_name($crm_product['description'] ?? $sku);
if (isset($crm_product['price'])) {
$product->set_regular_price((string) $crm_product['price']);
}
$product->save();
}
/**
* Full catalog sync: page through GET /products/search using syncToken
*/
function crm_sync_catalog_to_woo()
{
$access_token = crm_get_access_token();
if (is_wp_error($access_token)) {
return $access_token;
}
$sync_token = null;
do {
$query = ['size' => 100];
if ($sync_token) {
$query['syncToken'] = $sync_token;
}
$response = wp_remote_get(
CRM_API_BASE_URL . '/products/search?' . http_build_query($query),
[
'headers' => ['Authorization' => 'Bearer ' . $access_token],
'timeout' => 30,
]
);
if (is_wp_error($response)) {
return $response;
}
$body = json_decode(wp_remote_retrieve_body($response), true);
foreach (($body['data'] ?? []) as $crm_product) {
crm_upsert_woo_product($crm_product);
}
// syncToken is null on the last page
$sync_token = $body['syncToken'] ?? null;
} while ($sync_token);
return true;
}
// Run the catalog sync on a daily WP-Cron schedule
add_action('crm_daily_catalog_sync', 'crm_sync_catalog_to_woo');
if (!wp_next_scheduled('crm_daily_catalog_sync')) {
wp_schedule_event(time(), 'daily', 'crm_daily_catalog_sync');
}

Add to wp-config.php:

define('CRM_CLIENT_ID', 'abc123xyz456def789ghi012');
define('CRM_CLIENT_SECRET', 'your-secret-here');

Import the complete API collection into Postman for easy testing.

Download: M2M_API.postman_collection.json

  1. Import the collection into Postman
  2. Set collection variables:
    • apiUrl: Your API base URL
    • cognitoDomain: Your Cognito domain
    • clientId: Your M2M client ID
    • clientSecret: Your M2M client secret
  3. Run “Get Access Token” (automatically saves token)
  4. Use other requests (automatically use saved token)
  • Authentication

    • Get Access Token
  • Client Management (Admin only)

    • List M2M Clients
    • Create M2M Client
    • Revoke M2M Client
  • API Examples

    • Get Products
    • Search Products
    • Get Product by ID