⌘K

Cord publishes an official Node.js/TypeScript SDK inside the same package used by the frontend: @flouviahq/elements. Its /server entry point exposes a typed REST client (CordAPI) and the webhook signature verifier — you don’t need a separate package for your backend.

Installation

npm install @flouviahq/elements

The CordAPI client

import { CordAPI, CordError } from '@flouviahq/elements/server';

const cord = new CordAPI(process.env.CORD_SECRET_KEY); // sk_live_... or sk_test_...

try {
  const quote = await cord.quotes.create({
    cliente_id: 'customer-id',      // optional
    terminos: 'net30',
    vigencia_dias: 15,
    send: true,                     // emails the link to the customer
    items: [
      { descripcion: 'Development hours', cantidad: 10, precio_unitario: 1500 }
    ],
  });
  console.log(quote.folio, quote.link_publico); // e.g. COT-0149  https://cordhq.app/q/abc123
} catch (err) {
  if (err instanceof CordError) {
    // err.code: 'invalid_request' | 'missing_key' | 'invalid_key' | 'insufficient_scope'
    //         | 'rate_limited' | 'network_error' | 'server_error' | 'unknown' | ...
    console.error(err.status, err.code, err.message);
  }
}

cord.quotes, cord.clients, and cord.products expose create()/list() over /cotizaciones, /clientes, and /productos respectively; link_publico in the response is already absolute (no need to prefix the domain).

Verifying webhooks with the same client

The SDK ships a ready-to-use signature verifier (see Verifying webhook signatures for how the mechanism works):

// Example with a Next.js Route Handler
export async function POST(req: Request) {
  const body = await req.text();
  try {
    const event = cord.webhooks.constructEvent(body, req.headers, process.env.CORD_WEBHOOK_SECRET!);
    if (event.event === 'quote.paid') { /* ... */ }
    return new Response('ok');
  } catch {
    return new Response('Invalid signature', { status: 400 });
  }
}

Without the SDK

Cord’s API is standard REST, so you can also call it directly with fetch (built into Node 18+) without installing anything:

const BASE = 'https://cordhq.app/api/v1';

async function cord(path: string, init: RequestInit = {}) {
  const res = await fetch(`${BASE}${path}`, {
    ...init,
    headers: {
      'Authorization': `Bearer ${process.env.CORD_SECRET_KEY}`,
      'Content-Type': 'application/json',
      ...init.headers,
    },
  });
  const body = await res.json();
  if (!res.ok) throw new Error(body.error ?? `Cord API ${res.status}`);
  return body;
}

Remember:

  • Amounts are in pesos (1500 = $1,500.00), not cents.
  • Creating quotes, clients, or products requires a key with write scope.

START TODAY

¿Necesitas más ayuda?

Contacta a nuestro equipo especializado.

No credit card required · Free plan forever