API reference

Developer docs

Mint codes programmatically, embed the form, hook Stripe + WooCommerce events.

Introduction

The API lets a reseller's backend (WooCommerce, custom store, CRM) mint access codes from the reseller's own quota. There are two endpoints:

  • GET https://getcid.livezentech.com/api/reseller/quota — read remaining balance
  • POST https://getcid.livezentech.com/api/reseller/mint — atomically mint N codes

All requests return JSON. All endpoints expect Bearer token auth in the Authorization header (or X-Api-Token). Base URL: https://getcid.livezentech.com

Authentication

Resellers create their own tokens at /account/api-tokens. Each token is scoped to your account and carries:

  • A name (for your reference)
  • An optional IP allow-list (recommended for stable store IPs)
  • A rate limit (req/hour, default 1000, max 10000)

The plaintext value is shown once at creation — copy it to a secure secret store immediately. To rotate, create a new token and revoke the old one.

Authorization: Bearer 1a2b3c4d5e6f...

Treat the plaintext token like a password

Anyone with your token can mint codes from your quota. Never commit tokens to source control — store them in a secrets manager, env var, or WordPress option.

GET/api/reseller/quota

Returns the reseller's remaining code allowance. Cheap, idempotent, can be polled freely.

curl https://getcid.livezentech.com/api/reseller/quota \
  -H "Authorization: Bearer YOUR_RESELLER_TOKEN"

200 OK

{
  "ok": true,
  "granted": 50,
  "used": 3,
  "remaining": 47,
  "reseller": { "email": "[email protected]", "name": "Acme Inc." }
}

POST/api/reseller/mint

Atomically draws quantity codes from the reseller's quota and returns them. If the quota was changed by a concurrent request between read and write, the call returns 409 race_lost — retry once. Codes are not emailed unless send_email = true AND customer_email is set.

Always pass a reference

Set reference to your internal order ID (e.g. wc_order_4821). We store it on the audit log so refunds and disputes can be traced back to the originating order with one query.

Request body

Field Type Required Notes
quantity int yes 1 to 100 per call
customer_email string no If set + send_email, codes are emailed to this address
reference string no Your internal order/job id; echoed back in response + stored in our audit log
send_email bool no Default true. Set false to suppress notification (you'll email yourself)
curl -X POST https://getcid.livezentech.com/api/reseller/mint \
  -H "Authorization: Bearer YOUR_RESELLER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "quantity": 1,
    "customer_email": "[email protected]",
    "reference": "wc_order_12345",
    "send_email": true
  }'

200 OK

{
  "ok": true,
  "codes": ["AB12CD34EF"],
  "code_ids": [4821],
  "purchase_id": 1043,
  "remaining_quota": 47,
  "reference": "wc_order_12345",
  "reseller_email": "[email protected]"
}

409 Conflict (quota exhausted)

{
  "ok": false,
  "code": "insufficient_quota",
  "error": "Quota has 3 code(s) left, asked for 10.",
  "remaining": 3
}

Error codes

Errors carry code (machine-readable) and error (human-readable). The HTTP status alone is enough for retry logic.

HTTP code When
400Bad request (missing/invalid quantity or email)
401missing_tokenNo Authorization header
401invalid_tokenToken doesn't match any row
401token_revokedToken's status is revoked
401token_expiredPast the expires_at timestamp
403ip_not_allowedCaller IP isn't on the token's allow-list
403scope_mismatchToken is scoped admin but reseller endpoint requires reseller (or vice-versa)
403owner_not_resellerToken owner's account role is not reseller
403owner_disabledAdmin disabled the owner account
409quota_emptyNo codes left at all
409insufficient_quotaAsked for more than remaining
409race_lostConcurrent request beat you to the quota; retry once
429Rate limit exceeded; see X-RateLimit-* headers
500Server error — codes are not issued; quota is rolled back

Rate limiting

Per-token hourly limit (default 1000/hr, configurable up to 10000). Response headers:

X-RateLimit-Limit:     1000
X-RateLimit-Remaining: 982
X-RateLimit-Reset:     1748232000

The reset is a Unix timestamp (start of the next window). On overflow you get 429 with no body; back off until reset.

Iframe embed

Drop the GetCID form into any page on any origin. The iframe content runs on our domain so CSRF + access codes work normally.

Query param Values Effect
theme auto, light, dark Force a colour scheme. Default auto (matches user's OS).
accent indigo, blue, emerald, rose, amber Primary palette swap (reserved — may not visibly differ today).
code 10-char string Pre-fill the access code field. Skip the customer-paste step.
<iframe
    src="https://getcid.livezentech.com/embed/getcid?theme=auto"
    style="width:100%; min-height:520px; border:0; display:block"
    loading="lazy"
    referrerpolicy="strict-origin-when-cross-origin"
    title="Generate Microsoft Confirmation ID"></iframe>

<script>
window.addEventListener('message', function (e) {
    if (e && e.data && e.data.type === 'getcid:resize' && typeof e.data.height === 'number') {
        document.querySelectorAll('iframe[src*="embed/getcid"]').forEach(function (f) {
            f.style.height = (e.data.height + 20) + 'px';
        });
    }
});
</script>

The iframe page posts a postMessage with {type: "getcid:resize", height: N} after the result expands. The snippet above includes a listener that resizes the iframe to fit.

WooCommerce hook

The fastest path: hook woocommerce_order_status_completed, mint codes via the API, attach them to the order. Copy-paste-ready PHP lives on your integrations page with your own endpoint URL baked in. Key steps:

  1. Create a reseller token at /account/api-tokens and copy the plaintext.
  2. Store it as a WP option, env var, or constant — never in committed code.
  3. Drop the hook into your theme's functions.php or a tiny mu-plugin.
  4. Send reference: 'wc_order_' . $order_id so refunds/disputes can be traced back to the order.

Stripe webhooks

GetCID handles its own Stripe webhook at https://getcid.livezentech.com/stripe/webhook — you don't need to point Stripe at your own URL to make purchases work. The webhook idempotently mints codes for paid intents (the success-redirect handler also covers this path; whichever fires first wins).

If you also need to react to payment events in your own backend (sync customer records, fire your own emails), use a standalone Stripe webhook — just verify the signature:

<?php
// Verify Stripe webhook signature before trusting the event.
$payload   = file_get_contents('php://input');
$sigHeader = $_SERVER['HTTP_STRIPE_SIGNATURE'] ?? '';
$secret    = 'whsec_...'; // from /admin/settings → Stripe → Webhook signing secret

try {
    $event = \Stripe\Webhook::constructEvent($payload, $sigHeader, $secret);
} catch (\Throwable $e) {
    http_response_code(400);
    exit;
}

if ($event->type === 'payment_intent.succeeded') {
    // Codes already minted by GetCID; this is just a sync hook for your own DB.
}

Code samples

PHP (vanilla cURL)

<?php
$ch = curl_init('https://getcid.livezentech.com/api/reseller/mint');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . getenv('GETCID_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        'quantity'       => 1,
        'customer_email' => '[email protected]',
        'reference'      => 'order_42',
        'send_email'     => true,
    ]),
    CURLOPT_TIMEOUT        => 15,
]);
$response = curl_exec($ch);
$status   = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

$data = json_decode($response, true);
if ($status !== 200 || empty($data['ok'])) {
    throw new RuntimeException('Mint failed: ' . ($data['error'] ?? 'HTTP ' . $status));
}
echo 'Issued code: ' . $data['codes'][0];

Node.js (ES modules)

import fetch from 'node-fetch';

const resp = await fetch('https://getcid.livezentech.com/api/reseller/mint', {
    method: 'POST',
    headers: {
        Authorization: `Bearer ${process.env.GETCID_TOKEN}`,
        'Content-Type': 'application/json',
    },
    body: JSON.stringify({
        quantity: 1,
        customer_email: '[email protected]',
        reference: 'order_42',
        send_email: true,
    }),
});
const data = await resp.json();
if (!resp.ok || !data.ok) throw new Error(data.error || 'Mint failed');
console.log('Issued code:', data.codes[0]);