This page gathers all backend API endpoints and front-end responsibilities.
For more details, please refer to the Swagger documentation.
All endpoints support the Accept-Language header for translations.
The supported locales are English (en), German (de), French (fr).
Accept-Language: de
GET /api/products
(filters & pagination in query)
fetch('/api/products?page=1&per_page=20&category=concert', { headers })
.then(res => res.json());
GET /api/products/{id}
GET /api/cartmeta.guest_cart_id (UUID)X-Guest-Cart-ID: {guest_cart_id}PATCH /api/cart/item/{product_id}
X-Guest-Cart-ID: {guest_cart_id}{ "quantity":0|n } Always indicate the entire quantityThis cart is stored in database. After login, guest cart merges into user’s cart.
All endpoints require
Authorization: Bearer {token}
GET /api/cartPATCH /api/cart/item/{product_id} Always indicate the entire quantityDELETE /api/cart/items
⚠️ After any update (guest or user), always re-fetch the cart with GET /api/cart.
POST /api/auth/register
GET /api/auth/email/{id}/{hash}/verification-result/success/verification-result/invalid/verification-result/already-verified/verification-result/error
POST /api/auth/email/resend (Email is required in the body of the request).⚠️ By problems with verification, please contact administration with the registered email, the admin can verify it.
POST /api/auth/login
HTTP 400 { "message": "Two-factor authentication code is required", "code": "twofa_required" }twofa_code to complete loginHTTP 200 { "message": "Logged in successfully", "token": "...", "user": { … }, "twofa_enabled": true|false }⚠️ The Bearer token is valid 12 hours or 7 days when remember me is active.
POST /api/auth/2fa/enable (Auth) → { "qr_code_url", "secret", "expires_at" } (display QR + key + expire date (+10 minutes))POST /api/auth/2fa/confirm (Auth) → { "recovery_codes" } (recovery codes)POST /api/auth/2fa/disable (Auth) { "code" } is required (this can be application code or a recovery code⚠️ 2FA is optional but recommended. For help disabling it, please contact administration with your registered email. We use Google 2FA.
POST /api/auth/password/forgot { email } sends reset front URL/password-reset?token=...&email=john@example.com&locale=frPOST /api/auth/password/reset
POST /api/auth/password
GET /api/users/me (Auth) → includes twofa_enabledPATCH /api/users/me { first_name, last_name }PATCH /api/auth/email triggers change emails needs to be verified:GET /api/auth/email/change/verify?token=...&old_email=.../verification-result/success/verification-result/invalid/verification-result/already-verified/verification-result/error
GET /api/auth/email/cancel/{token}/{old_email}/verification-result/success/verification-result/invalid/verification-result/already-verified/verification-result/error
POST /api/payments⚠️ This endpoint is called when the user clicks on the "Pay" button.
After receiving client_secret, the front should:
const stripe = await loadStripe('pk_test_...');
const elements = stripe.elements();
const card = elements.create('card');
card.mount('#card-element');
const { error, paymentIntent } = await stripe.confirmCardPayment(clientSecret, { payment_method: { card, billing_details: { name, email } } });
POST /api/payments/webhook
Verify signature and handle events (invoices, tickets, email with tickets, stock updates).
⚠️ The front-end should not call this endpoint directly. It is called by Stripe when a payment is made.
GET /api/payments/{uuid}
Poll for status until it’s paid.
⚠️ Once paid, front-end must call DELETE /api/cart/items to clear the cart.
POST /api/payments/{uuid}/refund
{ "amount": 25.00 } regenerates the invoice PDF.
⚠️ After refund the admin should update the status of the tickets too, it's not automatically.
GET /api/invoices/user (supports filters & pagination)GET /api/invoices/{filename} (PDF)GET /api/invoices/admin/{filename}
GET /api/tickets/user (supports filters & pagination)GET /api/tickets/{filename} (PDF)GET /api/tickets/qr/{filename} (PNG)GET /api/tickets (supports filters & pagination)GET /api/tickets/admin/{filename} (PDF)GET /api/tickets/admin/qr/{filename} (QR)PUT /api/tickets/admin/{id}/status { status }POST /api/tickets { user_id, quantity, locale }⚠️ Only tickets marked “issued” are valid for scanning.
⚠️ For free tickets, the front-end should call POST /api/tickets with the user_id, locale and quantity. The backend will generate the invoices and the tickets and send them to the user via email.
GET /api/products/all (supports filters & pagination)GET /api/products/{id}POST /api/products { translations, price, sale, stock_quantity, images }PUT /api/products/{id}PATCH /api/products/{id}/pricing⚠️ All product data (translations, descriptions, etc.) must be provided for every supported locale.
⚠️ The sale field is a decimal (e.g. 0.10 for 10% discount).
GET /api/users (supports filters & pagination)GET /api/users/{id}PATCH /api/users/{id} { name, roles[], twofa_enabled }GET /api/users/email/{id}⚠️ The user can be deactivated by changing is_active.
GET /api/admin/sales (supports filters & pagination)
POST /api/users/employees
GET /api/tickets/scan/{token}
After scanning the QR code, the employee calls this endpoint to retrieve the ticket details (customer info, event info, ticket token and current status). The {token} parameter must be the UUID encoded in the QR code.
POST /api/tickets/scan/{token}
⚠️ To validate the ticket and mark it as used, the employee must send the {token} (the UUID that he received by the GET) to this endpoint.
GET /api/payments (supports filters & pagination)POST /api/payments/{uuid}/refund⚠️ The refund is not automatically done on the tickets, the admin must do it manually.
POST /api/auth/logout (Auth) – invalidate token.