← Volver al portal
Documentación técnica · DOC-API-01

API Guide

22 endpoints REST con autenticación Bearer JWT para integradores y mobile

Documento
DOC-API-01
Base URL
https://plazi.co/api
Auth
Bearer JWT (Supabase)
Endpoints
22 documentados

1 · Autenticación

Cómo obtener y usar el JWT

Flujo del comprador / vendedor (OTP)

  1. El usuario ingresa su correo en la app/web
  2. Supabase envía un código OTP vía Resend
  3. El usuario confirma el código y recibe un access_token (JWT firmado con ES256)
  4. Todas las llamadas a /api/* deben incluir: Authorization: Bearer <access_token>

Ejemplo · login programático (debug)

curl -X POST https://<project>.supabase.co/auth/v1/otp \
  -H "apikey: <ANON_KEY>" \
  -H "Content-Type: application/json" \
  -d '{"email":"demo-buyer@plazi.co"}'

# Después el usuario recibe el código y verifica:
curl -X POST https://<project>.supabase.co/auth/v1/verify \
  -H "apikey: <ANON_KEY>" \
  -H "Content-Type: application/json" \
  -d '{"type":"email","email":"demo-buyer@plazi.co","token":"123456"}'
RLS protege todo. Aunque el ANON_KEY es público, las tablas tienen Row Level Security: cada endpoint solo retorna/modifica datos del usuario autenticado. Las operaciones cross-user (notificar a un seller) usan service-role server-side.

Errores comunes

HTTPCausaSolución
401 · missing_auth_tokenFalta header AuthorizationAgregar Authorization: Bearer ...
401 · invalid_tokenJWT expirado o malformadoRefrescar la sesión en cliente
403 · not_a_sellerEndpoint requiere rol sellerCrear tienda en /vender/registro
403 · forbiddenFalta header admin secretUsar header x-plazi-admin
503 · push_columns_missingMigración SQL pendienteAplicar 20260606130000
DOC-API-01 · Página 1

2 · Endpoints públicos (catálogo)

3 endpoints accesibles sin auth

GET/api/products

Lista pública de productos. Soporta query ?limit=20&category=mochilas&city=BOG&q=wayuu.

GET/api/products/[slug]

Detalle público de un producto (PDP). Incluye imágenes, variantes, precio, ciudad y datos del seller.

GET/api/sitemap.xml

Sitemap dinámico (productos + categorías + tiendas + páginas estáticas).

3 · Órdenes (auth Bearer)

3 endpoints para crear y gestionar pedidos

POST/api/orders/place

Crea una orden desde mobile. Body: { items: [{variantId, qty}], address, paymentKind, couponCode? }. Devuelve { orderNumber, total, redirectUrl }.

GET/api/orders/[number]

Detalle de orden del comprador autenticado. 403 si no es propietario.

PATCH/api/orders/[number]/status

Auth seller. Body: { status: "packing" | "shipped" | "delivered" | "completed" | "cancelled" }. Valida transiciones permitidas (confirmed → packing → shipped → delivered → completed). Dispara push + email + inbox notification al buyer.

4 · Productos del vendedor

POST/api/products

Auth seller. Crea un producto con su variante principal. Body: { title, description, price, inventory, imageUrls[] }.

PATCH/api/products/[id]

Auth seller. Edita el producto. Verifica ownership.

DELETE/api/products/[id]

Auth seller. Soft delete (status = 'deleted').

DOC-API-01 · Página 2

5 · Comprador (favoritos, direcciones, notificaciones)

8 endpoints para las features del perfil

GET/api/wishlist

Devuelve { productIds: string[], products: FavoriteProduct[] } del usuario autenticado.

POST/api/wishlist

Toggle de favorito. Body: { productId }. Devuelve { inWishlist: boolean }.

GET/api/addresses

Lista direcciones guardadas del comprador (ordenadas por is_default DESC).

POST/api/addresses

Crea una dirección. Body: { label, recipient, phone, line1, city, state, isDefault? }.

PATCH/api/addresses

Edita. Body: { id, ...AddressInput }.

DELETE/api/addresses

Soft delete. Body: { id }.

GET/api/notifications

Inbox: { notifications: [...], unread: number }. Últimas 50.

PATCH/api/notifications

Marca leída. Body: { id } o { all: true }.

6 · Reseñas y cupones

POST/api/reviews

Auth. Crea una reseña 1-5 estrellas para un order_item entregado. Body: { orderItemId, rating, title?, body? }.

POST/api/coupons/validate

Valida un código de cupón. Body: { code, subtotalCents }. Devuelve descuento aplicable.

DOC-API-01 · Página 3

7 · Push notifications

2 endpoints para registro y envío

POST/api/push/register

Auth Bearer. Registra el Expo Push Token del device. Body: { token, platform, device_name? }. Lo guarda en profiles.push_token.

DELETE/api/push/register

Limpia el token (logout).

POST/api/push/notify

Admin secret. Endpoint manual para test/cron. Header: x-plazi-admin: $PLAZI_ADMIN_SECRET. Body: { kind: "test" | "order_new" | "order_status", ... }.

Ejemplo · test push

curl -X POST https://plazi.co/api/push/notify \
  -H "x-plazi-admin: $PLAZI_ADMIN_SECRET" \
  -H "content-type: application/json" \
  -d '{
    "kind": "test",
    "token": "ExponentPushToken[xxx]",
    "title": "🇨🇴 Test Plazi",
    "body": "Funciona perfecto"
  }'

8 · Admin (auth Bearer + rol admin)

3 endpoints para el panel admin del mobile

GET/api/admin/stats

KPIs hoy + 30 días: ventas, comisión Plazi (10%), pedidos, conteo de sellers por estado.

GET/api/admin/sellers?filter=pending|verified|suspended|all

Lista de vendedores con filtro de estado.

PATCH/api/admin/sellers

Cambia status de un vendedor. Body: { sellerId, status: "verified" | "pending" | "suspended" }. Escribe en outbox_events para auditoría.

GET/api/admin/orders?range=today|week|month

Todas las órdenes del rango. Para dashboard admin mobile.

DOC-API-01 · Página 4

9 · Receta E2E · checkout completo

Flujo end-to-end con curl

# 1. Listar productos (sin auth)
curl https://plazi.co/api/products?limit=3

# 2. Login OTP (Supabase Auth)
# El user recibe el código por correo, luego:
TOKEN=$(curl -s -X POST https://<sb>.supabase.co/auth/v1/verify \
  -H "apikey: $ANON_KEY" -H "Content-Type: application/json" \
  -d '{"type":"email","email":"demo-buyer@plazi.co","token":"123456"}' \
  | jq -r .access_token)

# 3. Guardar una dirección
curl -X POST https://plazi.co/api/addresses \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "label":"Casa",
    "recipient":"Don Juan",
    "phone":"3001234567",
    "line1":"Calle 123 # 45-67",
    "city":"Bogotá",
    "state":"Cundinamarca",
    "isDefault":true
  }'

# 4. Agregar a favoritos
curl -X POST https://plazi.co/api/wishlist \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"productId":"<product_uuid>"}'

# 5. Crear orden
curl -X POST https://plazi.co/api/orders/place \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "items":[{"variantId":"<variant_uuid>","qty":2}],
    "address":{"recipient":"Don Juan","phone":"3001234567",
               "line1":"Calle 123 # 45-67","city":"Bogotá","state":"Cundinamarca"},
    "paymentKind":"nequi"
  }'

# 6. (seller) cambiar status del pedido
curl -X PATCH https://plazi.co/api/orders/BG-2026-12345/status \
  -H "Authorization: Bearer $SELLER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"status":"packing"}'

# 7. (buyer) ver inbox de notificaciones
curl https://plazi.co/api/notifications \
  -H "Authorization: Bearer $TOKEN"

Rate limits

Vercel Fluid Compute escala automáticamente. Para protección anti-bots se recomienda agregar Vercel BotID a futuro. Por ahora no hay rate limits explícitos en los endpoints.

Versionado

La API no está versionada (/api/v1/...). Cambios breaking se anuncian con 30 días de aviso a integradores en el mailing list interno.

DOC-API-01 · Página 5 (final)