Designs
Cord Studio designs as code: keep them in your repository, check them before you upload them and choose which one each quote goes out with.
Overview
A Cord Studio design decides how your client sees the quote link: the order of the blocks, their content, their style and what it changes from your business’s theme. Through the API it’s the same JSON document the visual editor shows in its Code tab, and Cord validates it with the same rules: the blocks your client needs before approving, the 4.5 to 1 contrast and the media from your business’s library.
With the API you can keep your designs in your repository, check them in your CI and upload them to your account. The full operations, with every field, are in the API reference.
| Field | What it is |
|---|---|
object |
Always "diseno". |
id |
The design’s UUID. |
nombre |
1 to 80 characters. |
descripcion |
Internal description, up to 280 characters; null without one. Your client doesn’t see it. |
predeterminado |
true if it’s the design used by quotes that don’t choose another. Only one is the default at a time. |
actualizado |
Last edit, ISO 8601. |
diseno |
The document: esquema (1 today), temaOverrides (what the design changes from your business’s theme) and paginas, each with its bloques (id, tipo, props and estilo). It only comes in the detail and in the create and edit responses. |
List and retrieve
GET /api/v1/disenos returns your unarchived designs, without their document: the default first, then from the most recently edited to the oldest. It isn’t paginated, because an account has up to 100.
curl "https://cordhq.app/api/v1/disenos" \
-H "Authorization: Bearer sk_live_tU..."
{
"data": [
{ "object": "diseno", "id": "5b2e8c41-7d3a-4f19-9e6b-0c4a2d8f1b73", "nombre": "Construction proposal", "descripcion": "With a cover, timeline and guarantee", "predeterminado": true, "actualizado": "2026-11-10T16:42:08.000Z" },
{ "object": "diseno", "id": "c8d1f6a2-3e4b-4a7c-8f05-6b9e2d1c7a40", "nombre": "Monthly maintenance", "descripcion": null, "predeterminado": false, "actualizado": "2026-11-08T19:05:31.000Z" }
]
}
GET /api/v1/disenos/{id} returns one design with its document in diseno. The id of a design that doesn’t exist or is archived responds 404 not_found.
Create a design
POST /api/v1/disenos accepts nombre, descripcion and one of these two sources, never both:
diseno: a full document, for example one you downloaded withGET /api/v1/disenos/{id}or copied from the Code tab.plantilla: one of the eighteen templates in the gallery:agencia,arquitectura,eventos,consultoria,software,fotografia,industrial,salud,educacion,inmobiliaria,minimal,editorial,noche,brutalista,tropical,gala,poporescenario. Its texts come in your account’s language and with your business’s country conventions, and withoutnombrethe design takes the template’s name.gala,popandescenariocustomize Cord blocks: without the Professional plan they return 402subscription_required.
With neither, the design starts as the Cord card, the usual design, and is named "Diseño nuevo". A new design isn’t the default: to use it, mark it as explained in the next section.
curl -X POST "https://cordhq.app/api/v1/disenos" \
-H "Authorization: Bearer sk_live_tU..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: design-construction-2027" \
-d '{ "plantilla": "arquitectura", "nombre": "Construction proposal 2027" }'
It responds with the created design, including its document. With a diseno that doesn’t pass validation it responds 400 invalid_request with issues (see Validate without saving), and if your account already has 100 unarchived designs, 409 disenos_tope.
Edit and set the default
PATCH /api/v1/disenos/{id} changes what you send and keeps the rest:
| Field | Effect |
|---|---|
nombre, descripcion |
Replace the stored ones; descripcion: null removes it. |
diseno |
Replaces the whole document. Cord validates it the same way as on creation. |
predeterminado |
true uses it on quotes sent from now on, and the previous one stops being the default. false on the default stops using it: your quotes go out with the Cord card again. |
curl -X PATCH "https://cordhq.app/api/v1/disenos/5b2e8c41-7d3a-4f19-9e6b-0c4a2d8f1b73" \
-H "Authorization: Bearer sk_live_tU..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: default-construction-2027" \
-d '{ "predeterminado": true }'
It responds with the updated design. Editing a design or changing the default doesn’t touch what your clients already received: each quote freezes its design when it’s sent.
Validate without saving
POST /api/v1/disenos/validar takes { "diseno": { … } } and checks it the way the editor does, without saving anything. Use it in your CI before uploading a design; a key with read access on disenos is enough.
curl -X POST "https://cordhq.app/api/v1/disenos/validar" \
-H "Authorization: Bearer sk_test_tU..." \
-H "Content-Type: application/json" \
-d @disenos/construction-proposal.json
If the design can be saved, it responds 200 with object: "diseno_validacion", valido: true, avisos (what doesn’t block saving but is worth reviewing, such as a variable that doesn’t exist or text that’s hard to read), diseno (the document as Cord would save it, with the defaults it fills in) and personaliza_bloques_cord, which tells you whether saving it this way needs the Professional plan.
If not, it responds 400 invalid_request. issues lists each problem with its path in path (dot-separated), what’s wrong in message and a stable code in codigo, such as esquema, falta_bloque, orden_aprobacion, contraste, superficie_no_solida or medio_desconocido. field is the path of the first one:
{
"error": "diseno.paginas: Falta un bloque que el cliente necesita ver antes de aprobar.",
"code": "invalid_request",
"field": "diseno.paginas",
"issues": [
{ "path": "diseno.paginas", "message": "Falta un bloque que el cliente necesita ver antes de aprobar.", "codigo": "falta_bloque" },
{ "path": "diseno.paginas.0.bloques.4.props.medio", "message": "Este medio no está en la biblioteca del negocio.", "codigo": "medio_desconocido" }
]
}
The message texts come in Spanish. A design takes up to 60 blocks and 64 KB, and only uses images and videos from your business’s media library, which you upload in the editor’s Media tab; in the test environment, also those of your real account. Create and edit return the same 400 response when the design doesn’t pass.
Archive
DELETE /api/v1/disenos/{id} archives the design and responds { "data": { "id": "…", "archivado": true } }. It no longer shows up in the list or counts toward the limit of 100. Quotes already sent with it don’t change, and a draft that had it chosen goes out with the default.
curl -X DELETE "https://cordhq.app/api/v1/disenos/c8d1f6a2-3e4b-4a7c-8f05-6b9e2d1c7a40" \
-H "Authorization: Bearer sk_live_tU..." \
-H "Idempotency-Key: archive-monthly-maintenance"
The default can’t be archived: it responds 409 no_archivable. Make another design the default, or remove the mark with predeterminado: false, and try again.
Choose the design of a quote
POST /api/v1/cotizaciones and PATCH /api/v1/cotizaciones/{id} accept diseno_id: the id of one of your designs, or null for the quote to go out with the default. It only changes a draft: a sent quote keeps the design it went out with. With a publishable key, Cord ignores diseno_id.
curl -X PATCH "https://cordhq.app/api/v1/cotizaciones/2a9d8e4f-6b1c-4d7a-9e3f-5c8b1a2d4e6f" \
-H "Authorization: Bearer sk_live_tU..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: design-quote-2a9d8e4f" \
-d '{ "diseno_id": "c8d1f6a2-3e4b-4a7c-8f05-6b9e2d1c7a40" }'
The quote’s detail carries diseno_id, the chosen design (null if it goes out with the default), and diseno_propio, true if someone designed this quote on its own in the editor; that design takes precedence over diseno_id. When it’s sent, Cord takes its own design, the chosen one, the default or the Cord card, in that order, and freezes it. More in Quotes API and Design a single quote.
From your page, Cord Elements’ <CordBuilder disenoId> creates the quote with a design: a publishable key or the Elements proxy accept it too, under the same plan rule. The embedded quote shows the theme the quote went out with and only its Cord blocks (Appearance).
Plans
The routes on this page work on every plan, except for two things that are part of the Professional plan (and of Scale and Developer):
- Customizing Cord blocks: their texts, how they look and their surface, in
propsandestilo.superficieof a Cord block. Creating or editing a design that adds a customization responds402 subscription_required; whatever was already saved is kept. The validation’spersonaliza_bloques_cordtells you before you upload it. - Choosing a quote’s design with
diseno_id, which responds402 subscription_requiredwithout the plan.nullis always accepted.
The 402 response carries plan (your current one) and plan_required. Without the plan, what you saved is kept but not applied: your quotes go out with the default design and Cord blocks look as usual.
From the CLI
Since version 2.3.0, the Cord CLI downloads and uploads your designs as JSON files. Because the CLI only uses test keys, cord disenos works on your test environment, which is created with a copy of your real account’s unarchived designs. Resetting it copies them again with new ids, so run pull again after a reset; a test environment that already existed gets the copy the next time you reset it.
cord disenos pull --dir disenos
cord disenos validar disenos
cord disenos push disenos/construction-proposal.json
pullwrites one file per design to./disenos, or to the--dirfolder. If a file with the sameidis already there, it rewrites it.validarchecks one file or every.jsonin a folder, likePOST /api/v1/disenos/validar, without saving anything.pushupdates the designs whose file has anid, creates the rest and writes the newidinto the file. It sendsnombre,descripcionanddiseno; it doesn’t change which design is the default.pushandvalidarlist each problem with its path and code, move on to the next file and end with exit code1.- With
--json, each command prints{"type":"disenos_pull",…},{"type":"disenos_push",…}or{"type":"disenos_validar",…}with each file’s result.
Each file has id, nombre, descripcion, predeterminado and diseno. Shortened here, because when you download it Cord fills in each block’s props and estilo with their defaults:
{
"id": "5b2e8c41-7d3a-4f19-9e6b-0c4a2d8f1b73",
"nombre": "Construction proposal",
"descripcion": "With a cover and the Cord blocks",
"predeterminado": true,
"diseno": {
"esquema": 1,
"temaOverrides": {},
"paginas": [
{
"id": "principal",
"bloques": [
{ "id": "portada", "tipo": "portada", "props": { "titulo": "Proposal for {cliente.empresa}" } },
{ "id": "encabezado", "tipo": "encabezado" },
{ "id": "metadatos", "tipo": "meta" },
{ "id": "totalcord", "tipo": "total" },
{ "id": "partidas", "tipo": "partidas" },
{ "id": "planpagos", "tipo": "plan_pagos" },
{ "id": "notascord", "tipo": "notas" },
{ "id": "legalcord", "tipo": "legal" },
{ "id": "aprobacion", "tipo": "aprobacion" },
{ "id": "conversacion", "tipo": "conversacion" },
{ "id": "contacto", "tipo": "contacto" },
{ "id": "piecord", "tipo": "pie" }
]
}
]
}
}
Bring a design to your real account
The CLI doesn’t upload anything to your real account. For that, send the same file to POST /api/v1/disenos with a live secret key, from your server or your CI. Cord ignores the file’s id and predeterminado and responds with the new design and its id in your real account:
curl -X POST "https://cordhq.app/api/v1/disenos" \
-H "Authorization: Bearer sk_live_tU..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: upload-construction-proposal" \
-d @disenos/construction-proposal.json
Your test environment uses your real account’s media library, read-only: a design that only uses images and videos from your real account uploads to it unchanged. The ones you upload in the test environment belong only to it, and a design that uses them responds medio_desconocido in your real account: upload them to your real account’s library and change their ids, or remove them, before uploading the design. To use it on your quotes, then mark it with PATCH and predeterminado: true.
From the SDKs
The server SDKs have the designs resource, with the same fields as the API:
| SDK | Methods |
|---|---|
Node (@flouviahq/node, from 1.4.0) |
cord.designs.list, create, retrieve, update, validate and del |
Python (cord-sdk, from 1.2.0) |
cord.designs.list, create, retrieve, update, validate and delete, also on AsyncCord |
PHP (flouviahq/cord, from 1.2.0) |
$cord->designs->list, create, retrieve, update, validate and delete |
validate takes the document and responds like POST /api/v1/disenos/validar: an invalid design comes back as an invalid_request error with its issues. See Node SDK.
From the MCP
The Cord MCP server has two design tools. They don’t create or edit designs: that’s done in the editor, the API or the CLI.
| Tool | What it does | Group and resource |
|---|---|---|
listar_disenos |
Lists your designs in items (id, nombre, descripcion and predeterminado), and elegir_por_cotizacion says whether your plan lets you choose one per quote. |
Read, disenos |
aplicar_diseno |
Chooses which design a draft quote goes out with: it takes cotizacion_id and diseno_id (or null for the default). It sends nothing to the client. |
Draft writing, cotizaciones |
Permissions and errors
A restricted key needs the disenos resource: Read to list, retrieve and validate, and Write to create, edit and archive. Choosing a quote’s design needs write access on cotizaciones. The cord login key already includes disenos.
| Code | Status | When |
|---|---|---|
insufficient_permissions |
403 | The restricted key has no permission on disenos. |
invalid_request |
400 | A field isn’t valid, you sent diseno and plantilla together, or the design doesn’t pass validation. |
subscription_required |
402 | The design customizes Cord blocks, or diseno_id chooses a design, without the Professional plan. |
not_found |
404 | The design doesn’t exist or is archived, or diseno_id isn’t one of your designs. |
disenos_tope |
409 | Your account already has 100 unarchived designs. |
no_archivable |
409 | You tried to archive the default design. |
rate_limited |
429 | Your organization already made 30 design changes in the last minute (when creating or archiving) or 120 (when editing). |