Code Examples
Practical examples for common API tasks.
Setup
Node.js
const axios = require('axios');
const relay = axios.create({
baseURL: 'https://your-domain.com/api/v1',
headers: {
'Authorization': `Bearer ${process.env.RELAY_API_KEY}`,
'Content-Type': 'application/json'
}
});
Python
import requests
import os
BASE_URL = 'https://your-domain.com/api/v1'
HEADERS = {
'Authorization': f'Bearer {os.environ["RELAY_API_KEY"]}',
'Content-Type': 'application/json'
}
Working with Tickets
Create a Ticket
Node.js:
async function createTicket(subject, description, customerEmail) {
const response = await relay.post('/tickets', {
subject,
description,
customer_email: customerEmail,
priority: 'medium'
});
return response.data.data;
}
// Usage
const ticket = await createTicket(
'Need help with order',
'My order #12345 hasnt arrived',
'customer@example.com'
);
console.log('Created ticket:', ticket.id);
Python:
def create_ticket(subject, description, customer_email):
response = requests.post(
f'{BASE_URL}/tickets',
headers=HEADERS,
json={
'subject': subject,
'description': description,
'customer_email': customer_email,
'priority': 'medium'
}
)
return response.json()['data']
# Usage
ticket = create_ticket(
'Need help with order',
'My order #12345 hasnt arrived',
'customer@example.com'
)
print(f"Created ticket: {ticket['id']}")
List Open Tickets
Node.js:
async function getOpenTickets() {
const response = await relay.get('/tickets', {
params: {
status: 'open',
limit: 100
}
});
return response.data.data;
}
// Usage
const tickets = await getOpenTickets();
console.log(`Found ${tickets.length} open tickets`);
Python:
def get_open_tickets():
response = requests.get(
f'{BASE_URL}/tickets',
headers=HEADERS,
params={'status': 'open', 'limit': 100}
)
return response.json()['data']
# Usage
tickets = get_open_tickets()
print(f"Found {len(tickets)} open tickets")
Update Ticket Status
Node.js:
async function resolveTicket(ticketId) {
const response = await relay.patch(`/tickets/${ticketId}`, {
status: 'resolved'
});
return response.data.data;
}
// Usage
await resolveTicket('tkt_123');
Python:
def resolve_ticket(ticket_id):
response = requests.patch(
f'{BASE_URL}/tickets/{ticket_id}',
headers=HEADERS,
json={'status': 'resolved'}
)
return response.json()['data']
# Usage
resolve_ticket('tkt_123')
Working with Conversations
Send a Reply
Node.js:
async function sendReply(ticketId, message) {
const response = await relay.post('/conversations', {
ticket_id: ticketId,
content: message,
type: 'reply',
internal: false
});
return response.data.data;
}
// Usage
await sendReply('tkt_123', 'Thank you for contacting us. Ive looked into your order and it should arrive tomorrow.');
Add Internal Note
Node.js:
async function addNote(ticketId, note) {
const response = await relay.post('/conversations', {
ticket_id: ticketId,
content: note,
type: 'note',
internal: true
});
return response.data.data;
}
// Usage
await addNote('tkt_123', 'Customer called, very frustrated. Handle with care.');
Working with Customers
Find or Create Customer
Node.js:
async function findOrCreateCustomer(email, name) {
// Try to find existing customer
const searchResponse = await relay.get('/customers', {
params: { email }
});
if (searchResponse.data.data.length > 0) {
return searchResponse.data.data[0];
}
// Create new customer
const createResponse = await relay.post('/customers', {
email,
name
});
return createResponse.data.data;
}
// Usage
const customer = await findOrCreateCustomer(
'new@example.com',
'New Customer'
);
Get Customer Tickets
Node.js:
async function getCustomerTickets(customerId) {
const response = await relay.get('/tickets', {
params: {
customer_id: customerId,
limit: 50
}
});
return response.data.data;
}
Webhook Handler
Express.js
const express = require('express');
const crypto = require('crypto');
const app = express();
// Need raw body for signature verification
app.use('/webhook', express.raw({ type: 'application/json' }));
function verifySignature(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return `sha256=${expected}` === signature;
}
app.post('/webhook', (req, res) => {
const signature = req.headers['x-relay-signature'];
if (!verifySignature(req.body, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(req.body);
// Process event
switch (event.event) {
case 'ticket.created':
handleNewTicket(event.data.ticket);
break;
case 'message.customer_reply':
handleCustomerReply(event.data.message, event.data.ticket);
break;
case 'sla.breached':
handleSLABreach(event.data.ticket);
break;
}
res.status(200).send('OK');
});
function handleNewTicket(ticket) {
console.log('New ticket:', ticket.id, ticket.subject);
// Add your logic here
}
function handleCustomerReply(message, ticket) {
console.log('Customer replied to:', ticket.id);
// Add your logic here
}
function handleSLABreach(ticket) {
console.log('SLA breached for:', ticket.id);
// Alert team, escalate, etc.
}
app.listen(3000);
Flask (Python)
from flask import Flask, request
import hmac
import hashlib
import json
import os
app = Flask(__name__)
def verify_signature(payload, signature, secret):
expected = hmac.new(
secret.encode(),
payload,
hashlib.sha256
).hexdigest()
return f"sha256={expected}" == signature
@app.route('/webhook', methods=['POST'])
def webhook():
signature = request.headers.get('X-Relay-Signature')
secret = os.environ['WEBHOOK_SECRET']
if not verify_signature(request.data, signature, secret):
return 'Invalid signature', 401
event = request.json
if event['event'] == 'ticket.created':
handle_new_ticket(event['data']['ticket'])
elif event['event'] == 'message.customer_reply':
handle_customer_reply(event['data']['message'])
return 'OK', 200
def handle_new_ticket(ticket):
print(f"New ticket: {ticket['id']} - {ticket['subject']}")
def handle_customer_reply(message):
print(f"Customer replied: {message['body'][:100]}")
if __name__ == '__main__':
app.run(port=3000)
Bulk Operations
Bulk Update Tickets
Node.js:
async function bulkUpdateTickets(ticketIds, updates) {
const promises = ticketIds.map(id =>
relay.patch(`/tickets/${id}`, updates)
);
// Process in batches to respect rate limits
const results = [];
const batchSize = 10;
for (let i = 0; i < promises.length; i += batchSize) {
const batch = promises.slice(i, i + batchSize);
const batchResults = await Promise.all(batch);
results.push(...batchResults);
// Wait between batches
if (i + batchSize < promises.length) {
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
return results;
}
// Usage: Assign multiple tickets
await bulkUpdateTickets(
['tkt_1', 'tkt_2', 'tkt_3'],
{ assignee_id: 'user_123' }
);
Sync with External CRM
// Sync customers from external CRM
async function syncCustomersFromCRM(crmCustomers) {
for (const crmCustomer of crmCustomers) {
// Find or create in Relay
let customer;
try {
const search = await relay.get('/customers', {
params: { email: crmCustomer.email }
});
if (search.data.data.length > 0) {
// Update existing
customer = await relay.patch(
`/customers/${search.data.data[0].id}`,
{
name: crmCustomer.name,
phone: crmCustomer.phone,
custom_fields: {
crm_id: crmCustomer.id,
account_type: crmCustomer.type
}
}
);
} else {
// Create new
customer = await relay.post('/customers', {
email: crmCustomer.email,
name: crmCustomer.name,
phone: crmCustomer.phone,
custom_fields: {
crm_id: crmCustomer.id,
account_type: crmCustomer.type
}
});
}
console.log(`Synced: ${crmCustomer.email}`);
} catch (error) {
console.error(`Failed to sync ${crmCustomer.email}:`, error.message);
}
// Rate limit protection
await new Promise(resolve => setTimeout(resolve, 100));
}
}
Error Handling
async function safeApiCall(fn) {
try {
return await fn();
} catch (error) {
if (error.response) {
const { status, data } = error.response;
switch (status) {
case 401:
throw new Error('Invalid API key');
case 403:
throw new Error('Permission denied');
case 404:
throw new Error('Resource not found');
case 429:
// Wait and retry
const retryAfter = error.response.headers['retry-after'] || 60;
await new Promise(r => setTimeout(r, retryAfter * 1000));
return safeApiCall(fn);
default:
throw new Error(data.error?.message || 'API error');
}
}
throw error;
}
}
// Usage
const tickets = await safeApiCall(() => relay.get('/tickets'));