API Pública de Vendty (1.0.0)

Download OpenAPI specification:

Introducción

API pública de Vendty para integraciones con partners, ERPs y aplicaciones a medida. REST · JSON · OAuth2 (Personal Access Tokens con scopes).

Estado actual

  • URL base de producción: https://api-pub.vendty.com/v1
  • Fase 1 (lectura): Productos, Categorías, identidad del cliente API (/v1/me), health — en producción
  • Fase 2 (lectura): Clientes (terceros), Ventas con detalles y pagos, Métodos de pago, Grupos de clientes — en producción
  • Fase 3: Mutaciones (POST/PATCH), Webhooks, Developer Portal — planeado

Lo que ofrece

Seguridad por defecto

  • HTTPS obligatorio, HSTS, IDs opacos (sin enumeración secuencial).
  • Límites de uso por cliente con planes (Básico / Pro / Empresarial).
  • Auditoría de todas las llamadas: tanto las exitosas como las fallidas.
  • Usuarios MySQL solo de lectura por negocio — un token de lectura filtrado no puede modificar nada.

Contrato estable

Una vez publicada una versión bajo /v1/, el contrato se preserva: no se eliminan endpoints, no se quitan campos, no se cambian tipos. Los cambios incompatibles van a /v2/.

Pensada para integraciones reales

  • Paginación amistosa (per_page hasta 200, links.next para iterar).
  • Sincronización incremental con ?updated_since.
  • Idempotency keys obligatorias en cada mutación (cuando Fase 3 entregue las escrituras).

Soporte

Si tienes problemas con tu integración: incluye siempre el header X-Request-Id de la respuesta cuando contactes a tu representante de Vendty. Con ese ID ubicamos la llamada exacta en menos de un minuto.

Inicio rápido — API Pública de Vendty v1

En 5 minutos haces tu primera llamada autenticada a la API y confirmas que tus credenciales funcionan.

Lo que necesitas

  • Un Bearer token emitido a tu aplicación por Vendty. Si todavía no tienes uno, tu representante de Vendty registra un ApiClient para tu negocio y te entrega un token. Los tokens se muestran una sola vez al emitirlos — guárdalo en un lugar seguro (gestor de contraseñas, vault, no en el repositorio de tu aplicación).
  • curl o cualquier cliente HTTP.

1. Verifica que tu token funciona

curl -s https://api-pub.vendty.com/v1/me \
  -H "Authorization: Bearer TU_TOKEN_AQUI"

Respuesta esperada (HTTP 200):

{
  "data": {
    "id": "8d3b1bff-…",
    "name": "Mi aplicación",
    "rate_tier": "basic",
    "scopes": [],
    "allowed_origins": [],
    "created_at": "2026-05-11T18:35:00+00:00"
  },
  "meta": { "request_id": "f7ad…" }
}

Si recibes 401 unauthenticated → el token está mal, expiró o fue revocado. Contacta a Vendty.

Si recibes 403 tenant_not_enabled → tu negocio aún no ha completado el alta para la API. Contacta a Vendty.

2. Revisa tus permisos (scopes)

El campo data.scopes te dice qué puede hacer tu token. Los permisos más comunes:

Scope Permite
products:read Leer el catálogo de productos
customers:read Leer los clientes (terceros)
sales:read Leer las ventas
sales:write Crear ventas
reports:read Leer informes agregados

Si el arreglo data.scopes viene vacío, tu token solo puede llamar a /v1/me y /v1/health. Para usar endpoints de negocio pídele a Vendty un token con los scopes que necesitas.

3. Lee los headers de cada respuesta

4. Las llamadas que mutan requieren <code>Idempotency-Key</code>

3. Lee los headers de cada respuesta

Todas las respuestas incluyen:

Header Significado
X-Request-Id Identificador único de esta petición — úsalo al reportar incidencias
X-RateLimit-Limit Límite por minuto de tu plan
X-RateLimit-Remaining Cuántas llamadas te quedan en la ventana actual
X-RateLimit-Reset Marca de tiempo (Unix) en que se reinicia el contador

4. Las llamadas que mutan requieren Idempotency-Key

Cada POST, PATCH, PUT o DELETE debe llevar el header Idempotency-Key con un UUID v4. Si repites la misma llamada con la misma key (dentro de 24 h) recibes la respuesta original — sirve para reintentar de forma segura ante caídas de red.

curl -X POST https://api-pub.vendty.com/v1/customers \
  -H "Authorization: Bearer TU_TOKEN_AQUI" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "identification_type": "NIT",
    "identification": "900123456",
    "business_name": "Distribuidora ACME SAS",
    "country": "CO"
  }'

Nota: los endpoints de escritura llegan con Phase 2/3. En este momento (Phase 1) solo están disponibles las lecturas de productos y categorías.

5. Errores

Todos los errores siguen el mismo formato:

{
  "error": {
    "code": "validation_failed",
    "message": "La información proporcionada no es válida.",
    "details": { "fields": { "email": ["El campo email debe ser una dirección válida."] } },
    "request_id": "f7ad…"
  }
}

Programa tu lógica contra error.code (estable, legible por máquina). El campo error.message es para humanos y puede cambiar.

Siguientes pasos

Autenticación — v1

Bearer tokens

Toda llamada a /v1/* (excepto /v1/health) debe llevar un token Bearer de Passport en el header Authorization:

Authorization: Bearer tu_token

Los tokens los emite Vendty — no hay endpoint público de registro ni de login. Para obtener un token, contacta a tu representante de Vendty.

Propiedades del token

Un token tiene:

  • Un cliente — la aplicación (ApiClient) a la que pertenece.
  • Una etiqueta — nombre legible (ej. "Producción Siigo 2026") para identificarlo en los logs de auditoría.
  • Scopes — qué puede hacer (ver más abajo).
  • Una fecha de expiración — normalmente 365 días. Los tokens expirados devuelven 401 unauthenticated.

Puedes inspeccionar tu token activo con GET /v1/me.

Scopes (permisos)

Los tokens llevan cero o más scopes del catálogo. Por defecto un token no trae ningún scope — cada endpoint exige al menos uno. Pedir un scope que no tienes devuelve 403 scope_missing.

Scope Endpoints
products:read GET /v1/products, GET /v1/categories
products:write POST /v1/products, PATCH /v1/products/{id} (Phase 2)
customers:read GET /v1/customers, GET /v1/customer-groups
customers:write POST /v1/customers, PATCH /v1/customers/{id}
sales:read GET /v1/sales, GET /v1/payment-methods
sales:write POST /v1/sales
reports:read GET /v1/reports/*
credit-notes:read/write (Phase 2)
voids:write (Phase 2)
inventory:read/write (Phase 2)
webhooks:manage (Phase 3)

Ciclo de vida del token

Operación Quién Cómo
Crear cliente Operador Vendty php artisan api:client:create (una vez por aplicación)
Emitir token Operador Vendty php artisan api:token:issue — el bearer se muestra una sola vez
Inspeccionar GET /v1/me
Revocar Operador Vendty php artisan api:token:revoke
Rotar Tú vía Vendty Pides un token nuevo; el viejo se revoca al entregarte el nuevo

Cómo guardar tu token con seguridad

  • Nunca subas un token al control de versiones (Git). Usa variables de entorno o un gestor de secretos.
  • Nunca lo registres en logs. Si necesitas correlacionar, registra el request_id.
  • Trátalo como una contraseña — si crees que fue filtrado, solicita rotación inmediatamente.

CORS

Si llamas a la API desde un navegador, el origen de tu aplicación debe estar en la lista permitida (allowed_origins) de tu cliente. No se permiten comodines (*). Envía a Vendty los dominios desde los que vas a llamar cuando pidas tu token.

Cuando algo falla

HTTP code Significado
401 unauthenticated Token ausente, mal formado, expirado o revocado
403 scope_missing El token no tiene el scope que ese endpoint requiere
403 client_suspended Tu ApiClient está suspendido — contacta a Vendty
403 tenant_not_enabled Tu negocio aún no está habilitado para la API pública
429 rate_limit_exceeded Bajá la tasa de llamadas — ver header Retry-After

Catálogo de errores — v1

Todas las respuestas no-2xx siguen este formato:

{
  "error": {
    "code": "<string_estable_legible_por_maquina>",
    "message": "<texto_para_humanos>",
    "details": { ... opcional ... },
    "request_id": "<uuid>"
  }
}

error.code es el contrato. Es estable entre versiones. error.message es para humanos y puede cambiar en cualquier momento.

Replays vs nuevas peticiones

Una respuesta con header Idempotent-Replay: true es una copia exacta de la respuesta original asociada al mismo Idempotency-Key. Trátala igual que la primera respuesta.

Cómo reaccionar

  • Toma error.code como única fuente de verdad para tu lógica de cliente. Compara contra el string; no parsees error.message.
  • Siempre registra request_id. Cuando contactes a soporte de Vendty, es el dato más útil.
  • Política de reintentos: 429 y 503 son razonables para reintentar con backoff. El resto de 4xx no se reintentan — corrige tu llamada.
  • Idempotencia: cada reintento de una llamada mutativa debe reusar el mismo Idempotency-Key que el original. Keys distintos producen efectos distintos (o un 409 si reusas mal).

Sistema

Health check e identidad del cliente API

Productos

Catálogo de productos y categorías

Clientes

Terceros (clientes) y grupos

Listar clientes (terceros) del negocio

Catálogo de clientes con paginación. Requiere customers:read. El response NUNCA expone password, remember_token, numero_cuenta ni entidad_bancaria.

Authorizations:
bearerAuth
query Parameters
page
integer >= 1
Default: 1
per_page
integer [ 1 .. 200 ]
Default: 25
search
string <= 80 characters

Substring sobre razón social, nombre comercial y NIT (case-insensitive).

identification
string <= 30 characters

NIT/identificación exacta. Útil para deduplicación.

group_id
string^cg_[1-9A-HJ-NP-Za-km-z]{8,16}$
updated_since
string <date-time>
sort
string
Default: "-id"
Enum: "business_name" "-business_name" "identification" "-identification" "id" "-id"

Responses

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "meta": {
    },
  • "links": {}
}

Detalle de cliente por ID público

Authorizations:
bearerAuth
path Parameters
id
required
string^c_[1-9A-HJ-NP-Za-km-z]{8,16}$

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

Historial de ventas de un cliente

Requiere AMBOS scopes customers:read y sales:read.

Authorizations:
bearerAuth
path Parameters
id
required
string^c_[1-9A-HJ-NP-Za-km-z]{8,16}$
query Parameters
page
integer >= 1
Default: 1
per_page
integer [ 1 .. 200 ]
Default: 25

Responses

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "meta": {
    }
}

Catálogo de grupos de clientes

Tabla grupo_clientes (legacy, esquema mínimo: id, nombre).

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "data": [
    ]
}

Ventas

Ventas, líneas de detalle, pagos y métodos de pago

Listar ventas del negocio

Por defecto solo retorna ventas válidas (status=valid). Pasa ?status=voided para ver anuladas o ?status=all para ambas. El rango date_fromdate_to no puede exceder 90 días.

Authorizations:
bearerAuth
query Parameters
page
integer >= 1
Default: 1
per_page
integer [ 1 .. 200 ]
Default: 25
date_from
string <date>
date_to
string <date>
status
string
Default: "valid"
Enum: "valid" "voided" "all"
customer_id
string^c_[1-9A-HJ-NP-Za-km-z]{8,16}$
warehouse_id
string^wh_[1-9A-HJ-NP-Za-km-z]{8,16}$
seller_id
string^sl_[1-9A-HJ-NP-Za-km-z]{8,16}$
invoice_number
string <= 60 characters
include
string
Example: include=details,payments

Subconjunto de details, payments. Por defecto se eager-loadean customer, seller, warehouse.

sort
string
Default: "-date"
Enum: "date" "-date" "total" "-total" "id" "-id"

Responses

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "meta": {
    },
  • "links": {}
}

Detalle completo de una venta

Eager-load automático de customer, seller, warehouse, details, payments (con sus métodos).

Authorizations:
bearerAuth
path Parameters
id
required
string^s_[1-9A-HJ-NP-Za-km-z]{8,16}$

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

Catálogo de métodos de pago del negocio

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "data": [
    ]
}

Health check

Responses

Response samples

Content type
application/json
{
  • "status": "ok"
}

Info del cliente API autenticado

Authorizations:
bearerAuth

Responses

Products

List products of the authenticated tenant

Returns the tenant's product catalog. Requires products:read scope. Default returns only active products; pass active=false for inactive. Use include=stock (with warehouse_id) to embed stock for one warehouse.

Authorizations:
bearerAuth
query Parameters
page
integer >= 1
Default: 1
per_page
integer [ 1 .. 200 ]
Default: 25
search
string <= 80 characters

Case-insensitive substring search across name and code.

category_id
string^cat_[1-9A-HJ-NP-Za-km-z]{8,16}$

Filter by category (opaque public ID).

warehouse_id
string^wh_[1-9A-HJ-NP-Za-km-z]{8,16}$

Required when include=stock. Filters stock data to one warehouse.

active
boolean
Default: true
include
string
Example: include=stock,category

Comma-separated. Supported tokens: stock (requires warehouse_id), category. category is eagerly loaded regardless to avoid N+1.

updated_since
string <date-time>

Returns products created/updated at or after this timestamp. Legacy schemas use producto.fecha fallback.

sort
string
Default: "-created_at"
Enum: "name" "-name" "price" "-price" "created_at" "-created_at"

Responses

Response samples

Content type
application/json
{
  • "data": [
    ],
  • "meta": {
    },
  • "links": {}
}

Single product by opaque public ID

Returns a product the authenticated tenant owns. Returns 404 for IDs from other tenants — never 403 — to avoid cross-tenant existence disclosure.

Authorizations:
bearerAuth
path Parameters
id
required
string^p_[1-9A-HJ-NP-Za-km-z]{8,16}$

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

List tenant categories

Returns active categories. Requires products:read.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "data": [
    ]
}