access_token (JWT firmado con ES256)/api/* deben incluir: Authorization: Bearer <access_token>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"}'
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.
| HTTP | Causa | Solución |
|---|---|---|
401 · missing_auth_token | Falta header Authorization | Agregar Authorization: Bearer ... |
401 · invalid_token | JWT expirado o malformado | Refrescar la sesión en cliente |
403 · not_a_seller | Endpoint requiere rol seller | Crear tienda en /vender/registro |
403 · forbidden | Falta header admin secret | Usar header x-plazi-admin |
503 · push_columns_missing | Migración SQL pendiente | Aplicar 20260606130000 |
Lista pública de productos. Soporta query ?limit=20&category=mochilas&city=BOG&q=wayuu.
Detalle público de un producto (PDP). Incluye imágenes, variantes, precio, ciudad y datos del seller.
Sitemap dinámico (productos + categorías + tiendas + páginas estáticas).
Crea una orden desde mobile. Body: { items: [{variantId, qty}], address, paymentKind, couponCode? }. Devuelve { orderNumber, total, redirectUrl }.
Detalle de orden del comprador autenticado. 403 si no es propietario.
Auth seller. Body: { status: "packing" | "shipped" | "delivered" | "completed" | "cancelled" }. Valida transiciones permitidas (confirmed → packing → shipped → delivered → completed). Dispara push + email + inbox notification al buyer.
Auth seller. Crea un producto con su variante principal. Body: { title, description, price, inventory, imageUrls[] }.
Auth seller. Edita el producto. Verifica ownership.
Auth seller. Soft delete (status = 'deleted').
Devuelve { productIds: string[], products: FavoriteProduct[] } del usuario autenticado.
Toggle de favorito. Body: { productId }. Devuelve { inWishlist: boolean }.
Lista direcciones guardadas del comprador (ordenadas por is_default DESC).
Crea una dirección. Body: { label, recipient, phone, line1, city, state, isDefault? }.
Edita. Body: { id, ...AddressInput }.
Soft delete. Body: { id }.
Inbox: { notifications: [...], unread: number }. Últimas 50.
Marca leída. Body: { id } o { all: true }.
Auth. Crea una reseña 1-5 estrellas para un order_item entregado. Body: { orderItemId, rating, title?, body? }.
Valida un código de cupón. Body: { code, subtotalCents }. Devuelve descuento aplicable.
Auth Bearer. Registra el Expo Push Token del device. Body: { token, platform, device_name? }. Lo guarda en profiles.push_token.
Limpia el token (logout).
Admin secret. Endpoint manual para test/cron. Header: x-plazi-admin: $PLAZI_ADMIN_SECRET. Body: { kind: "test" | "order_new" | "order_status", ... }.
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"
}'
KPIs hoy + 30 días: ventas, comisión Plazi (10%), pedidos, conteo de sellers por estado.
Lista de vendedores con filtro de estado.
Cambia status de un vendedor. Body: { sellerId, status: "verified" | "pending" | "suspended" }. Escribe en outbox_events para auditoría.
Todas las órdenes del rango. Para dashboard admin mobile.
# 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"
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.
La API no está versionada (/api/v1/...). Cambios breaking se anuncian con 30 días de aviso a integradores en el mailing list interno.