ScanMosaic
API REST · v1

Integra códigos QR y enlaces cortos en tu app

Crea códigos QR dinámicos, enlaces cortos y códigos de barras, cambia su destino, lee sus estadísticas de escaneo y genera imágenes QR listas para imprimir, todo desde tu propio código. JSON sobre HTTPS, una sola clave de API y errores claros.

URL base
https://scanmosaic.com/api/v1
Autenticación
Authorization: Bearer tsk_…
Plan
Business

Inicio rápido

  1. Abre Claves de API en tu panel (plan Business) y crea una clave. Cópiala: solo se muestra una vez.
  2. Guárdala como variable de entorno en tu servidor, p. ej. TESSERA_API_KEY. Nunca la pongas en código de navegador o de app.
  3. Crea un código QR dinámico. La respuesta incluye su enlace corto en url; codifica ese enlace o descarga una imagen lista desde /qr.

cURL

curl "https://scanmosaic.com/api/v1/items" \
  -H "Authorization: Bearer $TESSERA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"kind": "qr", "name": "Table menu", "dest": "https://example.com/menu"}'

JavaScript

const res = await fetch("https://scanmosaic.com/api/v1/items", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.TESSERA_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "kind": "qr",
    "name": "Table menu",
    "dest": "https://example.com/menu"
  })
});
const body = await res.json();
if (!res.ok) throw new Error(body.error.message);
console.log(body.data);

Python

import os, requests

r = requests.post(
    "https://scanmosaic.com/api/v1/items",
    headers={"Authorization": f"Bearer {os.environ['TESSERA_API_KEY']}"},
    json={
    "kind": "qr",
    "name": "Table menu",
    "dest": "https://example.com/menu"
},
)
r.raise_for_status()
print(r.json()["data"])

cURL

curl "https://scanmosaic.com/api/v1/qr?item=k3Xp9Qa&size=1024" \
  -H "Authorization: Bearer $TESSERA_API_KEY" \
  -o menu.png

JavaScript

import { writeFile } from "node:fs/promises";

const res = await fetch("https://scanmosaic.com/api/v1/qr?item=k3Xp9Qa&size=1024", {
  headers: { Authorization: `Bearer ${process.env.TESSERA_API_KEY}` },
});
if (!res.ok) throw new Error((await res.json()).error.message);
await writeFile("menu.png", Buffer.from(await res.arrayBuffer()));

Python

import os, requests

r = requests.get(
    "https://scanmosaic.com/api/v1/qr?item=k3Xp9Qa&size=1024",
    headers={"Authorization": f"Bearer {os.environ['TESSERA_API_KEY']}"},
)
r.raise_for_status()
open("menu.png", "wb").write(r.content)

Autenticación

Envía tu clave en el encabezado Authorization de cada solicitud. Las claves empiezan por tsk_ y pertenecen a un workspace: pueden leer y cambiar todo lo que puede un editor de ese workspace, y nada en otros workspaces.

Authorization: Bearer tsk_AbC123…
  • Los propietarios y administradores crean y eliminan claves en Claves de API, dentro del panel. Al eliminar una clave, deja de funcionar al instante.
  • La API forma parte del plan Business. Si el plan termina, las solicitudes reciben 402 business_required hasta que renueves; tus códigos y datos se conservan.
  • Los cambios hechos con una clave aparecen en el registro de actividad del espacio de trabajo como "API key tsk_…".
  • CORS está abierto para que puedas llamar a la API desde cualquier origen, pero cualquiera que abra una página web puede copiar la clave que contenga. Llama a la API desde tu servidor.

Errores

Todos los errores usan la misma estructura JSON y un estado HTTP coherente. code es estable: constrúyelo sobre él. message es texto en inglés claro para registros y personas. Algunos errores añaden detalles, como param.

{
  "error": {
    "code": "bad_param",
    "message": "One of the parameters isn't valid.",
    "status": 400,
    "param": "size",
    "hint": "64 to 2048"
  }
}
Códigos de error
EstadoCódigoSignificado
400bad_jsonEl cuerpo no es un JSON válido.
400bad_paramUn parámetro de consulta o del cuerpo está fuera de rango. details: param, hint.
400bad_destinationdest no es una dirección web http(s) completa.
400bad_kindkind no es qr, link ni barcode.
400bad_aliasel alias no tiene entre 3 y 40 letras, números o guiones, o está reservado.
400domain_not_verifieddomain no es un dominio verificado de tu espacio de trabajo.
400unsafe_destinationGoogle Web Risk marca el destino como peligroso.
400empty / too_long / bad_formatImágenes QR: sin datos, demasiados datos o un formato distinto de png o svg.
400bad_cursorEse cursor no es uno de los que te dimos.
401api_key_requiredFalta la cabecera Authorization, o no es Bearer tsk_…
401invalid_api_keyLa clave no existe o fue eliminada.
402business_requiredEl workspace no está en el plan Business (por ejemplo, porque terminó).
403limit_reachedHas alcanzado el límite de tu plan para ese tipo de elemento. details: limit, kind.
404not_foundNo existe ese elemento en este espacio de trabajo.
409alias_takenEse alias ya se usa en ese dominio.
413too_bigEl cuerpo es demasiado grande (250 KB para items).
429rate_limited / daily_limitDemasiadas solicitudes. Espera los segundos indicados en Retry-After.
500server_errorAlgo falló por nuestra parte. Reintenta con espera progresiva.

Límites de uso

Cada clave puede hacer 120 solicitudes por minuto y 20,000 al día. Cada respuesta te indica cuánto llevas:

CabeceraSignificado
X-RateLimit-LimitSolicitudes permitidas por minuto.
X-RateLimit-RemainingSolicitudes restantes en el minuto actual.
X-RateLimit-ResetHora Unix en que se reinicia el minuto.
Retry-AfterSolo con 429: segundos que hay que esperar antes de volver a intentarlo.

Crear elementos también está limitado a 300 por hora y espacio de trabajo, y tu plan define cuántos elementos puedes conservar. ¿Necesitas más? Contáctanos.

Paginación

Las listas devuelven primero lo más reciente, hasta limit elementos (25 por defecto, 100 como máximo). Cuando has_more es true, pasa next_cursor como cursor para obtener la página siguiente. Los cursores siguen siendo válidos cuando se añaden elementos.

{
  "data": [
    "\u2026"
  ],
  "has_more": true,
  "next_cursor": "MTc2NzIyNTYwMC5rM1hwOVFh"
}

El objeto item

Los códigos QR, enlaces y códigos de barras son todos elementos. Un elemento individual se devuelve como data; las listas, como data con campos de paginación.

Campos del elemento
NombreTipoDescripción
idstringID corto, también es la terminación por defecto del enlace corto.
kindqr | link | barcodeQué es. No se puede cambiar tras la creación.
typestringTipo de contenido, p. ej. url (por defecto), pdf, menu, vcard para códigos QR; ean13, code128 para códigos de barras.
namestringTu etiqueta, hasta 80 caracteres.
deststring | nullA dónde van los escaneos y clics. null para páginas alojadas y códigos de barras.
urlstringEl enlace corto que codifica el código QR, p. ej. https://go.yourbrand.com/menu.
aliasstring | nullFinal personalizado (3–40 letras, números o guiones), único por dominio.
domainstring | nullTu dominio propio verificado, o null para el nuestro.
campaignstring | nullAgrupa elementos para los informes.
contentobject | nullDatos de la página alojada o datos del código de barras ({ "data": "…" }).
styleobjectDiseño del código QR (colores, estilos de puntos y esquinas).
rulesobject | nullReglas de enrutamiento (por dispositivo, país, hora…).
pausedbooleanLos elementos en pausa muestran una página de «pausado» en lugar de redirigir.
disabledbooleanLo desactivamos por incumplir los términos.
hitsintegerEscaneos totales (códigos QR) o clics (enlaces).
last_hitinteger | nullHora Unix del último escaneo o clic.
created / updatedintegerHoras Unix.

Endpoints

GET /api/v1/me

Cuenta

El workspace al que pertenece esta clave, su plan, límites, uso, dominios verificados y límites de frecuencia. Útil para comprobar que una clave funciona.

cURL

curl "https://scanmosaic.com/api/v1/me" \
  -H "Authorization: Bearer $TESSERA_API_KEY"

JavaScript

const res = await fetch("https://scanmosaic.com/api/v1/me", {
  headers: { Authorization: `Bearer ${process.env.TESSERA_API_KEY}` },
});
const body = await res.json();
if (!res.ok) throw new Error(body.error.message);
console.log(body.data);

Python

import os, requests

r = requests.get(
    "https://scanmosaic.com/api/v1/me",
    headers={"Authorization": f"Bearer {os.environ['TESSERA_API_KEY']}"},
)
r.raise_for_status()
print(r.json()["data"])
Respuesta 200 OK
{
  "data": {
    "workspace": {
      "id": "w_8fK2mQ",
      "name": "Acme"
    },
    "plan": "business",
    "key": {
      "prefix": "tsk_AbC123",
      "name": "Shopify sync"
    },
    "limits": {
      "qr": 1000,
      "link": 5000,
      "barcode": 10000,
      "domains": 5
    },
    "usage": {
      "dynamic": 12,
      "links": 40,
      "barcodes": 3,
      "storageBytes": 0,
      "workspaces": 1
    },
    "domains": [
      "go.yourbrand.com"
    ],
    "rate_limits": {
      "per_minute": 120,
      "per_day": 20000
    }
  }
}

GET /api/v1/items

Listar elementos

Elementos del espacio de trabajo, los más recientes primero.

Parámetros
NombreTipoDescripción
kindqr | link | barcodeSolo este tipo.
typestringSolo este tipo de contenido, p. ej. url o pdf.
campaignstringSolo esta campaña.
domainstringSolo los elementos de este dominio personalizado.
pausedtrue | falseSolo los elementos en pausa, o solo los activos.
qstringBusca por nombre, destino y alias.
limitinteger1–100, por defecto 25.
cursorstringnext_cursor de la página anterior.

cURL

curl "https://scanmosaic.com/api/v1/items?kind=link&campaign=spring&limit=50" \
  -H "Authorization: Bearer $TESSERA_API_KEY"

JavaScript

const res = await fetch("https://scanmosaic.com/api/v1/items?kind=link&campaign=spring&limit=50", {
  headers: { Authorization: `Bearer ${process.env.TESSERA_API_KEY}` },
});
const body = await res.json();
if (!res.ok) throw new Error(body.error.message);
console.log(body.data);

Python

import os, requests

r = requests.get(
    "https://scanmosaic.com/api/v1/items?kind=link&campaign=spring&limit=50",
    headers={"Authorization": f"Bearer {os.environ['TESSERA_API_KEY']}"},
)
r.raise_for_status()
print(r.json()["data"])
Respuesta 200 OK
{
  "data": [
    {
      "id": "k3Xp9Qa",
      "kind": "link",
      "type": "url",
      "name": "Spring menu",
      "dest": "https://example.com/menu",
      "content": null,
      "style": {},
      "rules": null,
      "alias": "menu",
      "domain": "go.yourbrand.com",
      "campaign": "spring",
      "og": null,
      "created": 1767225600,
      "updated": 1767225600,
      "paused": false,
      "disabled": false,
      "hits": 42,
      "last_hit": 1767312000,
      "url": "https://go.yourbrand.com/menu"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

POST /api/v1/items

Crear un elemento

Crea un código QR dinámico, un enlace corto o un código de barras guardado. Cuenta para los límites de tu plan.

Parámetros
NombreTipoDescripción
kindqr | link | barcodePor defecto qr.
dest obligatoriostringDirección http(s) completa a la que redirigir. No se usa en códigos de barras ni páginas alojadas.
namestringHasta 80 caracteres.
typestringPor defecto url (códigos, enlaces) o code128 (códigos de barras).
aliasstringFinal personalizado, p. ej. menu. 3–40 letras, números o guiones, único por dominio.
domainstringUno de tus dominios personalizados verificados (consulta /domains).
campaignstringHasta 60 caracteres.
styleobjectDiseño del QR, p. ej. {"fg": "#112233", "dot": "rounded"}.
contentobjectDatos de la página alojada o del código de barras, p. ej. {"bcid": "ean13", "text": "4006381333931"} para un código de barras.
rulesobjectReglas de enrutamiento.
pausedbooleanEmpieza en pausa.

cURL

curl "https://scanmosaic.com/api/v1/items" \
  -H "Authorization: Bearer $TESSERA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"kind": "link", "name": "Spring menu", "dest": "https://example.com/menu", "alias": "menu", "domain": "go.yourbrand.com", "campaign": "spring"}'

JavaScript

const res = await fetch("https://scanmosaic.com/api/v1/items", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.TESSERA_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "kind": "link",
    "name": "Spring menu",
    "dest": "https://example.com/menu",
    "alias": "menu",
    "domain": "go.yourbrand.com",
    "campaign": "spring"
  })
});
const body = await res.json();
if (!res.ok) throw new Error(body.error.message);
console.log(body.data);

Python

import os, requests

r = requests.post(
    "https://scanmosaic.com/api/v1/items",
    headers={"Authorization": f"Bearer {os.environ['TESSERA_API_KEY']}"},
    json={
    "kind": "link",
    "name": "Spring menu",
    "dest": "https://example.com/menu",
    "alias": "menu",
    "domain": "go.yourbrand.com",
    "campaign": "spring"
},
)
r.raise_for_status()
print(r.json()["data"])
Respuesta 201 Created
{
  "data": {
    "id": "k3Xp9Qa",
    "kind": "link",
    "type": "url",
    "name": "Spring menu",
    "dest": "https://example.com/menu",
    "content": null,
    "style": {},
    "rules": null,
    "alias": "menu",
    "domain": "go.yourbrand.com",
    "campaign": "spring",
    "og": null,
    "created": 1767225600,
    "updated": 1767225600,
    "paused": false,
    "disabled": false,
    "hits": 42,
    "last_hit": 1767312000,
    "url": "https://go.yourbrand.com/menu"
  }
}

GET /api/v1/items/{id}

Obtener un elemento

Un elemento por id.

cURL

curl "https://scanmosaic.com/api/v1/items/k3Xp9Qa" \
  -H "Authorization: Bearer $TESSERA_API_KEY"

JavaScript

const res = await fetch("https://scanmosaic.com/api/v1/items/k3Xp9Qa", {
  headers: { Authorization: `Bearer ${process.env.TESSERA_API_KEY}` },
});
const body = await res.json();
if (!res.ok) throw new Error(body.error.message);
console.log(body.data);

Python

import os, requests

r = requests.get(
    "https://scanmosaic.com/api/v1/items/k3Xp9Qa",
    headers={"Authorization": f"Bearer {os.environ['TESSERA_API_KEY']}"},
)
r.raise_for_status()
print(r.json()["data"])
Respuesta 200 OK
{
  "data": {
    "id": "k3Xp9Qa",
    "kind": "link",
    "type": "url",
    "name": "Spring menu",
    "dest": "https://example.com/menu",
    "content": null,
    "style": {},
    "rules": null,
    "alias": "menu",
    "domain": "go.yourbrand.com",
    "campaign": "spring",
    "og": null,
    "created": 1767225600,
    "updated": 1767225600,
    "paused": false,
    "disabled": false,
    "hits": 42,
    "last_hit": 1767312000,
    "url": "https://go.yourbrand.com/menu"
  }
}

PATCH /api/v1/items/{id}

Actualiza un artículo

Envía solo los campos que quieras cambiar. Cambiar dest surte efecto en el siguiente escaneo; los códigos impresos siguen funcionando. Cambiar domain o alias cambia el enlace corto, así que los códigos ya impresos dejan de funcionar.

Parámetros
NombreTipoDescripción
name, dest, alias, domain, campaign, style, content, rules, pausedIgual que en Create. kind no se puede cambiar. Envía null para borrar alias, domain, campaign o rules.

cURL

curl -X PATCH "https://scanmosaic.com/api/v1/items/k3Xp9Qa" \
  -H "Authorization: Bearer $TESSERA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"dest": "https://example.com/summer-menu", "paused": false}'

JavaScript

const res = await fetch("https://scanmosaic.com/api/v1/items/k3Xp9Qa", {
  method: "PATCH",
  headers: { Authorization: `Bearer ${process.env.TESSERA_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "dest": "https://example.com/summer-menu",
    "paused": false
  })
});
const body = await res.json();
if (!res.ok) throw new Error(body.error.message);
console.log(body.data);

Python

import os, requests

r = requests.patch(
    "https://scanmosaic.com/api/v1/items/k3Xp9Qa",
    headers={"Authorization": f"Bearer {os.environ['TESSERA_API_KEY']}"},
    json={
    "dest": "https://example.com/summer-menu",
    "paused": False
},
)
r.raise_for_status()
print(r.json()["data"])
Respuesta 200 OK
{
  "data": {
    "id": "k3Xp9Qa",
    "kind": "link",
    "type": "url",
    "name": "Spring menu",
    "dest": "https://example.com/summer-menu",
    "content": null,
    "style": {},
    "rules": null,
    "alias": "menu",
    "domain": "go.yourbrand.com",
    "campaign": "spring",
    "og": null,
    "created": 1767225600,
    "updated": 1767225600,
    "paused": false,
    "disabled": false,
    "hits": 42,
    "last_hit": 1767312000,
    "url": "https://go.yourbrand.com/menu"
  }
}

DELETE /api/v1/items/{id}

Eliminar un elemento

Elimina el elemento y su historial de escaneos. Su enlace corto deja de funcionar al instante. No se puede deshacer.

cURL

curl -X DELETE "https://scanmosaic.com/api/v1/items/k3Xp9Qa" \
  -H "Authorization: Bearer $TESSERA_API_KEY"

JavaScript

const res = await fetch("https://scanmosaic.com/api/v1/items/k3Xp9Qa", {
  method: "DELETE",
  headers: { Authorization: `Bearer ${process.env.TESSERA_API_KEY}` },
});
const body = await res.json();
if (!res.ok) throw new Error(body.error.message);
console.log(body.data);

Python

import os, requests

r = requests.delete(
    "https://scanmosaic.com/api/v1/items/k3Xp9Qa",
    headers={"Authorization": f"Bearer {os.environ['TESSERA_API_KEY']}"},
)
r.raise_for_status()
print(r.json()["data"])
Respuesta 200 OK
{
  "data": {
    "id": "k3Xp9Qa",
    "deleted": true
  }
}

GET /api/v1/items/{id}/stats

Estadísticas del elemento

Escaneos o clics en un periodo: una serie diaria y desgloses por país, dispositivo, sistema operativo, navegador, idioma y regla de enrutamiento. Los bots no se cuentan.

Parámetros
NombreTipoDescripción
daysinteger1–365, por defecto 30.

cURL

curl "https://scanmosaic.com/api/v1/items/k3Xp9Qa/stats?days=7" \
  -H "Authorization: Bearer $TESSERA_API_KEY"

JavaScript

const res = await fetch("https://scanmosaic.com/api/v1/items/k3Xp9Qa/stats?days=7", {
  headers: { Authorization: `Bearer ${process.env.TESSERA_API_KEY}` },
});
const body = await res.json();
if (!res.ok) throw new Error(body.error.message);
console.log(body.data);

Python

import os, requests

r = requests.get(
    "https://scanmosaic.com/api/v1/items/k3Xp9Qa/stats?days=7",
    headers={"Authorization": f"Bearer {os.environ['TESSERA_API_KEY']}"},
)
r.raise_for_status()
print(r.json()["data"])
Respuesta 200 OK
{
  "data": {
    "days": 7,
    "total": 42,
    "last_hit": 1767312000,
    "inRange": 12,
    "series": [
      [
        "2026-01-01",
        3
      ],
      [
        "2026-01-02",
        0
      ],
      [
        "…",
        0
      ]
    ],
    "countries": [
      {
        "k": "GB",
        "n": 7
      },
      {
        "k": "US",
        "n": 5
      }
    ],
    "devices": [
      {
        "k": "Mobile",
        "n": 10
      },
      {
        "k": "Desktop",
        "n": 2
      }
    ],
    "os": [
      {
        "k": "iOS",
        "n": 6
      }
    ],
    "browsers": [
      {
        "k": "Safari",
        "n": 6
      }
    ],
    "langs": [
      {
        "k": "en-gb",
        "n": 7
      }
    ],
    "rules": [
      {
        "k": "default",
        "n": 12
      }
    ]
  }
}

GET /api/v1/qr

Imagen del código QR

Genera un código QR como PNG o SVG. Usa GET con parámetros de consulta, o POST con los mismos parámetros en JSON. Pasa item para dibujar un código guardado con su propio diseño y enlace corto, o data para cualquier texto.

Parámetros
NombreTipoDescripción
datastringTexto o enlace a codificar (hasta 2,953 bytes). Obligatorio salvo que se indique item.
itemstringID de un código QR o enlace guardado: codifica su enlace corto con su diseño guardado.
formatpng | svgPor defecto png.
sizeintegerPíxeles: 64–2048 para PNG (512 por defecto), 64–4096 para SVG (1024 por defecto).
color#RRGGBBPuntos. Predeterminado #141A2E.
background#RRGGBBPor defecto #FFFFFF.
transparentbooleanFondo transparente.
corner_color#RRGGBBCuadrados de esquina. Por defecto: color.
gradient_color#RRGGBBSolo SVG: segundo color de un degradado diagonal.
error_correctionL | M | Q | HCuánto daño soporta el código: 7 %, 15 %, 25 %, 30 %. Por defecto M (PNG) o Q (SVG).
marginintegerZona de silencio en módulos, 0–8. Por defecto 4.
dot_stylestringsquare, dots, rounded, extra-rounded, classy, classy-rounded
corner_stylestringsquare, extra-rounded, dot
corner_dot_stylestringsquare, dot
downloadstringNombre de archivo: añade Content-Disposition: attachment.

Los PNG se dibujan en nuestros servidores con píxeles enteros por módulo, así que los bordes se mantienen nítidos para imprimir. Los degradados y logos son solo para SVG; para logos, usa el generador.

cURL

curl "https://scanmosaic.com/api/v1/qr" \
  -H "Authorization: Bearer $TESSERA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"data": "https://example.com", "format": "png", "size": 1024, "color": "#4865F0", "dot_style": "rounded", "corner_style": "extra-rounded"}' \
  -o qr.png

JavaScript

import { writeFile } from "node:fs/promises";

const res = await fetch("https://scanmosaic.com/api/v1/qr", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.TESSERA_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "data": "https://example.com",
    "format": "png",
    "size": 1024,
    "color": "#4865F0",
    "dot_style": "rounded",
    "corner_style": "extra-rounded"
  })
});
if (!res.ok) throw new Error((await res.json()).error.message);
await writeFile("qr.png", Buffer.from(await res.arrayBuffer()));

Python

import os, requests

r = requests.post(
    "https://scanmosaic.com/api/v1/qr",
    headers={"Authorization": f"Bearer {os.environ['TESSERA_API_KEY']}"},
    json={
    "data": "https://example.com",
    "format": "png",
    "size": 1024,
    "color": "#4865F0",
    "dot_style": "rounded",
    "corner_style": "extra-rounded"
},
)
r.raise_for_status()
open("qr.png", "wb").write(r.content)

GET /api/v1/domains

Dominios

Los dominios personalizados del workspace. Usa como dominio un host cuyo ready sea true cuando crees items.

cURL

curl "https://scanmosaic.com/api/v1/domains" \
  -H "Authorization: Bearer $TESSERA_API_KEY"

JavaScript

const res = await fetch("https://scanmosaic.com/api/v1/domains", {
  headers: { Authorization: `Bearer ${process.env.TESSERA_API_KEY}` },
});
const body = await res.json();
if (!res.ok) throw new Error(body.error.message);
console.log(body.data);

Python

import os, requests

r = requests.get(
    "https://scanmosaic.com/api/v1/domains",
    headers={"Authorization": f"Bearer {os.environ['TESSERA_API_KEY']}"},
)
r.raise_for_status()
print(r.json()["data"])
Respuesta 200 OK
{
  "data": [
    {
      "host": "go.yourbrand.com",
      "verified": true,
      "ready": true
    }
  ]
}

Dominios personalizados

Con el plan Business tus enlaces cortos pueden usar tu propio dominio, como go.yourbrand.com/menu. Añade y verifica el dominio en Dominios, dentro del panel: añades un registro CNAME que apunta a nosotros y un registro TXT que demuestra que es tuyo, y nosotros emitimos el certificado SSL. Después indica domain al crear o actualizar un elemento.

Cada dominio puede redirigir su dirección raíz (go.yourbrand.com) y las rutas desconocidas a las páginas que elijas.

OpenAPI

La API completa está descrita en openapi.json (OpenAPI 3.1). Impórtala en Postman, Insomnia o un generador de clientes.

Versiones

v1 es estable. Podemos añadir endpoints, campos y códigos de error, así que ignora los campos que no conozcas. No quitaremos ni renombraremos nada en v1; los cambios que rompan compatibilidad llegarían como v2, anunciada con mucha antelación.