Quotes

The transactional heart of Cord. Create proposals, get their public links, and manage them.

Overview

The Quote (cotizacion) object represents a commercial proposal to a client. Using the Cord API, you can inject quotes directly from an ERP, CRM, or generate automated shopping cart workflows.

All quotes generated via API are recorded in the audit log (audit_log), automatically tagged as originating from your API Key.

Creating a Quote

To create a draft quote, you must perform a POST /api/v1/cotizaciones sending the commercial details.

Request:

curl -X POST "https://cordhq.app/api/v1/cotizaciones" \
     -H "Authorization: Bearer sk_live_tU..." \
     -H "Content-Type: application/json" \
     -d '{
       "cliente_id": "cus_9x8f7",
       "terminos": "net30",
       "vigencia_dias": 15,
       "notas": "Annual project",
       "base_currency": "EUR",
       "items": [
         {
           "descripcion": "Annual license — Pro plan",
           "cantidad": 12,
           "precio_unitario": 500
         }
       ]
     }'

Every line in items requires descripcion, cantidad, and precio_unitario — field names stay in Spanish regardless of the request’s language, since they are the API’s canonical schema. producto_id is optional (it references a product from your catalog to inherit its name and list price), and precio_negociado lets you capture a discounted price different from the list price. There is no sku field: to link a line to a product, use its producto_id.

base_currency is the currency the client sees and pays the quote in (ISO 4217, e.g. MXN, USD, EUR, GBP). It’s optional — omit it and Cord falls back to your organization’s accounting currency — but the API is country-agnostic: an account in Madrid, Austin, or Bogotá quotes in its own currency with no extra parameter.

Successful Response:

Cord returns not only the internal database ID, but also the pre-built, already-absolute Public Token (link_publico) so you can immediately send it to your client via WhatsApp, SMS, or an external email engine.

{
  "data": {
    "id": "qte_2a9d8",
    "folio": "COT-00104",
    "token": "tok_x8Yj9Z...",
    "link_publico": "https://cordhq.app/q/tok_x8Yj9Z...",
    "needs_approval": false
  }
}

If the quote requires internal approval before it can be sent (for example, a discount outside the allowed threshold), needs_approval comes back true and motivo describes the reason.

Listing Quotes

You can retrieve your paginated quote history or filter by status (for example, finding all sent or paid quotes).

Request:

curl -X GET "https://cordhq.app/api/v1/cotizaciones?status=paid&limit=10" \
     -H "Authorization: Bearer sk_live_tU..."

The status value is the internal state as-is (English, never translated): draft, sent, viewed, approved, rejected, expired, paid, or invoiced. To find a quote by its number, use folio=COT-00104: it matches the full number, case-insensitive.

{
  "data": [
    {
      "id": "qte_2a9d8",
      "folio": "COT-00104",
      "cliente": "Stark Industries",
      "status": "paid",
      "total": 6000,
      "terminos": "net30",
      "vigencia": "2026-09-10",
      "creada": "2026-08-20T14:32:00.000Z",
      "link_publico": "/q/tok_x8Yj9Z..."
    }
  ],
  "meta": { "limit": 10, "offset": 0, "total": 1 }
}

Note: in the list, link_publico is a relative path (/q/<token>); the creation response returns it absolute. For the detail of a single quote (line items, event timeline, approval), use GET /api/v1/cotizaciones/{id}.

Changing a quote status

With a write key (write) you can move a quote through its lifecycle with POST /api/v1/cotizaciones/{id}:

curl -X POST "https://cordhq.app/api/v1/cotizaciones/qte_2a9d8" \
     -H "Authorization: Bearer sk_live_tU..." \
     -H "Content-Type: application/json" \
     -H "Idempotency-Key: approve-COT-00104" \
     -d '{ "action": "approve" }'
action From status Result
send draft Sends the quote to the client (email and link). On the Free plan it uses one of the monthly sends.
resend sent, viewed, expired Sends it to the client again.
approve sent, viewed Marks it as approved.
reject sent, viewed Marks it as rejected.
mark_paid approved, invoiced Records the payment. Accepts an optional payment_method (defaults to transferencia). Pending online payments for that quote are canceled.

The response is { "data": { "ok": true, "status": "approved" } }. If the quote is not in a status the action can apply to, or another request changed it at the same time, you get 409 with code: "invalid_state" and nothing is applied. Every change is recorded in the audit log with your key as the actor and fires its webhook event.

Issuing the invoice is not available on this route: invoices are created and issued with POST /api/v1/facturas and POST /api/v1/facturas/{id}.

Deleting a draft

DELETE /api/v1/cotizaciones/{id} deletes a quote that was never sent (draft). Any other status returns 409.