Docs SDK & Code Examples

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 jq for formatted, colored JSON output. Install it with brew install jq (macOS) or apt install jq (Linux).