Ir al artículo
Aniq-UI

NorthstackReferencia de la API

Referencia de la API

Cada ruta que sirve la API, quién puede llamarla, y cómo funcionan el inicio de sesión, los espacios de trabajo, los permisos, la facturación, las claves de API, los errores, las listas y los límites.

Para el paquete Full Stack

URL base y formato de respuesta

Cada ruta se sirve bajo el prefijo /api. En local la URL base es http://localhost:8000/api. En un servidor es la dirección de tu API seguida de /api, el mismo valor que leen el sitio web y el panel de NEXT_PUBLIC_API_BASE_URL (Variables de entorno). Los archivos se sirven fuera del prefijo: los archivos de marca del kit en /media/… y los archivos subidos en /media/uploads/….

Los cuerpos de las peticiones son JSON, salvo las subidas de archivos. Cada respuesta llega en el mismo envoltorio:

Envoltorio
{
  "success": true,
  "data": { },
  "message": ""
}

data contiene el resultado. message es un código corto que rellenan algunas escrituras, como project_created o invitation_sent, y está vacío en los demás casos. Los espacios de trabajo, proyectos y tareas se nombran por sus ids públicos (org_forma, prj_01); los miembros, invitaciones, claves y archivos por su número. Los textos de proyectos y tareas llevan ambos idiomas como { "en": { … }, "ar": { … } }.

La comprobación de estado no necesita token:

Terminal
curl http://localhost:8000/api/health
Respuesta
{"success":true,"data":{"status":"ok","database":"up"},"message":""}

Hasta que la base de datos responde y tiene sus tablas, responde 503 con "status":"unavailable" y "database":"down". La comprobación de estado de la imagen de Docker lee ese estado, y Docker Compose inicia el sitio web y el panel solo cuando pasa.

Los navegadores solo pueden llamar a la API desde las direcciones de CORS_ORIGIN. Sin definir, permite http://localhost:3030 y http://localhost:3031, y en producción la API se niega a iniciar sin él (Problemas de CORS).

Errores

Un fallo conserva el envoltorio, con success: false, data: null y el estado HTTP:

Error
{
  "success": false,
  "data": null,
  "message": "seat_limit_reached",
  "errors": { "email": ["…"] }
}
  • errors aparece en un fallo de validación (400), con los problemas por campo.
  • Un campo desconocido en un cuerpo se rechaza con 400: cada cuerpo acepta solo los campos listados abajo.
  • Cuando la API tiene una frase para el error, message es esa frase en el idioma de la petición (Accept-Language: ar para árabe): un inicio de sesión rechazado, todo 429, los registros cerrados, una cuenta protegida frente a un cambio de contraseña o correo, un secreto de webhook ausente, una suscripción que Stripe no pudo cancelar, un rol o permiso de plataforma que quien llama no tiene, y el modo de mantenimiento, entre otros.
  • En los demás casos, en 401, 403 y 404 el message es una frase general del estado, y en 400, 402, 409, 410 y 503 es el motivo como código corto (seat_limit_reached, slug_taken, over_plan_limit, payment_declined, preview_expired, invitation_expired, payment_unavailable), que un cliente convierte en su propia frase. Un cambio a un plan inferior rechazado por el uso lleva además blockers.
  • 402 significa un cambio a un plan superior que el proveedor de pago no quiso cobrar: payment_declined, payment_needs_action (el banco quiere que se confirme el pago) o payment_method_missing. El plan se queda como estaba.
  • Mientras el personal de la plataforma tiene activado el modo de mantenimiento, toda ruta fuera de la lista corta de Modo de mantenimiento responde 503 a cualquiera que no sea personal de la plataforma, con la frase en message y code: "maintenance_mode".
  • 401 significa sin token, un token caducado, o credenciales incorrectas. 403 significa sesión iniciada sin el permiso, o una escritura en un espacio de trabajo suspendido. 404 también responde por un espacio de trabajo del que quien llama no es miembro, para que un extraño no pueda saber qué espacios existen.
  • Una petición por encima de un límite responde 429 (Límites por dirección).

Inicio de sesión

  1. Inicio de sesión

    Terminal
    curl -X POST http://localhost:8000/api/auth/login \
      -H "Content-Type: application/json" \
      -d '{"email":"owner@northstack.example","password":"YOUR_PASSWORD"}'

    Pon la contraseña de ejemplo de Instalación en lugar de YOUR_PASSWORD, o usa una cuenta propia. data.access_token es el token, con token_type Bearer, expires_in y admin, la cuenta con sus roles de plataforma, permisos y espacios de trabajo.

  2. Llama a una ruta protegida

    Terminal
    curl http://localhost:8000/api/workspaces \
      -H "Authorization: Bearer YOUR_TOKEN"

    Eso lista los espacios de trabajo de la cuenta con su rol en cada uno. Cada ruta de espacio de trabajo recibe entonces el id público del espacio en su ruta:

    Terminal
    curl "http://localhost:8000/api/workspaces/org_forma/projects?limit=20" \
      -H "Authorization: Bearer YOUR_TOKEN"
  • remember: true firma un token de 30 días y remember: false uno de 12 horas; si se omite, el token dura JWT_EXPIRATION, 7d por defecto.
  • Un correo desconocido y una contraseña incorrecta responden ambos 401 con el mismo mensaje, tras el mismo trabajo de hash de contraseña, de modo que ni la respuesta ni su tiempo indican qué correos tienen cuenta.
  • Diez inicios de sesión fallidos desde una misma dirección en 15 minutos responden 429 hasta que el fallo más antiguo cumple 15 minutos (RATE_LIMIT_LOGIN). Los inicios de sesión correctos no cuentan.
  • Los tokens no guardan estado: POST /api/auth/logout responde al instante, y cerrar sesión es que el cliente olvide su token.
MétodoRutaQuién puede llamarlaQué hace
POST/api/auth/loginCualquieraInicio de sesión: email, password, opcionalmente remember
POST/api/auth/signupCualquieraUna cuenta nueva, con sesión iniciada al instante y lista para el alta inicial: name (de 2 a 80 caracteres), email, password (de 8 a 128) y acceptTerms (true). Un correo ya usado responde 409 con email_taken; mientras el ajuste signups_enabled de la plataforma está desactivado responde 403
POST/api/auth/forgot-passwordCualquieraemail, opcionalmente locale (en, ar). Envía por correo un enlace de restablecimiento que funciona una vez durante una hora cuando la cuenta existe, y responde igual en ambos casos
POST/api/auth/reset-passwordCualquieratoken (del enlace) y la nueva password (de 8 a 128). Un enlace usado o caducado responde 401
POST/api/auth/logoutCualquieraResponde { signedOut: true }
GET/api/auth/meCualquier cuenta con la sesión iniciadaLa cuenta, sus roles y permisos de plataforma, y sus espacios de trabajo
PATCH/api/auth/meCualquier cuenta con la sesión iniciadaCambia firstName, lastName, email o phone
PATCH/api/auth/me/preferencesCualquier cuenta con la sesión iniciadatheme (system, light, dark), reducedMotion, locale (en, ar) y lastWorkspaceId, el espacio de trabajo que abre el siguiente inicio de sesión
PATCH/api/admins/profile/passwordCualquier cuenta con la sesión iniciadaCambia la contraseña de la propia cuenta: current_password, password, password_confirmation

Espacios de trabajo y permisos

  • Las rutas de espacio de trabajo empiezan por /api/workspaces/:workspaceId, el id público del espacio. En cada petición la API comprueba que quien llama tiene una membresía activa allí (si no, 404) y tiene el permiso que nombra la ruta (si no, 403). El rol es el de la membresía: una persona puede ser propietaria de un espacio y administradora de otro.
  • Un espacio de trabajo tiene cuatro roles (owner, admin, member, billing) y su propia matriz de 14 permisos: workspace.read, workspace.update, workspace.delete, projects.read, projects.write, members.invite, members.remove, roles.manage, billing.read, billing.manage, keys.manage, audit.read, ai.read y ai.apply. El propietario los tiene todos, y workspace.delete y roles.manage quedan con el propietario diga lo que diga la matriz. Un cambio en la matriz se aplica a la siguiente petición.
  • Un espacio de trabajo suspendido conserva todo GET y rechaza cualquier otro método con 403.
  • Un espacio de trabajo con pago vencido lo conserva todo hasta que pasan BILLING_GRACE_DAYS (7 por defecto); entonces no puede crear proyectos, invitaciones ni claves de API (403), mientras toda lectura y toda otra escritura siguen funcionando.
  • Las rutas de plataforma (/api/platform, /api/users, /api/admins, /api/roles, /api/settings) comprueban en su lugar los permisos de plataforma de la cuenta, concedidos mediante roles de plataforma. Los datos de ejemplo crean Platform admin, con los 21, y Support, que lee todas las páginas de la plataforma y exporta informes. Una ruta que lista varios permisos acepta cualquiera de ellos.

Listas y paginación

Una lista
{ "data": [ ], "total": 12, "page": 1, "limit": 7, "totalPages": 2 }
  • Proyectos, proyectos archivados, actividad, conversaciones del chat y sus mensajes, y la página de organizaciones y usuarios de la plataforma con page y limit, como máximo 100 por página. Los valores por defecto son 7 proyectos, 12 eventos, 20 conversaciones y 10 organizaciones o usuarios.
  • La página de personal, de ajustes de la plataforma y de roles de plataforma usa en su lugar page y page_count (10 por defecto, como máximo 100). La página de roles de plataforma solo cuando se dan ambos; si no, se devuelven todos los roles.
  • Las listas vienen de la más reciente a la más antigua (proyectos, usuarios y organizaciones por su último cambio), con el id como desempate, salvo que se dé un sort; los roles de plataforma vienen por nombre. La lista de proyectos devuelve también counts por pestaña.
  • Lo que pertenece a un solo espacio de trabajo y se muestra completo responde sin paginar: las tareas de un tablero, los miembros, las invitaciones, las claves de API, los archivos de un proyecto, las últimas 36 facturas y las últimas 8 notificaciones.

Espacios de trabajo, miembros y la matriz de roles

MétodoRutaQuién puede llamarlaQué hace
GET/api/workspacesCualquier cuenta con la sesión iniciadaLos espacios de trabajo de la cuenta con su rol en cada uno, para el selector
GET/api/workspaces/slug-availabilityCualquier cuenta con la sesión iniciada?slug=: si una dirección de espacio de trabajo está libre, con una suggestion cuando no lo está
POST/api/workspacesCualquier cuenta con la sesión iniciadaAlta inicial: name (de 2 a 80), slug (de 3 a 48 letras minúsculas, dígitos y guiones), region (europe, north_america, asia_pacific) y opcionalmente invitations, hasta 20 { email, role }. Quien llama pasa a ser el propietario, en una prueba de Starter tan larga como el trial_days de la plataforma. Un slug ocupado responde 409 con slug_taken, y mientras signups_enabled está desactivado responde 403
GET/api/workspaces/:workspaceIdUn miembro con workspace.readEl espacio de trabajo: nombre, dirección, plan, uso frente a los límites del plan y sus ajustes. billingEmail es null salvo que quien llama tenga billing.read o billing.manage
PATCH/api/workspaces/:workspaceIdUn miembro con workspace.updateCambia name, slug, locale (en, ar), timeZone (una zona IANA como Europe/Berlin), domainConfigured, emailNotifications (los correos de facturación) o weeklyDigest
DELETE/api/workspaces/:workspaceIdEl propietario del espacio de trabajoconfirmName (el nombre del espacio de trabajo, escrito completo) y la password del propietario. El espacio se elimina de forma lógica, y su suscripción de Stripe se cancela primero; si Stripe la rechaza, responde 409 y el espacio se conserva
GET/api/workspaces/:workspaceId/membersUn miembro con workspace.readLos miembros con sus roles. search, role
PATCH/api/workspaces/:workspaceId/members/:memberIdUn miembro con roles.manageCambia el role de un miembro (admin, member, billing). La fila del propietario responde 403
DELETE/api/workspaces/:workspaceId/members/:memberIdUn miembro con members.removeElimina a un miembro. El propietario no se puede eliminar, y un administrador no puede eliminar a otro administrador
POST/api/workspaces/:workspaceId/members/transfer-ownershipEl propietario del espacio de trabajomemberId y la password del propietario. El miembro pasa a ser el propietario y el propietario anterior un administrador
GET/api/workspaces/:workspaceId/rolesUn miembro con workspace.readLa matriz de roles: cada permiso, en seis grupos, y los roles que lo tienen
PUT/api/workspaces/:workspaceId/rolesEl propietario del espacio de trabajoGuarda la matriz: matrix, cada permiso asignado a los roles que lo tienen. Un permiso o rol desconocido responde 400

Invitaciones

MétodoRutaQuién puede llamarlaQué hace
GET/api/workspaces/:workspaceId/invitationsUn miembro con workspace.readstatus (pending, el valor por defecto, o all). Responde invitations y seats, los puestos usados y restantes del plan
POST/api/workspaces/:workspaceId/invitationsUn miembro con members.inviteInvita a email como role (admin, member, billing). El enlace se envía por correo y funciona 7 días. Un plan lleno responde 409 con seat_limit_reached; already_member y already_invited se rechazan del mismo modo
POST/api/workspaces/:workspaceId/invitations/:id/resendUn miembro con members.inviteUn enlace nuevo, válido otros 7 días. Una vez por minuto como máximo (resend_too_soon), y cinco veces por invitación (resend_limit_reached)
DELETE/api/workspaces/:workspaceId/invitations/:idUn miembro con members.inviteRevocar una invitación
GET/api/invitations/:tokenCualquieraLo que abre el enlace de una invitación: el nombre y la dirección del espacio de trabajo, el rol, el correo invitado en parte oculto, y si sigue abierta
POST/api/invitations/:token/acceptLa cuenta invitada, con sesión iniciadaSe une al espacio de trabajo. Un enlace caducado o revocado responde 410; una cuenta cuyo correo no es el invitado responde 403; un plan lleno responde 409 con seat_limit_reached

Los correos de invitación pasan por los ajustes SMTP de la API, o van a su registro, con el enlace, mientras SMTP_HOST está vacío.

Proyectos y archivos

MétodoRutaQuién puede llamarlaQué hace
GET/api/workspaces/:workspaceId/projectsUn miembro con projects.readProyectos con counts por pestaña. status (all, active, completed o un estado), state (in_progress, review, blocked, completed), search, ownerId, dueBefore (YYYY-MM-DD), sort (updated_at, due_date, name, progress), order (asc, desc), page, limit
GET/api/workspaces/:workspaceId/projects/archivedUn miembro con projects.readLos proyectos archivados, con los mismos filtros
GET/api/workspaces/:workspaceId/projects/ownersUn miembro con projects.readLos miembros que son responsables de proyectos, para el filtro de responsable
GET/api/workspaces/:workspaceId/projects/:projectIdUn miembro con projects.readUn proyecto con su responsable, fecha de entrega, progreso y recuentos de tareas
POST/api/workspaces/:workspaceId/projectsUn miembro con projects.writeCrea un proyecto: translations (en obligatorio, ar opcional, cada name hasta 120 caracteres y description hasta 2000), y opcionalmente status, ownerId (un miembro), dueDate (YYYY-MM-DD) y progress (de 0 a 100)
PATCH/api/workspaces/:workspaceId/projects/:projectIdUn miembro con projects.writeCambia cualquiera de esos campos
DELETE/api/workspaces/:workspaceId/projects/:projectIdUn miembro con projects.writeArchiva un proyecto. No se elimina nada
POST/api/workspaces/:workspaceId/projects/:projectId/restoreUn miembro con projects.writeDevuelve un proyecto archivado
GET/api/workspaces/:workspaceId/projects/:projectId/activityUn miembro con projects.readLos últimos 100 eventos del proyecto
GET/api/workspaces/:workspaceId/projects/:projectId/filesUn miembro con projects.readLos archivos del proyecto, el más reciente primero
POST/api/workspaces/:workspaceId/projects/:projectId/filesUn miembro con projects.writeAdjunta un archivo: multipart file, 10 MB como máximo. Su tamaño cuenta para el almacenamiento del plan
GET/api/workspaces/:workspaceId/projects/:projectId/files/:fileId/downloadUn miembro con projects.readEl url, name y mime del archivo

Crear un proyecto en un espacio de trabajo con pago vencido cuyo periodo de gracia ha terminado responde 403.

Tareas y el tablero

Una tarea se lista y se crea bajo su proyecto, y se cambia por su propio id bajo el espacio de trabajo.

MétodoRutaQuién puede llamarlaQué hace
GET/api/workspaces/:workspaceId/projects/:projectId/tasksUn miembro con projects.readLas tareas del tablero en el orden de las columnas. assigneeId, priority, search
POST/api/workspaces/:workspaceId/projects/:projectId/tasksUn miembro con projects.writeCrea una tarea: translations (en obligatorio, cada title hasta 160 caracteres y description hasta 4000), y opcionalmente status (backlog, el valor por defecto, in_progress, review, done), priority (low, normal, high), assigneeId (un miembro) y dueDate
PATCH/api/workspaces/:workspaceId/tasks/:taskIdUn miembro con projects.writeCambia cualquiera de esos campos
POST/api/workspaces/:workspaceId/tasks/:taskId/moveUn miembro con projects.writeMueve una tarjeta: status (la columna) y beforeId, la tarjeta sobre la que cae, o nada para el final de la columna
DELETE/api/workspaces/:workspaceId/tasks/:taskIdUn miembro con projects.writeArchiva una tarea

Una persona asignada que no es miembro responde 400 con assignee_not_member. Cada cambio escribe un evento en el rastro de actividad, como task.moved con las columnas de origen y destino.

Resumen, actividad, notificaciones y búsqueda

MétodoRutaQuién puede llamarlaQué hace
GET/api/workspaces/:workspaceId/overviewUn miembro con workspace.readEl resumen: proyectos por estado, miembros e invitaciones pendientes, eventos de tareas por día de los últimos siete días, la lista de lanzamiento, hasta tres proyectos con vencimiento dentro del periodo y los últimos seis eventos. period (7d, 30d, el valor por defecto, 90d). Sin projects.read, los recuentos de proyectos, el gráfico y los proyectos con vencimiento vuelven a cero o vacíos
GET/api/workspaces/:workspaceId/activityUn miembro con audit.readEl rastro de actividad, con las personas que aparecen en él como actors. action (una acción como task.moved, o una familia que termina en punto como task.), actorId, from y to (YYYY-MM-DD), search, page, limit
GET/api/workspaces/:workspaceId/activity/exportUn miembro con audit.readLos mismos filtros como archivo CSV (date, actor, action, subject, details), hasta 5.000 filas. Las celdas que se ejecutarían como fórmula de hoja de cálculo se escapan
GET/api/workspaces/:workspaceId/notificationsUn miembro con workspace.readLa campana: los últimos 8 eventos y cuántos son más recientes que la última vez que quien lee miró
POST/api/workspaces/:workspaceId/notifications/readUn miembro con workspace.readMarca todo hasta ahora como leído
GET/api/workspaces/:workspaceId/searchUn miembro con workspace.readq (de 2 a 100 caracteres): hasta cinco proyectos, tareas y miembros cada uno. Los proyectos y las tareas aparecen solo para un miembro con projects.read

Los últimos eventos del resumen y la campana muestran todo el rastro a quien llama con projects.read o audit.read, solo los eventos billing. a quien tiene billing.read y ninguno de esos dos, y nada a nadie más.

Facturación, su webhook y el pago de prueba

MétodoRutaQuién puede llamarlaQué hace
GET/api/workspaces/:workspaceId/billingUn miembro con billing.readLa suscripción: plan, estado, precio, renovación, una cancelación o un cambio a un plan inferior a la espera de la renovación, el periodo de gracia del pago vencido, el uso y cualquier pago en curso
GET/api/workspaces/:workspaceId/billing/invoicesUn miembro con billing.readLas últimas 36 facturas
GET/api/workspaces/:workspaceId/billing/invoices/:invoiceId/download-linkUn miembro con billing.readUn enlace firmado al PDF de la factura, válido cinco minutos, construido a partir de PUBLIC_API_URL
POST/api/workspaces/:workspaceId/billing/previewUn miembro con billing.manageLo que cuesta cambiar a planId (starter, pro, scale): cambio a un plan superior o inferior, cuándo surte efecto, el cargo de hoy (chargeTodayCents), la siguiente factura y cualquier blockers (puestos, solicitudes de API o almacenamiento por encima de los límites del plan más pequeño). Un cambio a un plan superior de una suscripción de Stripe en marcha lo cotiza Stripe y responde chargesCardOnFile: true con un quote que mantiene ese precio 30 minutos; el pago de prueba prorratea la diferencia sobre el resto del periodo. El plan actual responde 400 con same_plan, salvo en un primer pago (una prueba, una prueba terminada o un espacio de trabajo cancelado), donde cualquier plan se cobra a su precio completo
POST/api/workspaces/:workspaceId/billing/checkoutUn miembro con billing.manageplanId, opcionalmente locale y el quote de la vista previa. Un cambio a un plan superior de una suscripción de Stripe en marcha se hace al instante y se cobra al método de pago guardado (upgraded: true), con la fecha de renovación sin cambios; un cobro rechazado responde 402 con payment_declined, payment_needs_action o payment_method_missing, y una cotización caducada o ajena 409 con preview_expired. Cualquier otro cambio a un plan superior responde con el url del pago alojado y su session. Un cambio a un plan inferior se programa para la renovación (scheduled: true), en Stripe mediante un calendario de suscripción, o se rechaza con 409 over_plan_limit y los blockers
POST/api/workspaces/:workspaceId/billing/checkout/:sessionId/syncUn miembro con billing.readTras el retorno del pago: lee la sesión de vuelta desde el proveedor y responde con la sesión y el resumen. El plan cambia solo cuando el proveedor dice que está pagado
POST/api/workspaces/:workspaceId/billing/keep-planUn miembro con billing.manageDeshace un cambio a un plan inferior programado para la renovación; responde con el resumen. Si no hay nada programado responde 409 con no_scheduled_change
POST/api/workspaces/:workspaceId/billing/portalUn miembro con billing.manageEl url del portal de clientes de Stripe, para el método de pago; url: null para un espacio de trabajo que no se factura mediante Stripe
POST/api/workspaces/:workspaceId/billing/cancelUn miembro con billing.manageCancela al final del periodo. Un cambio a un plan inferior programado para la renovación se descarta
POST/api/workspaces/:workspaceId/billing/resumeUn miembro con billing.manageConserva una suscripción que estaba configurada para cancelarse
PATCH/api/workspaces/:workspaceId/billing/emailUn miembro con billing.manageCambia el email de facturación
GET/api/billing/invoices/downloadCualquiera que tenga el enlace firmado?token=: la factura como PDF. Un token incorrecto responde 401 y uno caducado 403
POST/api/billing/webhooks/stripeStripeLos eventos de Stripe, verificados con STRIPE_WEBHOOK_SECRET contra la cabecera Stripe-Signature; una firma ausente o incorrecta responde 400, y también cada entrega mientras STRIPE_WEBHOOK_SECRET está vacío, con un mensaje que lo nombra. Las suscripciones usan checkout.session.completed, invoice.paid, invoice.payment_failed y customer.subscription.deleted, con cada id de evento aplicado una vez. Los pedidos de licencias llegan por la misma ruta (El pago de licencias)
GET/api/billing/simulator/:sessionIdUn miembro con billing.manage en el espacio de trabajo de la sesiónLa sesión del pago de prueba, para la propia página de pago del panel
POST/api/billing/simulator/:sessionId/completeUn miembro con billing.manage en el espacio de trabajo de la sesiónPago de prueba: el plan cambia como si el proveedor lo hubiera confirmado
POST/api/billing/simulator/:sessionId/cancelUn miembro con billing.manage en el espacio de trabajo de la sesiónSale del pago de prueba sin pagar
  • El pago usa Stripe Checkout cuando STRIPE_SECRET_KEY está definido, y el pago de prueba integrado en caso contrario, o siempre que BILLING_PROVIDER=simulator. El pago de prueba no cobra a nadie.
  • La dirección de retorno por sí sola nunca cambia un plan: solo lo hace el webhook firmado, o la sesión leída de vuelta en sync.
  • El precio de Stripe de cada plan se crea en el primer uso, con la clave de búsqueda northstack_<plan>_usd_<cents>_month, así que no hay que configurar nada antes en Stripe.
  • Un pago de Stripe completado para un espacio de trabajo que ya tiene una suscripción de Stripe cancela la antigua, con su tiempo sin usar abonado. invoice.paid guarda la factura de Stripe una vez (las facturas son únicas por id de factura del proveedor), con su importe y periodo, lleva el periodo del espacio de trabajo al que inicia una factura, y en una renovación aplica un cambio a un plan inferior programado para ella.
  • En el pago de prueba la API renueva cada periodo al terminar (una factura pagada, los siguientes 30 días, un cambio a un plan inferior programado aplicado) y termina uno configurado para cancelarse. Una prueba que llega a su fin pasa a pago vencido, con el periodo de gracia. Los contadores de uso vuelven a cero en cada periodo. Esto se ejecuta en cada lectura de facturación y una vez por hora.
  • Apunta tu webhook de Stripe a https://<your API>/api/billing/webhooks/stripe con los eventos de arriba más checkout.session.expired.

Claves de API y la API pública

MétodoRutaQuién puede llamarlaQué hace
GET/api/workspaces/:workspaceId/api-keysUn miembro con keys.manageLas claves del espacio de trabajo: nombre, prefijo, alcances, entorno, último uso y quién la creó. Nunca el secreto
POST/api/workspaces/:workspaceId/api-keysUn miembro con keys.managename (de 2 a 60), scopes (uno o más de projects:read, projects:write, tasks:read, tasks:write) y environment (production, el valor por defecto, o demo). Responde con la clave y su secret, mostrado esta única vez; solo se guarda su hash SHA-256
DELETE/api/workspaces/:workspaceId/api-keys/:idUn miembro con keys.manageRevoca una clave. Deja de funcionar al instante
GET/api/v1/projectsUna clave de API con projects:readLos 100 proyectos actualizados más recientemente del espacio de trabajo
POST/api/v1/projectsUna clave de API con projects:writeCrea un proyecto, con el mismo cuerpo que el del panel
PATCH/api/v1/projects/:projectIdUna clave de API con projects:writeCambia un proyecto, con el mismo cuerpo que el del panel
GET/api/v1/projects/:projectId/tasksUna clave de API con tasks:readLas tareas de un proyecto
POST/api/v1/projects/:projectId/tasksUna clave de API con tasks:writeCrea una tarea, con el mismo cuerpo que el del tablero
Terminal
curl http://localhost:8000/api/v1/projects \
  -H "Authorization: Bearer nst_live_…"
  • El secreto de una clave de producción empieza por nst_live_, el de una clave de demostración por nst_demo_. Una clave de demostración funciona solo mientras la API funciona en modo demostración.
  • Sin clave, una desconocida o revocada responde 401; una clave sin el alcance de la ruta responde 403; un espacio de trabajo suspendido rechaza la escritura.
  • Toda ruta salvo la lista de proyectos se ejecuta como el creador de la clave: lo que crea queda registrado como hecho por él, con la validación del panel, los eventos de actividad y los límites del plan. Responde 404 cuando el creador ha dejado el espacio de trabajo, y las tres escrituras responden 403 cuando el rol del creador ya no tiene projects.write.
  • Cada llamada cuenta para las solicitudes de API del plan, que leen la página de facturación y los límites del plan.

Resumen de la plataforma y organizaciones

MétodoRutaQuién puede llamarlaQué hace
GET/api/platform/overviewPersonal con platform.viewLos ingresos recurrentes mensuales y su historial, la mezcla de planes y las organizaciones por estado. range (30d, 90d, 6m, el valor por defecto, 12m)
GET/api/platform/overview/exportPersonal con reports.exportTodas las organizaciones como archivo CSV: organization, id, plan, status, seats, mrr_usd, created
GET/api/platform/organizationsPersonal con organizations.viewOrganizaciones. search (nombre o dirección), plan (starter, pro, scale), status (trialing, active, past_due, canceling, canceled, suspended), page, limit
GET/api/platform/organizations/:idPersonal con organizations.viewUna organización, por su id público
POST/api/platform/organizations/:id/suspendPersonal con organizations.managereason (de 3 a 300 caracteres). El espacio de trabajo conserva sus lecturas y rechaza toda escritura. Uno suspendido responde 409
POST/api/platform/organizations/:id/reactivatePersonal con organizations.manageLevanta una suspensión

Usuarios, personal, roles de plataforma y ajustes

MétodoRutaQuién puede llamarlaQué hace
GET/api/usersPersonal con users.viewTodas las cuentas. search, role (owner, admin, member o billing para un rol de espacio de trabajo tenido en cualquier parte, staff para un rol de plataforma, none para cuentas sin espacio de trabajo), page, limit
GET/api/users/deletedPersonal con users.viewLas cuentas eliminadas, con los mismos filtros
GET/api/users/statisticPersonal con users.viewTotales: cuentas, eliminadas, personal, sin espacio de trabajo, nuevas en los últimos 30 días
GET/api/users/deleted/:usernamePersonal con users.viewUna cuenta eliminada
GET/api/users/:usernamePersonal con users.viewUna cuenta
POST/api/usersPersonal con users.createCrea una cuenta: first_name, last_name, email, password (de 8 a 128), opcionalmente phone
PATCH/api/users/:usernamePersonal con users.updateCambia first_name, last_name, email o phone. Un correo nuevo está protegido como se indica abajo
PATCH/api/users/:username/change-passwordPersonal con users.updateDefine una password nueva (de 8 a 128), protegida como se indica abajo
DELETE/api/users/:usernamePersonal con users.deleteMueve una cuenta a la lista de eliminadas. Una cuenta que es propietaria de un espacio de trabajo responde 409 con user_owns_workspace hasta que la propiedad se traspasa
POST/api/users/deleted/:username/restorePersonal con users.restoreDevuelve una cuenta eliminada
GET/api/adminsPersonal con admins.viewTodas las cuentas con sus roles de plataforma. email, name (nombre, apellido o nombre de usuario), phone, una fila que coincida con cualquiera de los dados, page, page_count
GET/api/admins/statisticsPersonal con admins.viewRecuentos para la página de personal
GET/api/admins/:idPersonal con admins.viewUna cuenta, por id o nombre de usuario
POST/api/adminsPersonal con admins.createAñade una cuenta de personal: first_name, last_name, email, password y password_confirmation (6 caracteres o más), opcionalmente phone, phone_code, profile_picture
PATCH/api/admins/:idPersonal con admins.editCambia esos campos; una contraseña o un correo nuevos están protegidos como se indica abajo
PATCH/api/admins/:id/rolesPersonal con admins.assign_rolesDefine los roles de plataforma de una cuenta: role_ids. Cada rol concedido o quitado debe tener solo permisos que quien llama tiene él mismo, o responde 403 (role_outranks_caller). Su panel abierto recibe el aviso al instante
DELETE/api/admins/:idPersonal con admins.deleteElimina una cuenta. Una que es propietaria de un espacio de trabajo responde 409
PATCH/api/admins/profilePersonal con admins.editCambia el propio perfil del miembro del personal con sesión iniciada
GET/api/rolesPersonal con roles.viewRoles de plataforma. name, guard_name, created_from, created_to, page, page_count
GET/api/roles/statisticsPersonal con roles.viewRecuentos para la página de roles
GET/api/roles/selectPersonal con roles.viewEl id y el nombre de cada rol, para un selector
GET/api/roles/permissionsPersonal con roles.viewTodos los permisos de plataforma, agrupados por área
GET/api/roles/:idPersonal con roles.viewUn rol con sus permisos
POST/api/rolesPersonal con roles.createAñade un rol: name. Un nombre en uso responde 409
PUT/api/roles/:idPersonal con roles.editRenombra un rol: name
POST/api/roles/:id/permissionsPersonal con roles.assign_permissionsDefine los permissions de un rol, por nombre. Quien llama solo puede dar permisos que tiene, y cambiar solo un rol que no tenga ninguno que le falte, o responde 403 (permission_outranks_caller). Todos los que lo tienen reciben el aviso al instante
DELETE/api/roles/:idPersonal con roles.deleteElimina un rol. Uno que alguien tiene responde 400
GET/api/settingsPersonal con settings.viewLos ajustes de la plataforma. search, category, page, page_count
GET/api/settings/:keyPersonal con settings.viewUn ajuste
PATCH/api/settings/:keyPersonal con settings.editCambia un ajuste: value
DELETE/api/settings/:keyPersonal con settings.editEliminar un ajuste

La protección de contraseñas y correos: quien llama y no es la propia cuenta puede definir su contraseña o cambiar su correo solo cuando es Platform admin o tiene todos los permisos de plataforma que tiene la cuenta; en caso contrario la API responde 403. El correo también está protegido, porque un restablecimiento de contraseña se envía a él.

La protección de roles: nadie puede conceder, quitar ni elevar un rol de plataforma más allá de sus propios permisos, así que admins.assign_roles o roles.assign_permissions por sí solos nunca llevan al rol Platform admin.

Los 21 permisos de plataforma son platform.view, reports.export, organizations.view, organizations.manage, users.view, users.create, users.update, users.delete, users.restore, admins.view, admins.create, admins.edit, admins.delete, admins.assign_roles, roles.view, roles.create, roles.edit, roles.delete, roles.assign_permissions, settings.view y settings.edit.

Ajustes públicos y modo de mantenimiento

MétodoRutaQuién puede llamarlaQué hace
GET/api/public-settingsCualquieramaintenanceMode y trialDays (el trial_days de la plataforma, 14 si no está definido): lo que el alta inicial indica como duración de la prueba, y si el panel muestra su pantalla de mantenimiento. Abierto durante el mantenimiento

Mientras el ajuste de plataforma maintenance_mode es true, toda petición de quien no es personal de la plataforma (una cuenta con platform.view) responde 503, con code: "maintenance_mode" y el mensaje "The platform is closed for maintenance. Please try again shortly." Un token ausente o incorrecto recibe el mismo 503. Estas siguen abiertas para todos:

  • GET /api/health y GET /api/public-settings;
  • POST /api/auth/login y POST /api/auth/logout, donde el inicio de sesión sigue rechazando con el 503 a quien no es personal una vez que las credenciales son correctas;
  • POST /api/billing/webhooks/stripe y la descarga firmada de facturas;
  • el endpoint MCP, que conserva su propia clave, y GET /api/demo/status;
  • el POST /api/contact del sitio web y todas las rutas /api/licenses, para que el formulario de contacto y el pago de licencias sigan funcionando.

Todo lo demás está cerrado para quien no es personal, incluidos el registro, la recuperación de contraseña, las invitaciones, el alta inicial, la API pública bajo /api/v1, los archivos subidos y el asistente. La lista es back-end/src/common/constants/maintenance.constants.ts.

El formulario de contacto

MétodoRutaQuién puede llamarlaQué hace
POST/api/contactCualquieraname (de 2 a 120), email, topic (licensing, setup, product), message (de 20 a 4000 caracteres), clientToken (de 8 a 64 letras, dígitos, _ o -) y el campo oculto website. Responde { id }
  • Un clientToken repetido devuelve el id del primer mensaje en lugar de guardar un segundo, así que reintentar es seguro.
  • Un campo website relleno se trata como un bot: la respuesta es igual, y no se guarda nada.
  • Cada dirección puede enviar cinco por hora; el siguiente responde 429.
  • Los mensajes se guardan en la tabla contact_messages y se reenvían a CONTACT_INBOX cuando está definido.

El pago de licencias

MétodoRutaQuién puede llamarlaQué hace
GET/api/licenses/checkout/optionsCualquieraLos métodos de pago (card, paypal), el provider que cobra cada uno (stripe, paypal o simulator) y testMode, verdadero cuando ninguno mueve dinero real
POST/api/licenses/checkoutCualquieralicense (single, studio), email, name (de 2 a 120), method (card, paypal), opcionalmente locale (en, ar) y clientToken. Responde order, el id del pedido, y url, la página donde pagar. Una página de pago que no se puede abrir responde 503 con payment_unavailable
GET/api/licenses/orders/:idCualquiera que tenga el id del pedidoEl pedido: referencia, licencia, importe, correo, nombre, método, proveedor, status (pending, paid, cancelled, failed), test y licenseKey una vez pagado
POST/api/licenses/orders/:id/confirmCualquiera que tenga el id del pedidoEl comprador vuelve de Stripe o PayPal: pregunta al proveedor si el pago se completó y luego responde con el pedido
POST/api/licenses/orders/:id/cancelCualquiera que tenga el id del pedidoEl comprador salió de la página de pago sin pagar
POST/api/licenses/orders/:id/simulateCualquiera que tenga el id del pedidoEl Pay o Cancel del pago de prueba: outcome (pay, cancel). Un pedido tomado por Stripe o PayPal responde 404
  • El precio es el propio del servidor, de back-end/src/modules/licenses/constants/license-offers.ts; el navegador nunca envía uno.
  • Una tarjeta va a Stripe Checkout cuando STRIPE_SECRET_KEY está definido, PayPal a PayPal cuando PAYPAL_CLIENT_ID y PAYPAL_CLIENT_SECRET están definidos, y cualquiera de los dos al pago de prueba en caso contrario. En el modo demostración nunca se ofrece un proveedor con claves en vivo.
  • Un pedido se paga una sola vez, por lo que llegue primero entre el checkout.session.completed de Stripe en POST /api/billing/webhooks/stripe, el confirm del retorno o el Pay del pago de prueba. Solo ese emite la clave de licencia y envía el recibo por correo. checkout.session.expired marca el pedido como fallido.
  • El id del pedido es una cadena larga y aleatoria que solo llevan los enlaces de retorno del comprador. Un clientToken repetido responde con el primer pedido. Cada dirección puede iniciar diez pedidos por hora.

Archivos subidos y multimedia

MétodoRutaQuién puede llamarlaQué hace
POST/api/helpers/uploadCualquier cuenta con la sesión iniciadaGuarda una imagen: multipart file (10 MB como máximo), path para la carpeta y for para el tamaño predefinido (profile, cover, logo o default). Responde con las direcciones por tamaño: original, de 1920 píxeles de ancho como máximo, y una copia redimensionada, todas en JPEG. Un archivo que no es una imagen legible responde 400

Las imágenes y los archivos de proyecto van al bucket de Cloudflare R2 cuando están definidas sus cinco variables R2_*, y en caso contrario a MEDIA_UPLOAD_DIR, y se sirven en PUBLIC_MEDIA_URL seguido de /uploads/….

Todo lo que la API sirve bajo /media lleva X-Content-Type-Options: nosniff, y un archivo que no es una imagen rasterizada, un PDF, texto plano, audio o vídeo (un archivo HTML o SVG, por ejemplo) se envía con Content-Disposition: attachment, de modo que se descarga en lugar de abrirse como una página en la dirección de la API. Los archivos de un bucket R2 los sirve el bucket, con el tipo con el que se subieron.

Límites por dirección

RutaLímiteVariable
POST /api/auth/login10 inicios de sesión fallidos cada 15 minutosRATE_LIMIT_LOGIN
POST /api/auth/signup10 por horaNinguno
POST /api/auth/forgot-password5 cada 15 minutosNinguno
POST /api/auth/reset-password10 cada 15 minutosNinguno
POST /api/contact5 por horaNinguno
POST /api/licenses/checkout10 por horaNinguno
POST …/invitations/:id/resendUna vez por minuto, cinco veces por invitaciónNinguno

Una petición por encima de un límite responde 429, con una frase que nombra lo que se limitó y cuánto esperar, como "Too many sign-ups from this address. Wait an hour, then try again." Los recuentos viven en la memoria de la API, así que un reinicio los borra. Detrás de un proxy inverso, define TRUST_PROXY con el número de proxies delante de la API, o cada visitante se cuenta como la única dirección del proxy.

El asistente de IA, sus conversaciones y propuestas

Incluido con tu compra. Inicia sesión para leerlo o ábrelo en tu descarga.

La ruta de streaming del asistente, su lista de modelos, las conversaciones guardadas y las propuestas de tareas.

Servidor MCP

Incluido con tu compra. Inicia sesión para leerlo o ábrelo en tu descarga.

El endpoint MCP para agentes de código, cómo se autoriza y qué espacio de trabajo lee.

Actualizaciones de permisos en vivo mediante socket.io

Incluido con tu compra. Inicia sesión para leerlo o ábrelo en tu descarga.

El espacio de nombres de socket.io que escucha el panel, su evento y cómo se autoriza una conexión.

Rutas del modo demostración

Incluido con tu compra. Inicia sesión para leerlo o ábrelo en tu descarga.

Las rutas que existen solo para una compilación de demostración pública.

¿Te atascaste en un paso?

Busca una solución antes de empezar de nuevo.

Solución de problemas

Preferencias de Cookies

Utilizamos cookies para mejorar tu experiencia de navegación, analizar el tráfico del sitio y personalizar el contenido. Al hacer clic en "Aceptar Todo", consientes nuestro uso de cookies para análisis y publicidad personalizada.