SDK & Code Examples
Tiqora doesn't have official SDKs yet, but integrating is straightforward. Here are complete, production-ready client implementations for popular languages.
JavaScript / Node.js
const crypto = require('crypto');
class TiqoraClient {
constructor(apiKey, apiSecret, baseUrl = 'https://api.tiqora.dev') {
this.apiKey = apiKey;
this.apiSecret = apiSecret;
this.baseUrl = baseUrl;
}
async request(method, path, body = null) {
const timestamp = Math.floor(Date.now() / 1000).toString();
const bodyString = body ? JSON.stringify(body) : '';
const bodyHash = crypto.createHash('sha256').update(bodyString).digest('hex');
const message = timestamp + method.toUpperCase() + path + bodyHash;
const signature = crypto
.createHmac('sha256', this.apiSecret)
.update(message)
.digest('hex');
const response = await fetch(this.baseUrl + path, {
method: method.toUpperCase(),
headers: {
'Content-Type': 'application/json',
'x-api-key': this.apiKey,
'x-api-signature': signature,
'x-api-timestamp': timestamp,
},
body: body ? bodyString : undefined,
});
if (response.status === 204) return null;
return response.json();
}
// Tickets
async listTickets(params = {}) {
const query = new URLSearchParams(params).toString();
const path = '/api/v1/external/tickets' + (query ? '?' + query : '');
return this.request('GET', path);
}
async createTicket(data) {
return this.request('POST', '/api/v1/external/tickets', data);
}
async getTicket(id) {
return this.request('GET', `/api/v1/external/tickets/${id}`);
}
async updateTicket(id, data) {
return this.request('PATCH', `/api/v1/external/tickets/${id}`, data);
}
// Replies
async listReplies(ticketId, params = {}) {
const query = new URLSearchParams(params).toString();
const path = `/api/v1/external/tickets/${ticketId}/replies` + (query ? '?' + query : '');
return this.request('GET', path);
}
async createReply(ticketId, data) {
return this.request('POST', `/api/v1/external/tickets/${ticketId}/replies`, data);
}
// Customers
async listCustomers(params = {}) {
const query = new URLSearchParams(params).toString();
const path = '/api/v1/external/customers' + (query ? '?' + query : '');
return this.request('GET', path);
}
async createCustomer(data) {
return this.request('POST', '/api/v1/external/customers', data);
}
async getCustomer(id) {
return this.request('GET', `/api/v1/external/customers/${id}`);
}
async updateCustomer(id, data) {
return this.request('PATCH', `/api/v1/external/customers/${id}`, data);
}
// Pagination helper
async fetchAll(method, path) {
const all = [];
let cursor = null;
do {
const params = new URLSearchParams({ per_page: '100' });
if (cursor) params.set('cursor', cursor);
const fullPath = path + (path.includes('?') ? '&' : '?') + params;
const response = await this.request(method, fullPath);
all.push(...response.data);
cursor = response.meta.has_more ? response.meta.next_cursor : null;
} while (cursor);
return all;
}
}
// Usage
const tiqora = new TiqoraClient('tk_live_...', 'your_secret');
// Create a ticket
const ticket = await tiqora.createTicket({
subject: 'Need help with integration',
description: 'Getting 401 errors when calling the API.',
priority: 'high',
customer: { email: 'dev@example.com', name: 'Dev Team' },
});
// List open tickets
const openTickets = await tiqora.listTickets({ status: 'open' });
// Add a reply
await tiqora.createReply(ticket.data.id, {
body: 'We found the issue — your timestamp was in milliseconds instead of seconds.',
});
Python
import hashlib
import hmac
import json
import time
from urllib.parse import urlencode
import requests
class TiqoraClient:
def __init__(self, api_key, api_secret, base_url='https://api.tiqora.dev'):
self.api_key = api_key
self.api_secret = api_secret
self.base_url = base_url
def _sign(self, method, path, body=None):
timestamp = str(int(time.time()))
body_string = json.dumps(body, separators=(',', ':')) if body else ''
body_hash = hashlib.sha256(body_string.encode()).hexdigest()
message = timestamp + method.upper() + path + body_hash
signature = hmac.new(
self.api_secret.encode(),
message.encode(),
hashlib.sha256
).hexdigest()
return timestamp, signature
def request(self, method, path, body=None):
timestamp, signature = self._sign(method, path, body)
headers = {
'Content-Type': 'application/json',
'x-api-key': self.api_key,
'x-api-signature': signature,
'x-api-timestamp': timestamp,
}
response = requests.request(
method,
self.base_url + path,
headers=headers,
json=body,
)
if response.status_code == 204:
return None
return response.json()
# Tickets
def list_tickets(self, **params):
query = urlencode(params) if params else ''
path = '/api/v1/external/tickets' + ('?' + query if query else '')
return self.request('GET', path)
def create_ticket(self, data):
return self.request('POST', '/api/v1/external/tickets', data)
def get_ticket(self, ticket_id):
return self.request('GET', f'/api/v1/external/tickets/{ticket_id}')
def update_ticket(self, ticket_id, data):
return self.request('PATCH', f'/api/v1/external/tickets/{ticket_id}', data)
# Replies
def list_replies(self, ticket_id, **params):
query = urlencode(params) if params else ''
path = f'/api/v1/external/tickets/{ticket_id}/replies' + ('?' + query if query else '')
return self.request('GET', path)
def create_reply(self, ticket_id, data):
return self.request('POST', f'/api/v1/external/tickets/{ticket_id}/replies', data)
# Customers
def list_customers(self, **params):
query = urlencode(params) if params else ''
path = '/api/v1/external/customers' + ('?' + query if query else '')
return self.request('GET', path)
def create_customer(self, data):
return self.request('POST', '/api/v1/external/customers', data)
def get_customer(self, customer_id):
return self.request('GET', f'/api/v1/external/customers/{customer_id}')
def update_customer(self, customer_id, data):
return self.request('PATCH', f'/api/v1/external/customers/{customer_id}', data)
# Pagination helper
def fetch_all(self, path):
all_items = []
cursor = None
while True:
params = {'per_page': 100}
if cursor:
params['cursor'] = cursor
query = urlencode(params)
sep = '&' if '?' in path else '?'
response = self.request('GET', path + sep + query)
all_items.extend(response['data'])
if not response['meta']['has_more']:
break
cursor = response['meta']['next_cursor']
return all_items
# Usage
tiqora = TiqoraClient('tk_live_...', 'your_secret')
# Create a ticket
ticket = tiqora.create_ticket({
'subject': 'Payment issue',
'description': 'Customer cannot complete checkout.',
'priority': 'high',
'customer': {'email': 'user@example.com', 'name': 'User'},
})
# List open tickets
open_tickets = tiqora.list_tickets(status='open')
# Get all customers
all_customers = tiqora.fetch_all('/api/v1/external/customers')
PHP
<?php
class TiqoraClient
{
public function __construct(
private string $apiKey,
private string $apiSecret,
private string $baseUrl = 'https://api.tiqora.dev'
) {}
public function request(string $method, string $path, ?array $body = null): ?array
{
$timestamp = (string) time();
$bodyString = $body ? json_encode($body) : '';
$bodyHash = hash('sha256', $bodyString);
$message = $timestamp . strtoupper($method) . $path . $bodyHash;
$signature = hash_hmac('sha256', $message, $this->apiSecret);
$ch = curl_init($this->baseUrl . $path);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => strtoupper($method),
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
"x-api-key: {$this->apiKey}",
"x-api-signature: {$signature}",
"x-api-timestamp: {$timestamp}",
],
]);
if ($body) {
curl_setopt($ch, CURLOPT_POSTFIELDS, $bodyString);
}
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 204) return null;
return json_decode($response, true);
}
public function listTickets(array $params = []): array
{
$query = http_build_query($params);
return $this->request('GET', '/api/v1/external/tickets' . ($query ? "?{$query}" : ''));
}
public function createTicket(array $data): array
{
return $this->request('POST', '/api/v1/external/tickets', $data);
}
public function getTicket(string $id): array
{
return $this->request('GET', "/api/v1/external/tickets/{$id}");
}
public function updateTicket(string $id, array $data): array
{
return $this->request('PATCH', "/api/v1/external/tickets/{$id}", $data);
}
public function createReply(string $ticketId, array $data): array
{
return $this->request('POST', "/api/v1/external/tickets/{$ticketId}/replies", $data);
}
}
// Usage
$tiqora = new TiqoraClient('tk_live_...', 'your_secret');
$ticket = $tiqora->createTicket([
'subject' => 'Login issue',
'description' => 'User cannot log in after password reset.',
'customer' => ['email' => 'user@example.com'],
]);
cURL Examples
List Tickets
API_KEY="tk_live_your_key"
API_SECRET="your_secret"
TIMESTAMP=$(date +%s)
PATH_URL="/api/v1/external/tickets"
BODY_HASH=$(echo -n "" | openssl dgst -sha256 | awk '{print $NF}')
MESSAGE="${TIMESTAMP}GET${PATH_URL}${BODY_HASH}"
SIGNATURE=$(echo -n "$MESSAGE" | openssl dgst -sha256 -hmac "$API_SECRET" | awk '{print $NF}')
curl -s "https://api.tiqora.dev${PATH_URL}" \
-H "x-api-key: ${API_KEY}" \
-H "x-api-signature: ${SIGNATURE}" \
-H "x-api-timestamp: ${TIMESTAMP}" | jq
Create Ticket
API_KEY="tk_live_your_key"
API_SECRET="your_secret"
TIMESTAMP=$(date +%s)
PATH_URL="/api/v1/external/tickets"
BODY='{"subject":"Test ticket","description":"Created via cURL","customer":{"email":"test@example.com"}}'
BODY_HASH=$(echo -n "$BODY" | openssl dgst -sha256 | awk '{print $NF}')
MESSAGE="${TIMESTAMP}POST${PATH_URL}${BODY_HASH}"
SIGNATURE=$(echo -n "$MESSAGE" | openssl dgst -sha256 -hmac "$API_SECRET" | awk '{print $NF}')
curl -s "https://api.tiqora.dev${PATH_URL}" \
-X POST \
-H "Content-Type: application/json" \
-H "x-api-key: ${API_KEY}" \
-H "x-api-signature: ${SIGNATURE}" \
-H "x-api-timestamp: ${TIMESTAMP}" \
-d "$BODY" | jq
Hint: Pipe the output through
jqfor formatted, colored JSON output. Install it withbrew install jq(macOS) orapt install jq(Linux).