Referencia de la API

Cada endpoint de la API de SpaceKru v1 (15 operaciones) con parámetros, respuestas, errores y ejemplos en curl, Node.js y Python, seguido de los objetos y los 16 eventos de webhook. Generada a partir del documento OpenAPI 3.1.

La API de SpaceKru (v1.1) es una API REST/JSON disponible en todos los planes de pago de SpaceKru. Sincroniza leads en ambos sentidos (upsert por external_id), añade leads a campañas, crea y mueve deals y pide seguimientos a los Empleados de IA, gestiona productos, cotizaciones, órdenes, pagos y reservas, permite que tu plataforma converse con tu Empleado de IA de Customer Service y envía webhooks firmados para 16 eventos que dicen quién causó cada cambio. URL base: https://app.spacekru.com/api/public/v1. Autenticación: llave de API Bearer (sk_live_…). Documentación: https://www.spacekru.com/es/developers. OpenAPI 3.1: https://app.spacekru.com/api/public/v1/openapi.json.

Read in English

URL base y autenticación

https://app.spacekru.com/api/public/v1
Authorization: Bearer $SPACEKRU_API_KEY

Todas las solicitudes y respuestas son JSON (UTF-8). Las fechas son ISO 8601 en UTC. Las escrituras necesitan Content-Type: application/json. Mira Autenticación, Errores y Límites de uso. Las descripciones técnicas de cada campo vienen del documento OpenAPI y están en inglés.

Cuenta

Test a key.

Prueba la conexión

GET /ping · Scope: read

Returns the organization the key belongs to, its plan and the key's scopes. Use it to test a new key.

Scope: read.

ParámetroEnTipoDescripción
Accept-LanguageheaderstringLanguage of error.message: en or es. Without it, the language of the profile of the person who created the key. Codes and field names never change.

Respuestas

  • 200 — Authenticated. Devuelve Ping.
  • 401 — INVALID_API_KEY — the key is missing, malformed, unknown or revoked.
  • 402 — PLAN_UPGRADE_REQUIRED — the organization is not on an active paid plan (free plan, cancelled or unpaid subscription, closed account). No grace period.
  • 403 — INSUFFICIENT_SCOPE — the key lacks the scope this operation needs.
  • 429 — RATE_LIMITED — over 120 requests per minute or 10,000 per day for this key (defaults). Wait Retry-After seconds.
  • 500 — INTERNAL_ERROR — unexpected error on our side. Safe to retry with backoff; quote request_id to support if it persists.
  • 503 — SERVICE_BUSY (the server is at capacity) or ELIGIBILITY_UNAVAILABLE (your plan could not be verified). Retry after Retry-After seconds (5 or 10).

Ejemplo de solicitud

curl
curl "https://app.spacekru.com/api/public/v1/ping" \
  -H "Authorization: Bearer $SPACEKRU_API_KEY"
Node.js
const res = await fetch('https://app.spacekru.com/api/public/v1/ping', {
  headers: {
    Authorization: `Bearer ${process.env.SPACEKRU_API_KEY}`,
  },
});
const body = await res.json();
if (!res.ok) {
  // Branch on body.error.code; quote body.error.request_id to support.
  throw new Error(`${body.error.code}: ${body.error.message} (request ${body.error.request_id})`);
}
console.log(body);
Python
import os

import requests

r = requests.get(
    "https://app.spacekru.com/api/public/v1/ping",
    headers={
        "Authorization": f"Bearer {os.environ['SPACEKRU_API_KEY']}",
    },
    timeout=30,
)
body = r.json()
if not r.ok:
    # Branch on body["error"]["code"]; quote body["error"]["request_id"] to support.
    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']} (request {body['error']['request_id']})")
print(body)
Respuesta 200
{
  "object": "ping",
  "organization_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "name": "Acme Corp",
  "plan": "Business",
  "scopes": [
    "read",
    "write"
  ]
}

Leads

Create, update, read and annotate leads.

Lista leads (del más reciente)

GET /leads · Scope: read

Newest first (by created_at, then id). Filters combine with AND. Follow next_cursor until has_more is false. Internal records SpaceKru keeps for its own team are never listed.

Scope: read.

ParámetroEnTipoDescripción
limitqueryintegerPage size, 1 to 100. Default 25. 1 to 100. Default 25.
cursorquerystringThe next_cursor of the previous page. Opaque: do not build or edit it (an invalid cursor answers 400). Max 500 characters.
updated_sincequerystring (date-time)Only records whose updated_at is at or after this time. ISO 8601 with a time zone, e.g. 2026-10-19T00:00:00Z.
statusquerystringExact match on status. Common values: new, contacted, qualified, proposal, won. Max 50 characters.
typequerystringOnly people or only businesses. One of: person, business.
external_idquerystringExact match on the external_id of the lead (the id in your own system). Max 200 characters.
Accept-LanguageheaderstringLanguage of error.message: en or es. Without it, the language of the profile of the person who created the key. Codes and field names never change.

Respuestas

  • 200 — A page of leads.
  • 400 — INVALID_REQUEST — a query parameter is invalid (unknown parameter, bad limit, updated_since or cursor).
  • 401 — INVALID_API_KEY — the key is missing, malformed, unknown or revoked.
  • 402 — PLAN_UPGRADE_REQUIRED — the organization is not on an active paid plan (free plan, cancelled or unpaid subscription, closed account). No grace period.
  • 403 — INSUFFICIENT_SCOPE — the key lacks the scope this operation needs.
  • 429 — RATE_LIMITED — over 120 requests per minute or 10,000 per day for this key (defaults). Wait Retry-After seconds.
  • 500 — INTERNAL_ERROR — unexpected error on our side. Safe to retry with backoff; quote request_id to support if it persists.
  • 503 — SERVICE_BUSY (the server is at capacity) or ELIGIBILITY_UNAVAILABLE (your plan could not be verified). Retry after Retry-After seconds (5 or 10).

Ejemplo de solicitud

curl
curl "https://app.spacekru.com/api/public/v1/leads" \
  -H "Authorization: Bearer $SPACEKRU_API_KEY"
Node.js
const res = await fetch('https://app.spacekru.com/api/public/v1/leads', {
  headers: {
    Authorization: `Bearer ${process.env.SPACEKRU_API_KEY}`,
  },
});
const body = await res.json();
if (!res.ok) {
  // Branch on body.error.code; quote body.error.request_id to support.
  throw new Error(`${body.error.code}: ${body.error.message} (request ${body.error.request_id})`);
}
console.log(body);
Python
import os

import requests

r = requests.get(
    "https://app.spacekru.com/api/public/v1/leads",
    headers={
        "Authorization": f"Bearer {os.environ['SPACEKRU_API_KEY']}",
    },
    timeout=30,
)
body = r.json()
if not r.ok:
    # Branch on body["error"]["code"]; quote body["error"]["request_id"] to support.
    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']} (request {body['error']['request_id']})")
print(body)
Respuesta 200
{
  "data": [
    {
      "object": "lead",
      "id": "3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
      "type": "person",
      "full_name": "Maria Lopez",
      "business_name": null,
      "job_title": "Operations Manager",
      "work_email": "maria.lopez@example.com",
      "personal_email": null,
      "work_phone": "+13055550142",
      "personal_phone": null,
      "company_name": "Acme Corp",
      "city": "Miami",
      "country": "United States",
      "status": "new",
      "source": "api",
      "tags": [
        "typeform",
        "spring-promo"
      ],
      "instagram_profile": null,
      "linkedin_profile_url": null,
      "website": null,
      "external_id": "crm-88412",
      "created_at": "2026-10-19T14:32:10.000Z",
      "updated_at": "2026-10-19T14:32:10.000Z"
    }
  ],
  "has_more": true,
  "next_cursor": "eyJ0IjoiMjAyNi0xMC0xOVQxNDozMjoxMC4wMDBaIiwiaSI6IjNmMmI4YzFlLTlhNGQtNGU2Zi1iN2E4LTFjMmQzZTRmNWE2YiJ9"
}

Crea un lead

POST /leads · Scope: write

At least one contact channel is required: work_email, personal_email, work_phone, personal_phone, instagram_profile, linkedin_profile_url.

The lead is created with source = "api" (always) and type = "person" unless you send type. Blank strings and null are treated as "not sent" (no-code tools send "" for unmapped fields). Unknown fields are rejected with 400.

Duplicates: if an email or phone you send matches an existing lead, the API answers 409 DUPLICATE_RESOURCE with existing_id and creates nothing. When you send no email and no phone, the match is made on the social profile instead. An Instagram or LinkedIn URL sent in website is also stored in its own profile field.

initial_note is added to the lead's timeline, signed by the user who created the API key. If the note cannot be saved, the lead is still created.

Idempotency: send Idempotency-Key (up to 255 characters) to make retries safe. Same key and same body within 24 h: you get the original 201 again with Idempotent-Replayed: true. Same key, different body: 409 IDEMPOTENCY_CONFLICT. Only successful responses are stored: after an error you can retry with the same key.

Creating a lead does not make an AI Employee contact it: add the lead to a campaign in SpaceKru for that.

Scope: write (a read-only key answers 403 INSUFFICIENT_SCOPE).

ParámetroEnTipoDescripción
Idempotency-KeyheaderstringAny unique string per logical request, e.g. a UUID or your form response id. Max 255 characters.
Accept-LanguageheaderstringLanguage of error.message: en or es. Without it, the language of the profile of the person who created the key. Codes and field names never change.

Body de la solicitud (LeadCreate) — Requires at least one of: work_email, personal_email, work_phone, personal_phone, instagram_profile, linkedin_profile_url. Unknown fields are rejected. Los campos desconocidos se rechazan.

CampoTipoDescripción
full_namestringMax 200 characters.
business_namestringMax 200 characters.
job_titlestringMax 200 characters.
work_emailstring (email)Max 320 characters.
personal_emailstring (email)Max 320 characters.
work_phonestringMax 40 characters.
personal_phonestringMax 40 characters.
company_namestringMax 200 characters.
citystringMax 120 characters.
countrystringMax 120 characters.
websitestringMax 500 characters.
instagram_profilestringMax 300 characters.
linkedin_profile_urlstringMax 500 characters.
typestringOne of: person, business.
tagsarray of stringUp to 20 tags of up to 50 characters. A comma-separated string is also accepted (e.g. "typeform, vip"). Up to 20 items.
initial_notestringAdded to the lead's timeline. Max 5000 characters.
external_idstringYour id for this lead (unique per organization). Max 200 characters.
campaign_idstring (uuid)Add the new lead to this prospecting or recontact campaign.

Respuestas

  • 201 — Created. On a replay, the original response. With campaign_id, it also has enrollment. Devuelve Lead.
  • 400 — INVALID_REQUEST — validation failed (details[] lists up to 20 fields), the body is not valid JSON, or Content-Type is not application/json.
  • 401 — INVALID_API_KEY — the key is missing, malformed, unknown or revoked.
  • 402 — PLAN_UPGRADE_REQUIRED — the organization is not on an active paid plan (free plan, cancelled or unpaid subscription, closed account). No grace period.
  • 403 — INSUFFICIENT_SCOPE — the key lacks the scope this operation needs.
  • 409 — DUPLICATE_RESOURCE (a matching lead exists: see existing_id) or IDEMPOTENCY_CONFLICT.
  • 413 — PAYLOAD_TOO_LARGE — the body is over 1 MB.
  • 422 — UNPROCESSABLE — valid JSON that could not be applied (e.g. too many active subscriptions, a value the database rejected).
  • 429 — RATE_LIMITED — over 120 requests per minute or 10,000 per day for this key (defaults). Wait Retry-After seconds.
  • 500 — INTERNAL_ERROR — unexpected error on our side. Safe to retry with backoff; quote request_id to support if it persists.
  • 503 — SERVICE_BUSY (the server is at capacity) or ELIGIBILITY_UNAVAILABLE (your plan could not be verified). Retry after Retry-After seconds (5 or 10).

Ejemplo de solicitud

curl
curl -X POST "https://app.spacekru.com/api/public/v1/leads" \
  -H "Authorization: Bearer $SPACEKRU_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: typeform-resp-8f2a1c" \
  -d '{
  "full_name": "Maria Lopez",
  "work_email": "maria.lopez@example.com",
  "work_phone": "+13055550142",
  "company_name": "Acme Corp",
  "job_title": "Operations Manager",
  "city": "Miami",
  "country": "United States",
  "tags": [
    "typeform",
    "spring-promo"
  ],
  "external_id": "crm-88412",
  "initial_note": "Asked for a demo from the spring promo form."
}'
Node.js
const res = await fetch('https://app.spacekru.com/api/public/v1/leads', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.SPACEKRU_API_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': 'typeform-resp-8f2a1c',
  },
  body: JSON.stringify({
    "full_name": "Maria Lopez",
    "work_email": "maria.lopez@example.com",
    "work_phone": "+13055550142",
    "company_name": "Acme Corp",
    "job_title": "Operations Manager",
    "city": "Miami",
    "country": "United States",
    "tags": [
      "typeform",
      "spring-promo"
    ],
    "external_id": "crm-88412",
    "initial_note": "Asked for a demo from the spring promo form."
  }),
});
const body = await res.json();
if (!res.ok) {
  // Branch on body.error.code; quote body.error.request_id to support.
  throw new Error(`${body.error.code}: ${body.error.message} (request ${body.error.request_id})`);
}
console.log(body);
Python
import os

import requests

r = requests.post(
    "https://app.spacekru.com/api/public/v1/leads",
    headers={
        "Authorization": f"Bearer {os.environ['SPACEKRU_API_KEY']}",
        "Idempotency-Key": "typeform-resp-8f2a1c",
    },
    json={
        "full_name": "Maria Lopez",
        "work_email": "maria.lopez@example.com",
        "work_phone": "+13055550142",
        "company_name": "Acme Corp",
        "job_title": "Operations Manager",
        "city": "Miami",
        "country": "United States",
        "tags": ["typeform", "spring-promo"],
        "external_id": "crm-88412",
        "initial_note": "Asked for a demo from the spring promo form.",
    },
    timeout=30,
)
body = r.json()
if not r.ok:
    # Branch on body["error"]["code"]; quote body["error"]["request_id"] to support.
    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']} (request {body['error']['request_id']})")
print(body)
Respuesta 201
{
  "object": "lead",
  "id": "3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
  "type": "person",
  "full_name": "Maria Lopez",
  "business_name": null,
  "job_title": "Operations Manager",
  "work_email": "maria.lopez@example.com",
  "personal_email": null,
  "work_phone": "+13055550142",
  "personal_phone": null,
  "company_name": "Acme Corp",
  "city": "Miami",
  "country": "United States",
  "status": "new",
  "source": "api",
  "tags": [
    "typeform",
    "spring-promo"
  ],
  "instagram_profile": null,
  "linkedin_profile_url": null,
  "website": null,
  "external_id": "crm-88412",
  "created_at": "2026-10-19T14:32:10.000Z",
  "updated_at": "2026-10-19T14:32:10.000Z"
}

Obtén un lead

GET /leads/{id} · Scope: read

Scope: read.

ParámetroEnTipoDescripción
id (required)pathstring (uuid)The lead id. An id that is not a UUID, or that belongs to another organization, answers 404.
Accept-LanguageheaderstringLanguage of error.message: en or es. Without it, the language of the profile of the person who created the key. Codes and field names never change.

Respuestas

  • 200 — The lead. Devuelve Lead.
  • 401 — INVALID_API_KEY — the key is missing, malformed, unknown or revoked.
  • 402 — PLAN_UPGRADE_REQUIRED — the organization is not on an active paid plan (free plan, cancelled or unpaid subscription, closed account). No grace period.
  • 403 — INSUFFICIENT_SCOPE — the key lacks the scope this operation needs.
  • 404 — NOT_FOUND — no such record in this organization (also for ids that are not UUIDs).
  • 429 — RATE_LIMITED — over 120 requests per minute or 10,000 per day for this key (defaults). Wait Retry-After seconds.
  • 500 — INTERNAL_ERROR — unexpected error on our side. Safe to retry with backoff; quote request_id to support if it persists.
  • 503 — SERVICE_BUSY (the server is at capacity) or ELIGIBILITY_UNAVAILABLE (your plan could not be verified). Retry after Retry-After seconds (5 or 10).

Ejemplo de solicitud

curl
curl "https://app.spacekru.com/api/public/v1/leads/3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b" \
  -H "Authorization: Bearer $SPACEKRU_API_KEY"
Node.js
const res = await fetch('https://app.spacekru.com/api/public/v1/leads/3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b', {
  headers: {
    Authorization: `Bearer ${process.env.SPACEKRU_API_KEY}`,
  },
});
const body = await res.json();
if (!res.ok) {
  // Branch on body.error.code; quote body.error.request_id to support.
  throw new Error(`${body.error.code}: ${body.error.message} (request ${body.error.request_id})`);
}
console.log(body);
Python
import os

import requests

r = requests.get(
    "https://app.spacekru.com/api/public/v1/leads/3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
    headers={
        "Authorization": f"Bearer {os.environ['SPACEKRU_API_KEY']}",
    },
    timeout=30,
)
body = r.json()
if not r.ok:
    # Branch on body["error"]["code"]; quote body["error"]["request_id"] to support.
    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']} (request {body['error']['request_id']})")
print(body)
Respuesta 200
{
  "object": "lead",
  "id": "3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
  "type": "person",
  "full_name": "Maria Lopez",
  "business_name": null,
  "job_title": "Operations Manager",
  "work_email": "maria.lopez@example.com",
  "personal_email": null,
  "work_phone": "+13055550142",
  "personal_phone": null,
  "company_name": "Acme Corp",
  "city": "Miami",
  "country": "United States",
  "status": "new",
  "source": "api",
  "tags": [
    "typeform",
    "spring-promo"
  ],
  "instagram_profile": null,
  "linkedin_profile_url": null,
  "website": null,
  "external_id": "crm-88412",
  "created_at": "2026-10-19T14:32:10.000Z",
  "updated_at": "2026-10-19T14:32:10.000Z"
}

Actualiza un lead

PATCH /leads/{id} · Scope: write

Partial update: send only the fields to change (at least one). Send null or "" to clear a field.

tags: the array you send replaces the current tags; null removes them all; "" is ignored.

status and source are managed by SpaceKru and cannot be written (they are rejected as unknown fields).

Updates do NOT check for duplicates by email or phone. external_id must stay unique: another lead with the same one answers 409 with existing_id.

Scope: write (a read-only key answers 403 INSUFFICIENT_SCOPE).

ParámetroEnTipoDescripción
id (required)pathstring (uuid)The lead id. An id that is not a UUID, or that belongs to another organization, answers 404.
Accept-LanguageheaderstringLanguage of error.message: en or es. Without it, the language of the profile of the person who created the key. Codes and field names never change.

Body de la solicitud (LeadUpdate) — Only the fields you send change. null or "" clears a field. status and source are not writable. Los campos desconocidos se rechazan.

CampoTipoDescripción
full_namestringMax 200 characters.
business_namestringMax 200 characters.
job_titlestringMax 200 characters.
work_emailstring (email)Max 320 characters.
personal_emailstring (email)Max 320 characters.
work_phonestringMax 40 characters.
personal_phonestringMax 40 characters.
company_namestringMax 200 characters.
citystringMax 120 characters.
countrystringMax 120 characters.
websitestringMax 500 characters.
instagram_profilestringMax 300 characters.
linkedin_profile_urlstringMax 500 characters.
typestringOne of: person, business.
tagsarray of stringUp to 20 tags of up to 50 characters. A comma-separated string is also accepted (e.g. "typeform, vip"). Up to 20 items.
external_idstring or nullYour id for this lead. Another lead with the same one answers 409. Max 200 characters.

Respuestas

  • 200 — Updated. Devuelve Lead.
  • 400 — INVALID_REQUEST — validation failed (details[] lists up to 20 fields), the body is not valid JSON, or Content-Type is not application/json.
  • 401 — INVALID_API_KEY — the key is missing, malformed, unknown or revoked.
  • 402 — PLAN_UPGRADE_REQUIRED — the organization is not on an active paid plan (free plan, cancelled or unpaid subscription, closed account). No grace period.
  • 403 — INSUFFICIENT_SCOPE — the key lacks the scope this operation needs.
  • 404 — NOT_FOUND — no such record in this organization (also for ids that are not UUIDs).
  • 409 — DUPLICATE_RESOURCE — another lead already uses this external_id (see existing_id).
  • 413 — PAYLOAD_TOO_LARGE — the body is over 1 MB.
  • 422 — UNPROCESSABLE — valid JSON that could not be applied (e.g. too many active subscriptions, a value the database rejected).
  • 429 — RATE_LIMITED — over 120 requests per minute or 10,000 per day for this key (defaults). Wait Retry-After seconds.
  • 500 — INTERNAL_ERROR — unexpected error on our side. Safe to retry with backoff; quote request_id to support if it persists.
  • 503 — SERVICE_BUSY (the server is at capacity) or ELIGIBILITY_UNAVAILABLE (your plan could not be verified). Retry after Retry-After seconds (5 or 10).

Ejemplo de solicitud

curl
curl -X PATCH "https://app.spacekru.com/api/public/v1/leads/3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b" \
  -H "Authorization: Bearer $SPACEKRU_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "job_title": "Head of Operations",
  "tags": [
    "typeform",
    "spring-promo",
    "vip"
  ]
}'
Node.js
const res = await fetch('https://app.spacekru.com/api/public/v1/leads/3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.SPACEKRU_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "job_title": "Head of Operations",
    "tags": [
      "typeform",
      "spring-promo",
      "vip"
    ]
  }),
});
const body = await res.json();
if (!res.ok) {
  // Branch on body.error.code; quote body.error.request_id to support.
  throw new Error(`${body.error.code}: ${body.error.message} (request ${body.error.request_id})`);
}
console.log(body);
Python
import os

import requests

r = requests.patch(
    "https://app.spacekru.com/api/public/v1/leads/3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
    headers={
        "Authorization": f"Bearer {os.environ['SPACEKRU_API_KEY']}",
    },
    json={
        "job_title": "Head of Operations",
        "tags": ["typeform", "spring-promo", "vip"],
    },
    timeout=30,
)
body = r.json()
if not r.ok:
    # Branch on body["error"]["code"]; quote body["error"]["request_id"] to support.
    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']} (request {body['error']['request_id']})")
print(body)
Respuesta 200
{
  "object": "lead",
  "id": "3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
  "type": "person",
  "full_name": "Maria Lopez",
  "business_name": null,
  "job_title": "Head of Operations",
  "work_email": "maria.lopez@example.com",
  "personal_email": null,
  "work_phone": "+13055550142",
  "personal_phone": null,
  "company_name": "Acme Corp",
  "city": "Miami",
  "country": "United States",
  "status": "new",
  "source": "api",
  "tags": [
    "typeform",
    "spring-promo",
    "vip"
  ],
  "instagram_profile": null,
  "linkedin_profile_url": null,
  "website": null,
  "external_id": "crm-88412",
  "created_at": "2026-10-19T14:32:10.000Z",
  "updated_at": "2026-10-19T15:02:44.000Z"
}

Añade una nota a un lead

POST /leads/{id}/notes · Scope: write

Adds a note to the lead's timeline in SpaceKru, signed by the user who created the API key (or the account owner if that user no longer exists).

Scope: write (a read-only key answers 403 INSUFFICIENT_SCOPE).

ParámetroEnTipoDescripción
id (required)pathstring (uuid)The lead id. An id that is not a UUID, or that belongs to another organization, answers 404.
Accept-LanguageheaderstringLanguage of error.message: en or es. Without it, the language of the profile of the person who created the key. Codes and field names never change.

Body de la solicitud Los campos desconocidos se rechazan.

CampoTipoDescripción
content (required)stringMax 5000 characters.

Respuestas

  • 201 — Created. Devuelve Note.
  • 400 — INVALID_REQUEST — validation failed (details[] lists up to 20 fields), the body is not valid JSON, or Content-Type is not application/json.
  • 401 — INVALID_API_KEY — the key is missing, malformed, unknown or revoked.
  • 402 — PLAN_UPGRADE_REQUIRED — the organization is not on an active paid plan (free plan, cancelled or unpaid subscription, closed account). No grace period.
  • 403 — INSUFFICIENT_SCOPE — the key lacks the scope this operation needs.
  • 404 — NOT_FOUND — no such record in this organization (also for ids that are not UUIDs).
  • 413 — PAYLOAD_TOO_LARGE — the body is over 1 MB.
  • 422 — UNPROCESSABLE — valid JSON that could not be applied (e.g. too many active subscriptions, a value the database rejected).
  • 429 — RATE_LIMITED — over 120 requests per minute or 10,000 per day for this key (defaults). Wait Retry-After seconds.
  • 500 — INTERNAL_ERROR — unexpected error on our side. Safe to retry with backoff; quote request_id to support if it persists.
  • 503 — SERVICE_BUSY (the server is at capacity) or ELIGIBILITY_UNAVAILABLE (your plan could not be verified). Retry after Retry-After seconds (5 or 10).

Ejemplo de solicitud

curl
curl -X POST "https://app.spacekru.com/api/public/v1/leads/3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b/notes" \
  -H "Authorization: Bearer $SPACEKRU_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "content": "Called back: wants pricing for 3 locations."
}'
Node.js
const res = await fetch('https://app.spacekru.com/api/public/v1/leads/3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b/notes', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.SPACEKRU_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "content": "Called back: wants pricing for 3 locations."
  }),
});
const body = await res.json();
if (!res.ok) {
  // Branch on body.error.code; quote body.error.request_id to support.
  throw new Error(`${body.error.code}: ${body.error.message} (request ${body.error.request_id})`);
}
console.log(body);
Python
import os

import requests

r = requests.post(
    "https://app.spacekru.com/api/public/v1/leads/3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b/notes",
    headers={
        "Authorization": f"Bearer {os.environ['SPACEKRU_API_KEY']}",
    },
    json={
        "content": "Called back: wants pricing for 3 locations.",
    },
    timeout=30,
)
body = r.json()
if not r.ok:
    # Branch on body["error"]["code"]; quote body["error"]["request_id"] to support.
    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']} (request {body['error']['request_id']})")
print(body)
Respuesta 201
{
  "object": "note",
  "id": "5d6e7f80-91a2-4b3c-8d4e-5f6a7b8c9d0e",
  "lead_id": "3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
  "content": "Called back: wants pricing for 3 locations.",
  "created_at": "2026-10-19T15:10:03.000Z"
}

Deals

Read-only in v1.

Lista deals

GET /deals · Scope: read

Newest first (by created_at, then id). Filters combine with AND. Follow next_cursor until has_more is false.

Scope: read.

ParámetroEnTipoDescripción
limitqueryintegerPage size, 1 to 100. Default 25. 1 to 100. Default 25.
cursorquerystringThe next_cursor of the previous page. Opaque: do not build or edit it (an invalid cursor answers 400). Max 500 characters.
updated_sincequerystring (date-time)Only records whose updated_at is at or after this time. ISO 8601 with a time zone, e.g. 2026-10-19T00:00:00Z.
statusquerystringExact match on status. Common values: open, won, lost. Max 50 characters.
external_idquerystringExact match on the external_id of the deal (the id in your own system). Max 200 characters.
lead_idquerystring (uuid)Only the deals of this lead.
stage_idquerystring (uuid)Only the deals in this pipeline stage (see GET /pipeline-stages).
Accept-LanguageheaderstringLanguage of error.message: en or es. Without it, the language of the profile of the person who created the key. Codes and field names never change.

Respuestas

  • 200 — A page of deals.
  • 400 — INVALID_REQUEST — a query parameter is invalid (unknown parameter, bad limit, updated_since or cursor).
  • 401 — INVALID_API_KEY — the key is missing, malformed, unknown or revoked.
  • 402 — PLAN_UPGRADE_REQUIRED — the organization is not on an active paid plan (free plan, cancelled or unpaid subscription, closed account). No grace period.
  • 403 — INSUFFICIENT_SCOPE — the key lacks the scope this operation needs.
  • 429 — RATE_LIMITED — over 120 requests per minute or 10,000 per day for this key (defaults). Wait Retry-After seconds.
  • 500 — INTERNAL_ERROR — unexpected error on our side. Safe to retry with backoff; quote request_id to support if it persists.
  • 503 — SERVICE_BUSY (the server is at capacity) or ELIGIBILITY_UNAVAILABLE (your plan could not be verified). Retry after Retry-After seconds (5 or 10).

Ejemplo de solicitud

curl
curl "https://app.spacekru.com/api/public/v1/deals" \
  -H "Authorization: Bearer $SPACEKRU_API_KEY"
Node.js
const res = await fetch('https://app.spacekru.com/api/public/v1/deals', {
  headers: {
    Authorization: `Bearer ${process.env.SPACEKRU_API_KEY}`,
  },
});
const body = await res.json();
if (!res.ok) {
  // Branch on body.error.code; quote body.error.request_id to support.
  throw new Error(`${body.error.code}: ${body.error.message} (request ${body.error.request_id})`);
}
console.log(body);
Python
import os

import requests

r = requests.get(
    "https://app.spacekru.com/api/public/v1/deals",
    headers={
        "Authorization": f"Bearer {os.environ['SPACEKRU_API_KEY']}",
    },
    timeout=30,
)
body = r.json()
if not r.ok:
    # Branch on body["error"]["code"]; quote body["error"]["request_id"] to support.
    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']} (request {body['error']['request_id']})")
print(body)
Respuesta 200
{
  "data": [
    {
      "object": "deal",
      "id": "8d1e2f3a-4b5c-4d6e-8f70-9a1b2c3d4e5f",
      "lead_id": "3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
      "title": "Acme Corp — 3 locations",
      "value": 4800,
      "stage": "Proposal",
      "status": "open",
      "close_date": "2026-11-30",
      "lost_reason": null,
      "stage_id": "c3d4e5f6-a7b8-4c9d-8e0f-2a3b4c5d6e7f",
      "agent_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5e",
      "external_id": "opp-5521",
      "next_step_action": "Follow-up scheduled (WhatsApp)",
      "next_step_date": "2026-10-24T15:00:00.000Z",
      "created_at": "2026-10-20T09:15:00.000Z",
      "updated_at": "2026-10-22T16:40:12.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Obtén un deal

GET /deals/{id} · Scope: read

Scope: read.

ParámetroEnTipoDescripción
id (required)pathstring (uuid)The deal id. An id that is not a UUID, or that belongs to another organization, answers 404.
Accept-LanguageheaderstringLanguage of error.message: en or es. Without it, the language of the profile of the person who created the key. Codes and field names never change.

Respuestas

  • 200 — The deal. Devuelve Deal.
  • 401 — INVALID_API_KEY — the key is missing, malformed, unknown or revoked.
  • 402 — PLAN_UPGRADE_REQUIRED — the organization is not on an active paid plan (free plan, cancelled or unpaid subscription, closed account). No grace period.
  • 403 — INSUFFICIENT_SCOPE — the key lacks the scope this operation needs.
  • 404 — NOT_FOUND — no such record in this organization (also for ids that are not UUIDs).
  • 429 — RATE_LIMITED — over 120 requests per minute or 10,000 per day for this key (defaults). Wait Retry-After seconds.
  • 500 — INTERNAL_ERROR — unexpected error on our side. Safe to retry with backoff; quote request_id to support if it persists.
  • 503 — SERVICE_BUSY (the server is at capacity) or ELIGIBILITY_UNAVAILABLE (your plan could not be verified). Retry after Retry-After seconds (5 or 10).

Ejemplo de solicitud

curl
curl "https://app.spacekru.com/api/public/v1/deals/8d1e2f3a-4b5c-4d6e-8f70-9a1b2c3d4e5f" \
  -H "Authorization: Bearer $SPACEKRU_API_KEY"
Node.js
const res = await fetch('https://app.spacekru.com/api/public/v1/deals/8d1e2f3a-4b5c-4d6e-8f70-9a1b2c3d4e5f', {
  headers: {
    Authorization: `Bearer ${process.env.SPACEKRU_API_KEY}`,
  },
});
const body = await res.json();
if (!res.ok) {
  // Branch on body.error.code; quote body.error.request_id to support.
  throw new Error(`${body.error.code}: ${body.error.message} (request ${body.error.request_id})`);
}
console.log(body);
Python
import os

import requests

r = requests.get(
    "https://app.spacekru.com/api/public/v1/deals/8d1e2f3a-4b5c-4d6e-8f70-9a1b2c3d4e5f",
    headers={
        "Authorization": f"Bearer {os.environ['SPACEKRU_API_KEY']}",
    },
    timeout=30,
)
body = r.json()
if not r.ok:
    # Branch on body["error"]["code"]; quote body["error"]["request_id"] to support.
    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']} (request {body['error']['request_id']})")
print(body)
Respuesta 200
{
  "object": "deal",
  "id": "8d1e2f3a-4b5c-4d6e-8f70-9a1b2c3d4e5f",
  "lead_id": "3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
  "title": "Acme Corp — 3 locations",
  "value": 4800,
  "stage": "Proposal",
  "status": "open",
  "close_date": "2026-11-30",
  "lost_reason": null,
  "stage_id": "c3d4e5f6-a7b8-4c9d-8e0f-2a3b4c5d6e7f",
  "agent_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5e",
  "external_id": "opp-5521",
  "next_step_action": "Follow-up scheduled (WhatsApp)",
  "next_step_date": "2026-10-24T15:00:00.000Z",
  "created_at": "2026-10-20T09:15:00.000Z",
  "updated_at": "2026-10-22T16:40:12.000Z"
}

Cotizaciones

Read-only in v1. Quotes include their line items.

Lista cotizaciones

GET /quotes · Scope: read

Newest first (by created_at, then id). Filters combine with AND. Follow next_cursor until has_more is false.

Scope: read.

ParámetroEnTipoDescripción
limitqueryintegerPage size, 1 to 100. Default 25. 1 to 100. Default 25.
cursorquerystringThe next_cursor of the previous page. Opaque: do not build or edit it (an invalid cursor answers 400). Max 500 characters.
updated_sincequerystring (date-time)Only records whose updated_at is at or after this time. ISO 8601 with a time zone, e.g. 2026-10-19T00:00:00Z.
statusquerystringExact match on status. Common values: draft, sent, accepted, rejected. Max 50 characters.
external_idquerystringExact match on the external_id of the quote (the id in your own system). Max 200 characters.
Accept-LanguageheaderstringLanguage of error.message: en or es. Without it, the language of the profile of the person who created the key. Codes and field names never change.

Respuestas

  • 200 — A page of quotes.
  • 400 — INVALID_REQUEST — a query parameter is invalid (unknown parameter, bad limit, updated_since or cursor).
  • 401 — INVALID_API_KEY — the key is missing, malformed, unknown or revoked.
  • 402 — PLAN_UPGRADE_REQUIRED — the organization is not on an active paid plan (free plan, cancelled or unpaid subscription, closed account). No grace period.
  • 403 — INSUFFICIENT_SCOPE — the key lacks the scope this operation needs.
  • 429 — RATE_LIMITED — over 120 requests per minute or 10,000 per day for this key (defaults). Wait Retry-After seconds.
  • 500 — INTERNAL_ERROR — unexpected error on our side. Safe to retry with backoff; quote request_id to support if it persists.
  • 503 — SERVICE_BUSY (the server is at capacity) or ELIGIBILITY_UNAVAILABLE (your plan could not be verified). Retry after Retry-After seconds (5 or 10).

Ejemplo de solicitud

curl
curl "https://app.spacekru.com/api/public/v1/quotes" \
  -H "Authorization: Bearer $SPACEKRU_API_KEY"
Node.js
const res = await fetch('https://app.spacekru.com/api/public/v1/quotes', {
  headers: {
    Authorization: `Bearer ${process.env.SPACEKRU_API_KEY}`,
  },
});
const body = await res.json();
if (!res.ok) {
  // Branch on body.error.code; quote body.error.request_id to support.
  throw new Error(`${body.error.code}: ${body.error.message} (request ${body.error.request_id})`);
}
console.log(body);
Python
import os

import requests

r = requests.get(
    "https://app.spacekru.com/api/public/v1/quotes",
    headers={
        "Authorization": f"Bearer {os.environ['SPACEKRU_API_KEY']}",
    },
    timeout=30,
)
body = r.json()
if not r.ok:
    # Branch on body["error"]["code"]; quote body["error"]["request_id"] to support.
    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']} (request {body['error']['request_id']})")
print(body)
Respuesta 200
{
  "data": [
    {
      "object": "quote",
      "id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
      "number": "Q-1042",
      "lead_id": "3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
      "deal_id": "8d1e2f3a-4b5c-4d6e-8f70-9a1b2c3d4e5f",
      "status": "sent",
      "subtotal": 1200,
      "tax_total": 84,
      "shipping_cost": 0,
      "discount_total": 0,
      "total": 1284,
      "valid_until": "2026-11-15",
      "items": [
        {
          "product_id": "2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f",
          "name": "Annual plan — per location",
          "sku": "PLAN-LOC-12",
          "description": null,
          "quantity": 3,
          "unit_price": 400,
          "total": 1284,
          "variant_id": null,
          "tax_rate": 7,
          "discount": 0
        }
      ],
      "external_id": "qt-7781",
      "notes": "Prices valid for the 2026 rollout.",
      "payment_terms": "Net 15",
      "created_at": "2026-10-22T16:45:00.000Z",
      "updated_at": "2026-10-22T16:47:31.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Obtén una cotización

GET /quotes/{id} · Scope: read

Scope: read.

ParámetroEnTipoDescripción
id (required)pathstring (uuid)The quote id. An id that is not a UUID, or that belongs to another organization, answers 404.
Accept-LanguageheaderstringLanguage of error.message: en or es. Without it, the language of the profile of the person who created the key. Codes and field names never change.

Respuestas

  • 200 — The quote. Devuelve Quote.
  • 401 — INVALID_API_KEY — the key is missing, malformed, unknown or revoked.
  • 402 — PLAN_UPGRADE_REQUIRED — the organization is not on an active paid plan (free plan, cancelled or unpaid subscription, closed account). No grace period.
  • 403 — INSUFFICIENT_SCOPE — the key lacks the scope this operation needs.
  • 404 — NOT_FOUND — no such record in this organization (also for ids that are not UUIDs).
  • 429 — RATE_LIMITED — over 120 requests per minute or 10,000 per day for this key (defaults). Wait Retry-After seconds.
  • 500 — INTERNAL_ERROR — unexpected error on our side. Safe to retry with backoff; quote request_id to support if it persists.
  • 503 — SERVICE_BUSY (the server is at capacity) or ELIGIBILITY_UNAVAILABLE (your plan could not be verified). Retry after Retry-After seconds (5 or 10).

Ejemplo de solicitud

curl
curl "https://app.spacekru.com/api/public/v1/quotes/1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d" \
  -H "Authorization: Bearer $SPACEKRU_API_KEY"
Node.js
const res = await fetch('https://app.spacekru.com/api/public/v1/quotes/1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d', {
  headers: {
    Authorization: `Bearer ${process.env.SPACEKRU_API_KEY}`,
  },
});
const body = await res.json();
if (!res.ok) {
  // Branch on body.error.code; quote body.error.request_id to support.
  throw new Error(`${body.error.code}: ${body.error.message} (request ${body.error.request_id})`);
}
console.log(body);
Python
import os

import requests

r = requests.get(
    "https://app.spacekru.com/api/public/v1/quotes/1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
    headers={
        "Authorization": f"Bearer {os.environ['SPACEKRU_API_KEY']}",
    },
    timeout=30,
)
body = r.json()
if not r.ok:
    # Branch on body["error"]["code"]; quote body["error"]["request_id"] to support.
    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']} (request {body['error']['request_id']})")
print(body)
Respuesta 200
{
  "object": "quote",
  "id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
  "number": "Q-1042",
  "lead_id": "3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
  "deal_id": "8d1e2f3a-4b5c-4d6e-8f70-9a1b2c3d4e5f",
  "status": "sent",
  "subtotal": 1200,
  "tax_total": 84,
  "shipping_cost": 0,
  "discount_total": 0,
  "total": 1284,
  "valid_until": "2026-11-15",
  "items": [
    {
      "product_id": "2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f",
      "name": "Annual plan — per location",
      "sku": "PLAN-LOC-12",
      "description": null,
      "quantity": 3,
      "unit_price": 400,
      "total": 1284,
      "variant_id": null,
      "tax_rate": 7,
      "discount": 0
    }
  ],
  "external_id": "qt-7781",
  "notes": "Prices valid for the 2026 rollout.",
  "payment_terms": "Net 15",
  "created_at": "2026-10-22T16:45:00.000Z",
  "updated_at": "2026-10-22T16:47:31.000Z"
}

Órdenes

Read-only in v1. Orders include their line items and payment status.

Lista órdenes

GET /orders · Scope: read

Newest first (by created_at, then id). Filters combine with AND. Follow next_cursor until has_more is false. Archived orders are NOT listed (you can still retrieve them by id, and webhooks report them).

Scope: read.

ParámetroEnTipoDescripción
limitqueryintegerPage size, 1 to 100. Default 25. 1 to 100. Default 25.
cursorquerystringThe next_cursor of the previous page. Opaque: do not build or edit it (an invalid cursor answers 400). Max 500 characters.
updated_sincequerystring (date-time)Only records whose updated_at is at or after this time. ISO 8601 with a time zone, e.g. 2026-10-19T00:00:00Z.
statusquerystringExact match on status. Common values: draft, pending, processing, shipped, delivered, cancelled. Max 50 characters.
external_idquerystringExact match on the external_id of the order (the id in your own system). Max 200 characters.
Accept-LanguageheaderstringLanguage of error.message: en or es. Without it, the language of the profile of the person who created the key. Codes and field names never change.

Respuestas

  • 200 — A page of orders.
  • 400 — INVALID_REQUEST — a query parameter is invalid (unknown parameter, bad limit, updated_since or cursor).
  • 401 — INVALID_API_KEY — the key is missing, malformed, unknown or revoked.
  • 402 — PLAN_UPGRADE_REQUIRED — the organization is not on an active paid plan (free plan, cancelled or unpaid subscription, closed account). No grace period.
  • 403 — INSUFFICIENT_SCOPE — the key lacks the scope this operation needs.
  • 429 — RATE_LIMITED — over 120 requests per minute or 10,000 per day for this key (defaults). Wait Retry-After seconds.
  • 500 — INTERNAL_ERROR — unexpected error on our side. Safe to retry with backoff; quote request_id to support if it persists.
  • 503 — SERVICE_BUSY (the server is at capacity) or ELIGIBILITY_UNAVAILABLE (your plan could not be verified). Retry after Retry-After seconds (5 or 10).

Ejemplo de solicitud

curl
curl "https://app.spacekru.com/api/public/v1/orders" \
  -H "Authorization: Bearer $SPACEKRU_API_KEY"
Node.js
const res = await fetch('https://app.spacekru.com/api/public/v1/orders', {
  headers: {
    Authorization: `Bearer ${process.env.SPACEKRU_API_KEY}`,
  },
});
const body = await res.json();
if (!res.ok) {
  // Branch on body.error.code; quote body.error.request_id to support.
  throw new Error(`${body.error.code}: ${body.error.message} (request ${body.error.request_id})`);
}
console.log(body);
Python
import os

import requests

r = requests.get(
    "https://app.spacekru.com/api/public/v1/orders",
    headers={
        "Authorization": f"Bearer {os.environ['SPACEKRU_API_KEY']}",
    },
    timeout=30,
)
body = r.json()
if not r.ok:
    # Branch on body["error"]["code"]; quote body["error"]["request_id"] to support.
    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']} (request {body['error']['request_id']})")
print(body)
Respuesta 200
{
  "data": [
    {
      "object": "order",
      "id": "9f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a",
      "number": "ORD-2088",
      "quote_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
      "lead_id": "3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
      "deal_id": "8d1e2f3a-4b5c-4d6e-8f70-9a1b2c3d4e5f",
      "status": "processing",
      "payment_status": "paid",
      "subtotal": 1200,
      "tax": 84,
      "shipping_cost": 0,
      "total": 1284,
      "tracking_number": null,
      "carrier": null,
      "items": [
        {
          "product_id": "2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f",
          "name": "Annual plan — per location",
          "sku": "PLAN-LOC-12",
          "description": null,
          "quantity": 3,
          "unit_price": 400,
          "total": 1284,
          "variant_id": null,
          "tax_rate": 7,
          "discount": 0
        }
      ],
      "external_id": "erp-so-3310",
      "delivery_type": "pickup",
      "shipping_address": null,
      "billing_address": null,
      "notes": null,
      "amount_paid": 1284,
      "created_at": "2026-10-24T10:05:00.000Z",
      "updated_at": "2026-10-24T18:20:09.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Obtén una orden

GET /orders/{id} · Scope: read

Archived orders are returned too.

Scope: read.

ParámetroEnTipoDescripción
id (required)pathstring (uuid)The order id. An id that is not a UUID, or that belongs to another organization, answers 404.
Accept-LanguageheaderstringLanguage of error.message: en or es. Without it, the language of the profile of the person who created the key. Codes and field names never change.

Respuestas

  • 200 — The order. Devuelve Order.
  • 401 — INVALID_API_KEY — the key is missing, malformed, unknown or revoked.
  • 402 — PLAN_UPGRADE_REQUIRED — the organization is not on an active paid plan (free plan, cancelled or unpaid subscription, closed account). No grace period.
  • 403 — INSUFFICIENT_SCOPE — the key lacks the scope this operation needs.
  • 404 — NOT_FOUND — no such record in this organization (also for ids that are not UUIDs).
  • 429 — RATE_LIMITED — over 120 requests per minute or 10,000 per day for this key (defaults). Wait Retry-After seconds.
  • 500 — INTERNAL_ERROR — unexpected error on our side. Safe to retry with backoff; quote request_id to support if it persists.
  • 503 — SERVICE_BUSY (the server is at capacity) or ELIGIBILITY_UNAVAILABLE (your plan could not be verified). Retry after Retry-After seconds (5 or 10).

Ejemplo de solicitud

curl
curl "https://app.spacekru.com/api/public/v1/orders/9f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a" \
  -H "Authorization: Bearer $SPACEKRU_API_KEY"
Node.js
const res = await fetch('https://app.spacekru.com/api/public/v1/orders/9f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a', {
  headers: {
    Authorization: `Bearer ${process.env.SPACEKRU_API_KEY}`,
  },
});
const body = await res.json();
if (!res.ok) {
  // Branch on body.error.code; quote body.error.request_id to support.
  throw new Error(`${body.error.code}: ${body.error.message} (request ${body.error.request_id})`);
}
console.log(body);
Python
import os

import requests

r = requests.get(
    "https://app.spacekru.com/api/public/v1/orders/9f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a",
    headers={
        "Authorization": f"Bearer {os.environ['SPACEKRU_API_KEY']}",
    },
    timeout=30,
)
body = r.json()
if not r.ok:
    # Branch on body["error"]["code"]; quote body["error"]["request_id"] to support.
    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']} (request {body['error']['request_id']})")
print(body)
Respuesta 200
{
  "object": "order",
  "id": "9f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a",
  "number": "ORD-2088",
  "quote_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
  "lead_id": "3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
  "deal_id": "8d1e2f3a-4b5c-4d6e-8f70-9a1b2c3d4e5f",
  "status": "processing",
  "payment_status": "paid",
  "subtotal": 1200,
  "tax": 84,
  "shipping_cost": 0,
  "total": 1284,
  "tracking_number": null,
  "carrier": null,
  "items": [
    {
      "product_id": "2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f",
      "name": "Annual plan — per location",
      "sku": "PLAN-LOC-12",
      "description": null,
      "quantity": 3,
      "unit_price": 400,
      "total": 1284,
      "variant_id": null,
      "tax_rate": 7,
      "discount": 0
    }
  ],
  "external_id": "erp-so-3310",
  "delivery_type": "pickup",
  "shipping_address": null,
  "billing_address": null,
  "notes": null,
  "amount_paid": 1284,
  "created_at": "2026-10-24T10:05:00.000Z",
  "updated_at": "2026-10-24T18:20:09.000Z"
}

Suscripciones de webhook

Subscribe a URL to real-time events (REST Hooks). Every operation requires the write scope.

Lista las suscripciones de webhook

GET /subscriptions · Scope: write

Every webhook subscription of the organization — active and deactivated, created by any key or tool — newest first, up to 200. has_more is always false. Never includes the secret.

Scope: write (a read-only key answers 403 INSUFFICIENT_SCOPE).

ParámetroEnTipoDescripción
Accept-LanguageheaderstringLanguage of error.message: en or es. Without it, the language of the profile of the person who created the key. Codes and field names never change.

Respuestas

  • 200 — Subscriptions.
  • 401 — INVALID_API_KEY — the key is missing, malformed, unknown or revoked.
  • 402 — PLAN_UPGRADE_REQUIRED — the organization is not on an active paid plan (free plan, cancelled or unpaid subscription, closed account). No grace period.
  • 403 — INSUFFICIENT_SCOPE — the key lacks the scope this operation needs.
  • 429 — RATE_LIMITED — over 120 requests per minute or 10,000 per day for this key (defaults). Wait Retry-After seconds.
  • 500 — INTERNAL_ERROR — unexpected error on our side. Safe to retry with backoff; quote request_id to support if it persists.
  • 503 — SERVICE_BUSY (the server is at capacity) or ELIGIBILITY_UNAVAILABLE (your plan could not be verified). Retry after Retry-After seconds (5 or 10).

Ejemplo de solicitud

curl
curl "https://app.spacekru.com/api/public/v1/subscriptions" \
  -H "Authorization: Bearer $SPACEKRU_API_KEY"
Node.js
const res = await fetch('https://app.spacekru.com/api/public/v1/subscriptions', {
  headers: {
    Authorization: `Bearer ${process.env.SPACEKRU_API_KEY}`,
  },
});
const body = await res.json();
if (!res.ok) {
  // Branch on body.error.code; quote body.error.request_id to support.
  throw new Error(`${body.error.code}: ${body.error.message} (request ${body.error.request_id})`);
}
console.log(body);
Python
import os

import requests

r = requests.get(
    "https://app.spacekru.com/api/public/v1/subscriptions",
    headers={
        "Authorization": f"Bearer {os.environ['SPACEKRU_API_KEY']}",
    },
    timeout=30,
)
body = r.json()
if not r.ok:
    # Branch on body["error"]["code"]; quote body["error"]["request_id"] to support.
    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']} (request {body['error']['request_id']})")
print(body)
Respuesta 200
{
  "data": [
    {
      "object": "subscription",
      "id": "0a1b2c3d-4e5f-4a6b-9c7d-8e9f0a1b2c3d",
      "event_type": "lead.created",
      "target_url": "https://hooks.zapier.com/hooks/catch/1234567/abcdefg/",
      "is_active": true,
      "failure_count": 0,
      "disabled_reason": null,
      "last_success_at": null,
      "created_at": "2026-10-19T14:40:00.000Z",
      "exclude_own_changes": false
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Suscribe una URL a un evento (REST Hook)

POST /subscriptions · Scope: write

The secret used to sign deliveries is returned ONLY in this response. Store it now.

target_url rules: https:// only, default port 443 only, no user or password in the URL, a public host (no localhost, .local, .internal or private/reserved IP addresses — checked again on every delivery). Redirects are never followed. Your endpoint must answer within 8 seconds.

At most 50 active subscriptions per organization (422 beyond that). One subscription = one event and one URL: subscribe the same URL several times for several events.

No backfill: only events that happen after you subscribe are sent. To load history, list the resource once.

If the key that created a subscription is revoked, the subscription is deactivated (disabled_reason: "key_revoked").

Scope: write (a read-only key answers 403 INSUFFICIENT_SCOPE).

ParámetroEnTipoDescripción
Accept-LanguageheaderstringLanguage of error.message: en or es. Without it, the language of the profile of the person who created the key. Codes and field names never change.

Body de la solicitud (SubscriptionCreate) Los campos desconocidos se rechazan.

CampoTipoDescripción
event_type (required)stringOne of: lead.created, lead.updated, deal.created, deal.stage_changed, deal.updated, quote.created, quote.status_changed, order.created, order.status_changed, campaign_lead.replied, campaign_lead.form_submitted, product.created, product.updated, booking.created, booking.updated, conversation.message_created.
target_url (required)string (uri)Public https:// URL on port 443, without credentials. Internal hosts and private IP addresses are rejected. Redirects are not followed. Max 2000 characters.
exclude_own_changesbooleanDo not deliver changes made with THIS API key. Turn it on when your platform both writes through the API and listens to the same events. Default false.

Respuestas

  • 201 — Created. The only response that includes secret. Devuelve SubscriptionCreated.
  • 400 — INVALID_REQUEST — validation failed (details[] lists up to 20 fields), the body is not valid JSON, or Content-Type is not application/json.
  • 401 — INVALID_API_KEY — the key is missing, malformed, unknown or revoked.
  • 402 — PLAN_UPGRADE_REQUIRED — the organization is not on an active paid plan (free plan, cancelled or unpaid subscription, closed account). No grace period.
  • 403 — INSUFFICIENT_SCOPE — the key lacks the scope this operation needs.
  • 413 — PAYLOAD_TOO_LARGE — the body is over 1 MB.
  • 422 — UNPROCESSABLE — valid JSON that could not be applied (e.g. too many active subscriptions, a value the database rejected).
  • 429 — RATE_LIMITED — over 120 requests per minute or 10,000 per day for this key (defaults). Wait Retry-After seconds.
  • 500 — INTERNAL_ERROR — unexpected error on our side. Safe to retry with backoff; quote request_id to support if it persists.
  • 503 — SERVICE_BUSY (the server is at capacity) or ELIGIBILITY_UNAVAILABLE (your plan could not be verified). Retry after Retry-After seconds (5 or 10).

Ejemplo de solicitud

curl
curl -X POST "https://app.spacekru.com/api/public/v1/subscriptions" \
  -H "Authorization: Bearer $SPACEKRU_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "event_type": "lead.created",
  "target_url": "https://hooks.zapier.com/hooks/catch/1234567/abcdefg/"
}'
Node.js
const res = await fetch('https://app.spacekru.com/api/public/v1/subscriptions', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.SPACEKRU_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "event_type": "lead.created",
    "target_url": "https://hooks.zapier.com/hooks/catch/1234567/abcdefg/"
  }),
});
const body = await res.json();
if (!res.ok) {
  // Branch on body.error.code; quote body.error.request_id to support.
  throw new Error(`${body.error.code}: ${body.error.message} (request ${body.error.request_id})`);
}
console.log(body);
Python
import os

import requests

r = requests.post(
    "https://app.spacekru.com/api/public/v1/subscriptions",
    headers={
        "Authorization": f"Bearer {os.environ['SPACEKRU_API_KEY']}",
    },
    json={
        "event_type": "lead.created",
        "target_url": "https://hooks.zapier.com/hooks/catch/1234567/abcdefg/",
    },
    timeout=30,
)
body = r.json()
if not r.ok:
    # Branch on body["error"]["code"]; quote body["error"]["request_id"] to support.
    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']} (request {body['error']['request_id']})")
print(body)
Respuesta 201
{
  "object": "subscription",
  "id": "0a1b2c3d-4e5f-4a6b-9c7d-8e9f0a1b2c3d",
  "event_type": "lead.created",
  "target_url": "https://hooks.zapier.com/hooks/catch/1234567/abcdefg/",
  "is_active": true,
  "failure_count": 0,
  "disabled_reason": null,
  "last_success_at": null,
  "created_at": "2026-10-19T14:40:00.000Z",
  "exclude_own_changes": false,
  "secret": "whsec_EXAMPLE0nlyN0tARealSecretDoNotUseIt00000"
}

Desuscribe

DELETE /subscriptions/{id} · Scope: write

Deletes the subscription permanently (any subscription of the organization, active or deactivated). Retries still pending for it are cancelled.

Scope: write (a read-only key answers 403 INSUFFICIENT_SCOPE).

ParámetroEnTipoDescripción
id (required)pathstring (uuid)The subscription id. An id that is not a UUID, or that belongs to another organization, answers 404.
Accept-LanguageheaderstringLanguage of error.message: en or es. Without it, the language of the profile of the person who created the key. Codes and field names never change.

Respuestas

  • 200 — Deleted.
  • 401 — INVALID_API_KEY — the key is missing, malformed, unknown or revoked.
  • 402 — PLAN_UPGRADE_REQUIRED — the organization is not on an active paid plan (free plan, cancelled or unpaid subscription, closed account). No grace period.
  • 403 — INSUFFICIENT_SCOPE — the key lacks the scope this operation needs.
  • 404 — NOT_FOUND — no such record in this organization (also for ids that are not UUIDs).
  • 429 — RATE_LIMITED — over 120 requests per minute or 10,000 per day for this key (defaults). Wait Retry-After seconds.
  • 500 — INTERNAL_ERROR — unexpected error on our side. Safe to retry with backoff; quote request_id to support if it persists.
  • 503 — SERVICE_BUSY (the server is at capacity) or ELIGIBILITY_UNAVAILABLE (your plan could not be verified). Retry after Retry-After seconds (5 or 10).

Ejemplo de solicitud

curl
curl -X DELETE "https://app.spacekru.com/api/public/v1/subscriptions/0a1b2c3d-4e5f-4a6b-9c7d-8e9f0a1b2c3d" \
  -H "Authorization: Bearer $SPACEKRU_API_KEY"
Node.js
const res = await fetch('https://app.spacekru.com/api/public/v1/subscriptions/0a1b2c3d-4e5f-4a6b-9c7d-8e9f0a1b2c3d', {
  method: 'DELETE',
  headers: {
    Authorization: `Bearer ${process.env.SPACEKRU_API_KEY}`,
  },
});
const body = await res.json();
if (!res.ok) {
  // Branch on body.error.code; quote body.error.request_id to support.
  throw new Error(`${body.error.code}: ${body.error.message} (request ${body.error.request_id})`);
}
console.log(body);
Python
import os

import requests

r = requests.delete(
    "https://app.spacekru.com/api/public/v1/subscriptions/0a1b2c3d-4e5f-4a6b-9c7d-8e9f0a1b2c3d",
    headers={
        "Authorization": f"Bearer {os.environ['SPACEKRU_API_KEY']}",
    },
    timeout=30,
)
body = r.json()
if not r.ok:
    # Branch on body["error"]["code"]; quote body["error"]["request_id"] to support.
    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']} (request {body['error']['request_id']})")
print(body)
Respuesta 200
{
  "object": "subscription",
  "id": "0a1b2c3d-4e5f-4a6b-9c7d-8e9f0a1b2c3d",
  "deleted": true
}

Objetos

Lead

CampoTipoDescripción
object"lead"—
idstring (uuid)—
typestringOne of: person, business.
full_namestring or null—
business_namestring or null—
job_titlestring or null—
work_emailstring or null—
personal_emailstring or null—
work_phonestring or null—
personal_phonestring or null—
company_namestring or null—
citystring or null—
countrystring or null—
statusstring or nullManaged by SpaceKru (read-only). Free text; common values: new, contacted, qualified, proposal, won.
sourcestring or nullWhere the lead came from (read-only). api for leads created through the API.
tagsarray of string—
instagram_profilestring or null—
linkedin_profile_urlstring or null—
websitestring or null—
external_idstring or nullThe id of this lead in YOUR system (unique per organization). Use it to sync without storing SpaceKru ids.
created_atstring (date-time) or nullWhen the lead was created (UTC).
updated_atstring (date-time) or nullLast change (UTC). Used by updated_since.

Deal

CampoTipoDescripción
object"deal"—
idstring (uuid)—
lead_idstring or null—
titlestring or null—
valuenumber or null—
stagestring or nullName of the pipeline stage.
statusstring or nullFree text; common values: open, won, lost.
close_datestring or nullCalendar date YYYY-MM-DD or a date-time.
lost_reasonstring or null—
stage_idstring or nullId of the pipeline stage (see GET /pipeline-stages). The reliable way to know and change the stage.
agent_idstring or nullThe AI Employee in charge of the deal (it does the follow-ups).
external_idstring or nullThe id of this deal in YOUR system.
next_step_actionstring or nullNext scheduled step, e.g. "Follow-up scheduled (WhatsApp)".
next_step_datestring (date-time) or nullWhen the next step is scheduled (UTC).
created_atstring (date-time) or nullWhen the deal was created (UTC).
updated_atstring (date-time) or nullLast change (UTC).

Cotización

CampoTipoDescripción
object"quote"—
idstring (uuid)—
numberstring or null—
lead_idstring or null—
deal_idstring or null—
statusstring or nullFree text; common values: draft, sent, accepted, rejected.
subtotalnumber or null—
tax_totalnumber or null—
shipping_costnumber or null—
discount_totalnumber or null—
totalnumber or null—
valid_untilstring or nullCalendar date, YYYY-MM-DD.
itemsarray of LineItem—
external_idstring or nullThe id of this quote in YOUR system.
notesstring or null—
payment_termsstring or null—
created_atstring (date-time) or nullWhen the quote was created (UTC).
updated_atstring (date-time) or nullLast change (UTC).

Orden

CampoTipoDescripción
object"order"—
idstring (uuid)—
numberstring or null—
quote_idstring or null—
lead_idstring or null—
deal_idstring or null—
statusstring or nullFree text; common values: draft, pending, processing, shipped, delivered, cancelled.
payment_statusstring or nullFree text; common values: unpaid, partial, paid, refunded.
subtotalnumber or null—
taxnumber or null—
shipping_costnumber or null—
totalnumber or null—
tracking_numberstring or null—
carrierstring or null—
itemsarray of LineItem—
external_idstring or nullThe id of this order in YOUR system.
delivery_typestring or nullpickup or delivery.
shipping_addressobject or null—
billing_addressobject or null—
notesstring or null—
amount_paidnumberSum of the recorded payments.
created_atstring (date-time) or nullWhen the order was created (UTC).
updated_atstring (date-time) or nullLast change (UTC).

Ítem

CampoTipoDescripción
product_idstring or null—
namestring or null—
skustring or null—
descriptionstring or null—
quantitynumber or null—
unit_pricenumber or null—
totalnumber or null—
variant_idstring or null—
tax_ratenumber or nullPercent.
discountnumber or nullPercent.

Pago

CampoTipoDescripción
object"payment"—
idstring (uuid)—
order_idstring (uuid)—
amountnumber—
payment_methodstring or null—
reference_codestring or null—
payment_datestring (date-time) or nullWhen it was paid.
created_atstring (date-time) or nullWhen it was recorded.
order_payment_statusstring or nullunpaid, partial or paid after this payment.

Producto

CampoTipoDescripción
object"product"—
idstring (uuid)—
namestring—
skustring or null—
reference_codestring or null—
categorystring or null—
descriptionstring or null—
brandstring or null—
pricenumber or null—
sale_pricenumber or null—
currencystring or nullISO 4217, e.g. USD, COP, MXN.
stock_quantityinteger or null—
track_stockboolean—
statusstringOne of: active, draft, archived.
imagesarray of string—
urlstring or null—
min_order_quantityinteger or null—
has_variantsboolean—
variantsarray of ProductVariant—
external_idstring or null—
created_atstring (date-time) or nullCreated (UTC).
updated_atstring (date-time) or nullLast change (UTC).

Variante de producto

CampoTipoDescripción
object"product_variant"—
idstring (uuid)—
skustring or null—
titlestring or null—
pricenumber or null—
stock_quantityinteger or null—
attributesobject or null—

Empleado de IA

CampoTipoDescripción
object"agent"—
idstring (uuid)—
namestring—
rolestringcustomer_service, prospector, community_manager…
statusstring or null—
languagestring or null—
channelsarray of stringChannels turned on: whatsapp, email, web_chat, instagram…

Etapa del pipeline

CampoTipoDescripción
object"pipeline_stage"—
idstring (uuid)—
namestring—
typestringOne of: OPEN, WON, LOST.
positioninteger—

Campaña

CampoTipoDescripción
object"campaign"—
idstring (uuid)—
namestring or null—
typestringprospecting, recontact, inbound, email_marketing, whatsapp_marketing…
statusstring—
agent_idstring or null—
channelsarray of string—
enrollablebooleantrue = leads can be added with POST /campaigns/{id}/leads.
created_atstring (date-time) or nullWhen the campaign was created (UTC).

Inscripción

CampoTipoDescripción
object"enrollment"—
campaign_idstring (uuid)—
dry_runboolean—
requestedinteger—
enrolledintegerAdded (or that would be added, on a dry run).
already_in_campaigninteger—
excludedinteger—
excluded_lead_idsarray of string (uuid)—
reasonsobject—

Lead de campaña

A lead inside one of your campaigns. Only delivered by the campaign_lead.* webhooks.

CampoTipoDescripción
object"campaign_lead"—
idstring (uuid)—
campaign_idstring (uuid)—
lead_idstring or null—
statusstring or nullStatus inside the campaign. Free text; common values: new, contacted, replied, awaiting_supervisor, converted, not_interested, closed_unresponsive.
form_submitted_atstring (date-time) or nullWhen the lead submitted the campaign form, if it did.
leadLead or any or nullThe lead itself.

Seguimiento

CampoTipoDescripción
object"follow_up"—
deal_idstring (uuid)—
scheduled_message_idstring (uuid)—
scheduled_atstring (date-time)Adjusted to the working hours of the AI Employee.
channelstringOne of: whatsapp, email.

Recurso de reserva

CampoTipoDescripción
object"booking_resource"—
idstring (uuid)—
namestring—
capacityinteger or null—
categorystring or null—
zonestring or null—
is_activeboolean—
min_slot_durationinteger or nullMinutes.

Horario disponible

CampoTipoDescripción
object"availability_slot"—
start_timestring (date-time)—
end_timestring (date-time)—
resourceobject—

Reserva

CampoTipoDescripción
object"booking"—
idstring (uuid)—
resource_idstring or null—
lead_idstring or null—
start_timestring (date-time)—
end_timestring (date-time)—
statusstringOne of: confirmed, cancelled, seated, completed.
party_sizeinteger or null—
notesstring or null—
meeting_urlstring or null—
external_idstring or null—
created_atstring (date-time) or nullCreated (UTC).
updated_atstring (date-time) or nullLast change (UTC).

Conversación

CampoTipoDescripción
object"conversation"—
idstring (uuid)—
lead_idstring or null—
statusstringOne of: open, closed.
external_conversation_idstring or null—
localestring or null—
message_countinteger—
last_activity_atstring (date-time) or nullLast message (UTC).
created_atstring (date-time) or nullOpened (UTC).

Mensaje de conversación

CampoTipoDescripción
object"conversation_message"—
idstring (uuid)—
conversation_idstring (uuid)—
rolestringcontact = your customer, agent = the AI Employee, human = a person replying from the SpaceKru Inbox. One of: contact, agent, human.
textstring or null—
created_atstring (date-time) or nullWhen it was written (UTC).

Turno de conversación

CampoTipoDescripción
object"conversation_turn"—
conversation_idstring (uuid)—
messagesarray of ConversationMessageThe AI Employee's replies to this message (it can send more than one).
deferredbooleantrue = no reply now.
deferred_reasonstring or nullOne of: no_inbound_campaign, agent_not_ready, replies_disabled, message_filtered, campaign_inactive, no_reply.

Suscripción

CampoTipoDescripción
object"subscription"—
idstring (uuid)—
event_typestringOne of: lead.created, lead.updated, deal.created, deal.stage_changed, deal.updated, quote.created, quote.status_changed, order.created, order.status_changed, campaign_lead.replied, campaign_lead.form_submitted, product.created, product.updated, booking.created, booking.updated, conversation.message_created.
target_urlstring—
is_activebooleanfalse once deactivated (see disabled_reason). A deactivated subscription is never reactivated: delete it and create a new one.
failure_countintegerConsecutive failed delivery attempts. Any success resets it to 0.
disabled_reasonstring or nullWhy it was deactivated: target_gone_410 — Your endpoint answered 410 Gone. disabled_after_20_consecutive_failures — Too many consecutive failed delivery attempts (the number is in the value, e.g. disabled_after_20_consecutive_failures). key_revoked — The API key that created the subscription was revoked.
last_success_atstring (date-time) or nullLast successful delivery.
created_atstring (date-time)—
exclude_own_changesbooleantrue = changes made with the API key that created this subscription are not delivered to it (no echo in two-way syncs).

Nota

CampoTipoDescripción
object"note"—
idstring—
lead_idstring—
contentstring—
created_atstring (date-time) or nullWhen the note was added (UTC).

Error

The only error shape of the API.

CampoTipoDescripción
error (required)object—

Eventos de webhook

Cada evento se envía por POST a la target_url de sus suscripciones. Firmas, reintentos y garantías: Webhooks.

lead.created

Se dispara cuando: Se crea un lead desde cualquier origen: la app, una importación CSV, un formulario, el Lead Finder, un mensaje entrante o la API.

`changes`: {} (siempre vacío).

Contenido
{
  "id": "e4d3c2b1-a098-4765-8432-10fedcba9876",
  "event": "lead.created",
  "occurred_at": "2026-10-19T14:32:11.000Z",
  "organization_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "changes": {},
  "triggered_by": {
    "type": "api",
    "api_key_id": "0b6c1d2e-3f4a-4b5c-9d6e-7f8a9b0c1d2e"
  },
  "data": {
    "object": "lead",
    "id": "3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
    "type": "person",
    "full_name": "Maria Lopez",
    "business_name": null,
    "job_title": "Operations Manager",
    "work_email": "maria.lopez@example.com",
    "personal_email": null,
    "work_phone": "+13055550142",
    "personal_phone": null,
    "company_name": "Acme Corp",
    "city": "Miami",
    "country": "United States",
    "status": "new",
    "source": "api",
    "tags": [
      "typeform",
      "spring-promo"
    ],
    "instagram_profile": null,
    "linkedin_profile_url": null,
    "website": null,
    "external_id": "crm-88412",
    "created_at": "2026-10-19T14:32:10.000Z",
    "updated_at": "2026-10-19T14:32:10.000Z"
  }
}

lead.updated

Se dispara cuando: Cambia uno de estos campos de un lead: type, full_name, business_name, job_title, work_email, personal_email, work_phone, personal_phone, company_name, status, tags, city, country, instagram_profile, linkedin_profile_url, website, external_id. Los cambios en cualquier otro campo (por ejemplo, contadores internos de seguimiento) nunca lo disparan.

`changes`: { "campo": [antes, después] } por cada campo que cambió. Los valores son los guardados tal cual (por ejemplo tags como se almacena), y solo aparecen esos 17 campos.

Contenido
{
  "id": "e4d3c2b1-a098-4765-8432-10fedcba9876",
  "event": "lead.updated",
  "occurred_at": "2026-10-19T14:32:11.000Z",
  "organization_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "changes": {
    "status": [
      "new",
      "contacted"
    ],
    "job_title": [
      "Operations Manager",
      "Head of Operations"
    ]
  },
  "triggered_by": {
    "type": "app",
    "api_key_id": null
  },
  "data": {
    "object": "lead",
    "id": "3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
    "type": "person",
    "full_name": "Maria Lopez",
    "business_name": null,
    "job_title": "Head of Operations",
    "work_email": "maria.lopez@example.com",
    "personal_email": null,
    "work_phone": "+13055550142",
    "personal_phone": null,
    "company_name": "Acme Corp",
    "city": "Miami",
    "country": "United States",
    "status": "contacted",
    "source": "api",
    "tags": [
      "typeform",
      "spring-promo"
    ],
    "instagram_profile": null,
    "linkedin_profile_url": null,
    "website": null,
    "external_id": "crm-88412",
    "created_at": "2026-10-19T14:32:10.000Z",
    "updated_at": "2026-10-19T14:32:10.000Z"
  }
}

deal.created

Se dispara cuando: Se crea un deal: en la app, por un Empleado de IA, desde una cotización o por la API.

`changes`: {} (siempre vacío).

Contenido
{
  "id": "e4d3c2b1-a098-4765-8432-10fedcba9876",
  "event": "deal.created",
  "occurred_at": "2026-10-19T14:32:11.000Z",
  "organization_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "changes": {},
  "triggered_by": {
    "type": "api",
    "api_key_id": "0b6c1d2e-3f4a-4b5c-9d6e-7f8a9b0c1d2e"
  },
  "data": {
    "object": "deal",
    "id": "8d1e2f3a-4b5c-4d6e-8f70-9a1b2c3d4e5f",
    "lead_id": "3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
    "title": "Acme Corp — 3 locations",
    "value": 4800,
    "stage": "Proposal",
    "status": "open",
    "close_date": "2026-11-30",
    "lost_reason": null,
    "stage_id": "c3d4e5f6-a7b8-4c9d-8e0f-2a3b4c5d6e7f",
    "agent_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5e",
    "external_id": "opp-5521",
    "next_step_action": "Follow-up scheduled (WhatsApp)",
    "next_step_date": "2026-10-24T15:00:00.000Z",
    "created_at": "2026-10-20T09:15:00.000Z",
    "updated_at": "2026-10-22T16:40:12.000Z"
  }
}

deal.stage_changed

Se dispara cuando: Cambia la etapa del pipeline de un deal, o su estado (open, won, lost). Úsalo para "deal ganado" y "deal perdido".

`changes`: stage, stage_id y/o status, cada uno como [antes, después].

Contenido
{
  "id": "e4d3c2b1-a098-4765-8432-10fedcba9876",
  "event": "deal.stage_changed",
  "occurred_at": "2026-10-19T14:32:11.000Z",
  "organization_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "changes": {
    "stage": [
      "Proposal",
      "Won"
    ],
    "stage_id": [
      "c3d4e5f6-a7b8-4c9d-8e0f-2a3b4c5d6e7f",
      "d4e5f6a7-b8c9-4d0e-9f1a-3b4c5d6e7f80"
    ],
    "status": [
      "open",
      "won"
    ]
  },
  "triggered_by": {
    "type": "app",
    "api_key_id": null
  },
  "data": {
    "object": "deal",
    "id": "8d1e2f3a-4b5c-4d6e-8f70-9a1b2c3d4e5f",
    "lead_id": "3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
    "title": "Acme Corp — 3 locations",
    "value": 5200,
    "stage": "Won",
    "status": "won",
    "close_date": "2026-10-28T17:02:00.000Z",
    "lost_reason": null,
    "stage_id": "d4e5f6a7-b8c9-4d0e-9f1a-3b4c5d6e7f80",
    "agent_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5e",
    "external_id": "opp-5521",
    "next_step_action": null,
    "next_step_date": null,
    "created_at": "2026-10-20T09:15:00.000Z",
    "updated_at": "2026-10-28T17:02:00.000Z"
  }
}

deal.updated

Se dispara cuando: Cambia uno de estos campos guardados de un deal SIN cambio de etapa ni de estado: deal_title, deal_value, agent_id, close_date, lost_reason, next_step_action, next_step_date, external_id. (deal_title y deal_value son title y value en el objeto Deal.)

`changes`: { "campo": [antes, después] } con los nombres de campo guardados de la lista anterior.

Contenido
{
  "id": "e4d3c2b1-a098-4765-8432-10fedcba9876",
  "event": "deal.updated",
  "occurred_at": "2026-10-19T14:32:11.000Z",
  "organization_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "changes": {
    "deal_value": [
      4800,
      5200
    ]
  },
  "triggered_by": {
    "type": "app",
    "api_key_id": null
  },
  "data": {
    "object": "deal",
    "id": "8d1e2f3a-4b5c-4d6e-8f70-9a1b2c3d4e5f",
    "lead_id": "3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
    "title": "Acme Corp — 3 locations",
    "value": 5200,
    "stage": "Proposal",
    "status": "open",
    "close_date": "2026-11-30",
    "lost_reason": null,
    "stage_id": "c3d4e5f6-a7b8-4c9d-8e0f-2a3b4c5d6e7f",
    "agent_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5e",
    "external_id": "opp-5521",
    "next_step_action": "Follow-up scheduled (WhatsApp)",
    "next_step_date": "2026-10-24T15:00:00.000Z",
    "created_at": "2026-10-20T09:15:00.000Z",
    "updated_at": "2026-10-22T16:40:12.000Z"
  }
}

quote.created

Se dispara cuando: Se crea una cotización.

`changes`: {} (siempre vacío).

Contenido
{
  "id": "e4d3c2b1-a098-4765-8432-10fedcba9876",
  "event": "quote.created",
  "occurred_at": "2026-10-19T14:32:11.000Z",
  "organization_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "changes": {},
  "triggered_by": {
    "type": "app",
    "api_key_id": null
  },
  "data": {
    "object": "quote",
    "id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
    "number": "Q-1042",
    "lead_id": "3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
    "deal_id": "8d1e2f3a-4b5c-4d6e-8f70-9a1b2c3d4e5f",
    "status": "sent",
    "subtotal": 1200,
    "tax_total": 84,
    "shipping_cost": 0,
    "discount_total": 0,
    "total": 1284,
    "valid_until": "2026-11-15",
    "items": [
      {
        "product_id": "2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f",
        "name": "Annual plan — per location",
        "sku": "PLAN-LOC-12",
        "description": null,
        "quantity": 3,
        "unit_price": 400,
        "total": 1284,
        "variant_id": null,
        "tax_rate": 7,
        "discount": 0
      }
    ],
    "external_id": "qt-7781",
    "notes": "Prices valid for the 2026 rollout.",
    "payment_terms": "Net 15",
    "created_at": "2026-10-22T16:45:00.000Z",
    "updated_at": "2026-10-22T16:47:31.000Z"
  }
}

quote.status_changed

Se dispara cuando: Cambia el estado de una cotización (por ejemplo de sent a accepted).

`changes`: status como [antes, después].

Contenido
{
  "id": "e4d3c2b1-a098-4765-8432-10fedcba9876",
  "event": "quote.status_changed",
  "occurred_at": "2026-10-19T14:32:11.000Z",
  "organization_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "changes": {
    "status": [
      "sent",
      "accepted"
    ]
  },
  "triggered_by": {
    "type": "app",
    "api_key_id": null
  },
  "data": {
    "object": "quote",
    "id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
    "number": "Q-1042",
    "lead_id": "3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
    "deal_id": "8d1e2f3a-4b5c-4d6e-8f70-9a1b2c3d4e5f",
    "status": "accepted",
    "subtotal": 1200,
    "tax_total": 84,
    "shipping_cost": 0,
    "discount_total": 0,
    "total": 1284,
    "valid_until": "2026-11-15",
    "items": [
      {
        "product_id": "2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f",
        "name": "Annual plan — per location",
        "sku": "PLAN-LOC-12",
        "description": null,
        "quantity": 3,
        "unit_price": 400,
        "total": 1284,
        "variant_id": null,
        "tax_rate": 7,
        "discount": 0
      }
    ],
    "external_id": "qt-7781",
    "notes": "Prices valid for the 2026 rollout.",
    "payment_terms": "Net 15",
    "created_at": "2026-10-22T16:45:00.000Z",
    "updated_at": "2026-10-22T16:47:31.000Z"
  }
}

order.created

Se dispara cuando: Se crea una orden.

`changes`: {} (siempre vacío).

Contenido
{
  "id": "e4d3c2b1-a098-4765-8432-10fedcba9876",
  "event": "order.created",
  "occurred_at": "2026-10-19T14:32:11.000Z",
  "organization_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "changes": {},
  "triggered_by": {
    "type": "app",
    "api_key_id": null
  },
  "data": {
    "object": "order",
    "id": "9f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a",
    "number": "ORD-2088",
    "quote_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
    "lead_id": "3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
    "deal_id": "8d1e2f3a-4b5c-4d6e-8f70-9a1b2c3d4e5f",
    "status": "pending",
    "payment_status": "unpaid",
    "subtotal": 1200,
    "tax": 84,
    "shipping_cost": 0,
    "total": 1284,
    "tracking_number": null,
    "carrier": null,
    "items": [
      {
        "product_id": "2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f",
        "name": "Annual plan — per location",
        "sku": "PLAN-LOC-12",
        "description": null,
        "quantity": 3,
        "unit_price": 400,
        "total": 1284,
        "variant_id": null,
        "tax_rate": 7,
        "discount": 0
      }
    ],
    "external_id": "erp-so-3310",
    "delivery_type": "pickup",
    "shipping_address": null,
    "billing_address": null,
    "notes": null,
    "amount_paid": 0,
    "created_at": "2026-10-24T10:05:00.000Z",
    "updated_at": "2026-10-24T18:20:09.000Z"
  }
}

order.status_changed

Se dispara cuando: Cambia el estado de una orden, o su estado de pago (por ejemplo a paid).

`changes`: status y/o payment_status, cada uno como [antes, después].

Contenido
{
  "id": "e4d3c2b1-a098-4765-8432-10fedcba9876",
  "event": "order.status_changed",
  "occurred_at": "2026-10-19T14:32:11.000Z",
  "organization_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "changes": {
    "payment_status": [
      "unpaid",
      "paid"
    ]
  },
  "triggered_by": {
    "type": "app",
    "api_key_id": null
  },
  "data": {
    "object": "order",
    "id": "9f8e7d6c-5b4a-4392-8170-6f5e4d3c2b1a",
    "number": "ORD-2088",
    "quote_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
    "lead_id": "3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
    "deal_id": "8d1e2f3a-4b5c-4d6e-8f70-9a1b2c3d4e5f",
    "status": "processing",
    "payment_status": "paid",
    "subtotal": 1200,
    "tax": 84,
    "shipping_cost": 0,
    "total": 1284,
    "tracking_number": null,
    "carrier": null,
    "items": [
      {
        "product_id": "2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f",
        "name": "Annual plan — per location",
        "sku": "PLAN-LOC-12",
        "description": null,
        "quantity": 3,
        "unit_price": 400,
        "total": 1284,
        "variant_id": null,
        "tax_rate": 7,
        "discount": 0
      }
    ],
    "external_id": "erp-so-3310",
    "delivery_type": "pickup",
    "shipping_address": null,
    "billing_address": null,
    "notes": null,
    "amount_paid": 1284,
    "created_at": "2026-10-24T10:05:00.000Z",
    "updated_at": "2026-10-24T18:20:09.000Z"
  }
}

campaign_lead.replied

Se dispara cuando: Un lead de una de tus campañas responde (su estado en la campaña pasa a replied).

`changes`: status como [antes, "replied"].

Contenido
{
  "id": "e4d3c2b1-a098-4765-8432-10fedcba9876",
  "event": "campaign_lead.replied",
  "occurred_at": "2026-10-19T14:32:11.000Z",
  "organization_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "changes": {
    "status": [
      "contacted",
      "replied"
    ]
  },
  "triggered_by": {
    "type": "app",
    "api_key_id": null
  },
  "data": {
    "object": "campaign_lead",
    "id": "6b7c8d9e-0f1a-4b2c-9d3e-4f5a6b7c8d9e",
    "campaign_id": "4e5f6a7b-8c9d-4e0f-a1b2-c3d4e5f6a7b8",
    "lead_id": "3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
    "status": "replied",
    "form_submitted_at": null,
    "lead": {
      "object": "lead",
      "id": "3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
      "type": "person",
      "full_name": "Maria Lopez",
      "business_name": null,
      "job_title": "Operations Manager",
      "work_email": "maria.lopez@example.com",
      "personal_email": null,
      "work_phone": "+13055550142",
      "personal_phone": null,
      "company_name": "Acme Corp",
      "city": "Miami",
      "country": "United States",
      "status": "new",
      "source": "api",
      "tags": [
        "typeform",
        "spring-promo"
      ],
      "instagram_profile": null,
      "linkedin_profile_url": null,
      "website": null,
      "external_id": "crm-88412",
      "created_at": "2026-10-19T14:32:10.000Z",
      "updated_at": "2026-10-19T14:32:10.000Z"
    }
  }
}

campaign_lead.form_submitted

Se dispara cuando: Un lead de una de tus campañas envía el formulario de la campaña.

`changes`: {} (siempre vacío). data.form_submitted_at trae la hora.

Contenido
{
  "id": "e4d3c2b1-a098-4765-8432-10fedcba9876",
  "event": "campaign_lead.form_submitted",
  "occurred_at": "2026-10-19T14:32:11.000Z",
  "organization_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "changes": {},
  "triggered_by": {
    "type": "app",
    "api_key_id": null
  },
  "data": {
    "object": "campaign_lead",
    "id": "6b7c8d9e-0f1a-4b2c-9d3e-4f5a6b7c8d9e",
    "campaign_id": "4e5f6a7b-8c9d-4e0f-a1b2-c3d4e5f6a7b8",
    "lead_id": "3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
    "status": "contacted",
    "form_submitted_at": "2026-10-19T14:31:58.000Z",
    "lead": {
      "object": "lead",
      "id": "3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
      "type": "person",
      "full_name": "Maria Lopez",
      "business_name": null,
      "job_title": "Operations Manager",
      "work_email": "maria.lopez@example.com",
      "personal_email": null,
      "work_phone": "+13055550142",
      "personal_phone": null,
      "company_name": "Acme Corp",
      "city": "Miami",
      "country": "United States",
      "status": "new",
      "source": "api",
      "tags": [
        "typeform",
        "spring-promo"
      ],
      "instagram_profile": null,
      "linkedin_profile_url": null,
      "website": null,
      "external_id": "crm-88412",
      "created_at": "2026-10-19T14:32:10.000Z",
      "updated_at": "2026-10-19T14:32:10.000Z"
    }
  }
}

product.created

Se dispara cuando: Se crea un producto: en la app, por importación CSV, por un Empleado de IA o por la API.

`changes`: {} (siempre vacío).

Contenido
{
  "id": "e4d3c2b1-a098-4765-8432-10fedcba9876",
  "event": "product.created",
  "occurred_at": "2026-10-19T14:32:11.000Z",
  "organization_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "changes": {},
  "triggered_by": {
    "type": "app",
    "api_key_id": null
  },
  "data": {
    "object": "product",
    "id": "2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f",
    "name": "Dining chair",
    "sku": "CHAIR-OAK",
    "reference_code": null,
    "category": "Furniture",
    "description": "Solid oak dining chair.",
    "brand": "Acme Home",
    "price": 199,
    "sale_price": 179,
    "currency": "USD",
    "stock_quantity": 40,
    "track_stock": true,
    "status": "active",
    "images": [
      "https://cdn.example.com/chair.jpg"
    ],
    "url": "https://shop.example.com/chair",
    "min_order_quantity": 1,
    "has_variants": true,
    "variants": [
      {
        "object": "product_variant",
        "id": "7a8b9c0d-1e2f-4a3b-8c4d-5e6f7a8b9c0d",
        "sku": "CHAIR-OAK-BLK",
        "title": "Oak / Black",
        "price": 189,
        "stock_quantity": 12,
        "attributes": {
          "wood": "Oak",
          "color": "Black"
        }
      }
    ],
    "external_id": "sku-88731",
    "created_at": "2026-09-02T12:00:00.000Z",
    "updated_at": "2026-10-19T09:30:00.000Z"
  }
}

product.updated

Se dispara cuando: Cambia uno de estos campos de un producto: name, sku, reference_code, category, description, brand, price, sale_price, currency, stock_quantity, track_stock, status, images, url, min_order_quantity, external_id. Los cambios de variantes no lo disparan.

`changes`: { "campo": [antes, después] } por cada campo que cambió.

Contenido
{
  "id": "e4d3c2b1-a098-4765-8432-10fedcba9876",
  "event": "product.updated",
  "occurred_at": "2026-10-19T14:32:11.000Z",
  "organization_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "changes": {
    "stock_quantity": [
      40,
      35
    ]
  },
  "triggered_by": {
    "type": "app",
    "api_key_id": null
  },
  "data": {
    "object": "product",
    "id": "2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f",
    "name": "Dining chair",
    "sku": "CHAIR-OAK",
    "reference_code": null,
    "category": "Furniture",
    "description": "Solid oak dining chair.",
    "brand": "Acme Home",
    "price": 199,
    "sale_price": 179,
    "currency": "USD",
    "stock_quantity": 35,
    "track_stock": true,
    "status": "active",
    "images": [
      "https://cdn.example.com/chair.jpg"
    ],
    "url": "https://shop.example.com/chair",
    "min_order_quantity": 1,
    "has_variants": true,
    "variants": [
      {
        "object": "product_variant",
        "id": "7a8b9c0d-1e2f-4a3b-8c4d-5e6f7a8b9c0d",
        "sku": "CHAIR-OAK-BLK",
        "title": "Oak / Black",
        "price": 189,
        "stock_quantity": 12,
        "attributes": {
          "wood": "Oak",
          "color": "Black"
        }
      }
    ],
    "external_id": "sku-88731",
    "created_at": "2026-09-02T12:00:00.000Z",
    "updated_at": "2026-10-19T09:30:00.000Z"
  }
}

booking.created

Se dispara cuando: Se crea una reserva: en la app, por un Empleado de IA o por la API.

`changes`: {} (siempre vacío).

Contenido
{
  "id": "e4d3c2b1-a098-4765-8432-10fedcba9876",
  "event": "booking.created",
  "occurred_at": "2026-10-19T14:32:11.000Z",
  "organization_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "changes": {},
  "triggered_by": {
    "type": "api",
    "api_key_id": "0b6c1d2e-3f4a-4b5c-9d6e-7f8a9b0c1d2e"
  },
  "data": {
    "object": "booking",
    "id": "f6a7b8c9-d0e1-4f2a-9b3c-5d6e7f809102",
    "resource_id": "e5f6a7b8-c9d0-4e1f-8a2b-4c5d6e7f8091",
    "lead_id": "3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
    "start_time": "2026-10-25T00:00:00.000Z",
    "end_time": "2026-10-25T01:30:00.000Z",
    "status": "confirmed",
    "party_size": 4,
    "notes": "Birthday",
    "meeting_url": null,
    "external_id": "pos-res-1042",
    "created_at": "2026-10-20T14:00:00.000Z",
    "updated_at": "2026-10-20T14:00:00.000Z"
  }
}

booking.updated

Se dispara cuando: Cambia uno de estos campos de una reserva: resource_id, lead_id, start_time, end_time, status, party_size, notes, meeting_url, external_id.

`changes`: { "campo": [antes, después] } por cada campo que cambió.

Contenido
{
  "id": "e4d3c2b1-a098-4765-8432-10fedcba9876",
  "event": "booking.updated",
  "occurred_at": "2026-10-19T14:32:11.000Z",
  "organization_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "changes": {
    "status": [
      "confirmed",
      "seated"
    ]
  },
  "triggered_by": {
    "type": "app",
    "api_key_id": null
  },
  "data": {
    "object": "booking",
    "id": "f6a7b8c9-d0e1-4f2a-9b3c-5d6e7f809102",
    "resource_id": "e5f6a7b8-c9d0-4e1f-8a2b-4c5d6e7f8091",
    "lead_id": "3f2b8c1e-9a4d-4e6f-b7a8-1c2d3e4f5a6b",
    "start_time": "2026-10-25T00:00:00.000Z",
    "end_time": "2026-10-25T01:30:00.000Z",
    "status": "seated",
    "party_size": 4,
    "notes": "Birthday",
    "meeting_url": null,
    "external_id": "pos-res-1042",
    "created_at": "2026-10-20T14:00:00.000Z",
    "updated_at": "2026-10-20T14:00:00.000Z"
  }
}

conversation.message_created

Se dispara cuando: El Empleado de IA, o una persona que responde desde el Inbox, escribe en una conversación abierta por la API.

`changes`: {} (siempre vacío).

Contenido
{
  "id": "e4d3c2b1-a098-4765-8432-10fedcba9876",
  "event": "conversation.message_created",
  "occurred_at": "2026-10-19T14:32:11.000Z",
  "organization_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "changes": {},
  "triggered_by": {
    "type": "app",
    "api_key_id": null
  },
  "data": {
    "object": "conversation_message",
    "id": "29304b5c-6d7e-4f80-91a2-b3c4d5e6f708",
    "conversation_id": "18293a4b-5c6d-4e7f-8091-a2b3c4d5e6f7",
    "role": "human",
    "text": "Hi Maria, this is Ana from the team. Your table is ready.",
    "created_at": "2026-10-20T15:00:06.000Z"
  }
}