Student Registration API — Vital4Female
Documentación técnica para integrar el endpoint de registro de estudiantes desde cualquier cliente externo (Vue.js, React, mobile, etc.).
Endpoint
POST /api/v1/students
Content-Type: application/json
Accept: application/json
Request Body
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
firstname |
string | ✅ | Nombre del estudiante (max 100 chars) |
lastname |
string | ✅ | Apellido del estudiante (max 100 chars) |
email |
string | ✅ | Email único — se usa como login |
birthday |
date | ❌ | Fecha de nacimiento (YYYY-MM-DD) |
product_id |
integer | ✅ | ID del producto/membresía seleccionado |
membership |
string | ✅ | Nombre de la membresía |
payment_method |
string | ✅ | Método de pago (ideal, ideal-qr, etc.) |
discount_code |
string | ❌ | Código de descuento (opcional) |
Ejemplo de request
{
"firstname": "Anna",
"lastname": "Jansen",
"email": "anna.jansen@example.com",
"birthday": "1990-05-14",
"product_id": 3,
"membership": "Founder Membership",
"payment_method": "ideal",
"discount_code": "Founder40"
}
Responses
✅ 201 — Registro exitoso
{
"success": true,
"data": {
"payment_url": "https://app.paypro.nl/betalen/abc123",
"payment_hash": "sub_AbCdEfGh12345",
"order_id": 42,
"user_id": 88
},
"message": "Student registered successfully."
}
Acción esperada del cliente: redirigir al usuario a
data.payment_urlpara completar el pago en PayPro. Sipayment_urles la URL base de la app, significa que el producto era gratuito y no requiere pago.
❌ 422 — Error de validación o negocio
{
"success": false,
"message": "The email has already been taken.",
"data": {
"email": ["The email has already been taken."]
}
}
Posibles causas: - Email ya registrado - Código de descuento inválido, expirado o sin usos disponibles - Campo requerido faltante o con formato incorrecto
❌ 429 — Rate limit excedido
{
"success": false,
"message": "Too Many Attempts."
}
❌ 500 — Error interno
{
"success": false,
"message": "Registration failed. Please try again."
}
Los detalles del error se loggean internamente. No se exponen al cliente por seguridad.
Flujo completo
Cliente API Laravel PayPro
│ │ │
│── POST /api/v1/students ──>│ │
│ │── Valida datos │
│ │── Valida descuento │
│ │── Crea User │
│ │── Crea Student │
│ │── Crea Order │
│ │── createCustomer() ──>│
│ │── createSubscription()│
│ │<── payment_url ───────│
│ │── Despacha emails (queue)
│<── 201 { payment_url } ───│ │
│ │ │
│── redirect(payment_url) ──────────────────────────>│
│ │ │
│<──────────── PayPro procesa y llama webhook ───────│
Ejemplo de integración Vue.js (Composition API)
Ver archivo CheckoutForm.vue incluido en esta documentación.
Composable reutilizable
// composables/useStudentRegistration.js
import { ref } from 'vue'
export function useStudentRegistration() {
const loading = ref(false)
const errors = ref({})
async function register(payload) {
loading.value = true
errors.value = {}
try {
const response = await fetch('/api/v1/students', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
body: JSON.stringify(payload)
})
const json = await response.json()
if (!response.ok) {
if (response.status === 422 && json.data) {
errors.value = json.data // errores de validación por campo
}
throw new Error(json.message || 'Registration failed')
}
return json.data // { payment_url, payment_hash, order_id, user_id }
} finally {
loading.value = false
}
}
return { loading, errors, register }
}
Validación de código de descuento
El blade actual llama a un endpoint separado para validar el descuento antes del submit. Este endpoint debe seguir respondiendo:
GET /api/checkdiscounts/{code}
{
"valid": true,
"message": "Código válido",
"amount": 40
}
Configuración de Rate Limiting
En app/Http/Kernel.php o bootstrap/app.php (Laravel 11+), el endpoint ya tiene rate limiting por email + IP con máximo 5 intentos por minuto. Para ajustarlo, modificar las constantes en LoginController:
private const MAX_ATTEMPTS = 5;
private const DECAY_SECONDS = 60;
Variables de entorno requeridas
PAYPRO_API_KEY=your_key_here
PAYPRO_MODE=TEST # o LIVE
APP_URL=https://admin.vital4female.nl
QUEUE_CONNECTION=redis # recomendado para producción
Cola de trabajos (Queue Workers)
Los emails se despachan de forma asíncrona. En producción levantar al menos un worker:
php artisan queue:work redis --queue=default --tries=3 --timeout=60
Para múltiples workers con Supervisor:
[program:v4f-worker]
command=php /var/www/artisan queue:work redis --tries=3 --timeout=60
numprocs=4
autostart=true
autorestart=true
Webhook de PayPro
Cuando PayPro confirma el pago, llama al webhook configurado. Este endpoint debe actualizar el student_status y order_status a Actief.
POST /webhook/payments
Este flujo es independiente del registro — el registro siempre devuelve pending.