Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Ahondev/portfolio-v2/llms.txt

Use this file to discover all available pages before exploring further.

The WP SSR Framework exposes two public-facing form endpoints under /api/v1/. Neither requires authentication. On success each endpoint validates the payload with the built-in RequestValidator and dispatches a Markdown-formatted Telegram message via TelegramNotificationService. All validation errors return a structured 422 response with per-field messages so the frontend can display inline feedback without any extra parsing logic.

POST /api/v1/contact

Submits a general contact enquiry. Use this for short inbound messages where the visitor describes their project type and leaves a free-text message. Base URL (with rewrites): POST /api/v1/contact
Base URL (without rewrites): POST /wp-json/api/v1/contact

Request body

name
string
required
Full name of the sender. Must be between 2 and 100 characters.
email
string
required
A valid email address. Maximum 255 characters. Validated with FILTER_VALIDATE_EMAIL.
phone
string
Optional phone number. When provided it must match the pattern /^[0-9+\s]{10,}$/ (digits, +, and spaces, at least 10 characters total).
project
string
required
Short description of the project type (e.g. "Site vitrine", "Application mobile"). Maximum 200 characters.
message
string
required
The visitor’s message. Must be between 10 and 2 000 characters.

Responses

success
boolean
true on a successful submission.
code
integer
HTTP status code echoed in the body. 200 on success.
data
object
Example success response
{
  "success": true,
  "code": 200,
  "data": {}
}
Validation error (422)
{
  "success": false,
  "code": 422,
  "error": {
    "message": "Validation error",
    "context": "contact",
    "errors": {
      "email": ["Le champ email doit être une adresse email valide."],
      "message": ["Le champ message doit contenir au moins 10 caractères."]
    }
  }
}
Rate-limit error (429)
{
  "success": false,
  "code": 429,
  "error": {
    "message": "Too many requests",
    "context": "global"
  }
}

Example request

curl -s -X POST https://example.com/api/v1/contact \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Marie Dupont",
    "email": "marie@example.com",
    "phone": "+33 6 12 34 56 78",
    "project": "Site vitrine",
    "message": "Bonjour, je souhaite un site vitrine pour mon activité de conseil."
  }'

Side effects

Telegram notification — A Markdown message is dispatched to the configured chat (see Telegram notifications below). No WordPress post is created by this endpoint.

POST /api/v1/devis

Submits a detailed project quote request. This endpoint collects structured budget, deadline, and urgency data on top of the basic contact fields — ideal for a multi-step quote form. Base URL (with rewrites): POST /api/v1/devis
Base URL (without rewrites): POST /wp-json/api/v1/devis

Request body

firstName
string
required
Sender’s first name. Between 2 and 100 characters.
lastName
string
required
Sender’s last name. Between 2 and 100 characters.
email
string
required
A valid email address. Maximum 255 characters.
phone
string
required
Phone number. Required for quote requests (unlike /contact where it is optional). Must match /^[0-9+\s]{10,}$/.
company
string
Company or organisation name. Optional. Maximum 150 characters.
projectType
string
required
Category of the project (e.g. "E-commerce", "Application SaaS"). Maximum 200 characters.
budget
string
required
Estimated budget range as a string (e.g. "5 000 – 10 000 €"). Maximum 100 characters.
deadline
string
required
Target delivery timeline (e.g. "3 mois", "Q1 2026"). Maximum 100 characters.
urgency
string
required
Urgency level (e.g. "Normal", "Urgent"). Maximum 50 characters.
needs
string
required
Detailed description of the main requirements. Between 10 and 2 000 characters.

Responses

The response envelope is identical to /contact. Example success response
{
  "success": true,
  "code": 200,
  "data": {}
}
Validation error (422)
{
  "success": false,
  "code": 422,
  "error": {
    "message": "Validation error",
    "context": "devis",
    "errors": {
      "phone": ["Le numéro de téléphone n'est pas valide."],
      "needs": ["Le champ needs est requis."]
    }
  }
}

Example request

curl -s -X POST https://example.com/api/v1/devis \
  -H "Content-Type: application/json" \
  -d '{
    "firstName": "Luc",
    "lastName": "Martin",
    "email": "luc.martin@example.com",
    "phone": "+33 7 00 11 22 33",
    "company": "Martin & Associés",
    "projectType": "Application SaaS",
    "budget": "10 000 – 20 000 €",
    "deadline": "6 mois",
    "urgency": "Normal",
    "needs": "Nous avons besoin d'\''une plateforme de gestion RH avec authentification SSO et tableau de bord analytique."
  }'

Side effects

Telegram notification — A Markdown message is dispatched with the full quote details. No WordPress post is created by this endpoint.

Validation system

Both endpoints use a lightweight validation pipeline built into the framework:
  1. ApiRequest — abstract base class. Its static validate() method extracts get_params() from the WP_REST_Request, delegates to RequestValidator, and returns only the fields that have declared rules (unknown keys are stripped automatically).
  2. RequestValidator — pure-PHP rule engine. Rules are declared as a pipe-separated string (e.g. 'required|string|min:2|max:100'). Supported rules: required, string, email, min:<n>, max:<n>, phone, numeric, integer, boolean, in:<a,b,c>, not_in:<a,b>, confirmed, url, ip, date, regex:<pattern>.
  3. ValidationException — thrown when errors exist. Carries the full [field => [messages]] map and sets HTTP code 422.
// ContactRequest.php — rules definition
public static function rules(): array
{
    return [
        'name'    => 'required|string|min:2|max:100',
        'email'   => 'required|email|max:255',
        'phone'   => 'nullable|phone',
        'project' => 'required|string|max:200',
        'message' => 'required|string|min:10|max:2000',
    ];
}
The nullable modifier causes the validator to skip all further rules when the field is absent or empty. This is how phone is optional on /contact but still validated when present.

Telegram notifications

TelegramNotificationService::sendNotification(string $message) calls the Telegram Bot API using WordPress’s built-in wp_remote_post(). Two environment variables must be set:
VariableDescription
TELEGRAM_BOT_TOKENThe token issued by @BotFather
TELEGRAM_CHAT_IDThe numeric ID of the target chat or channel
Messages are sent with parse_mode: Markdown, so the notification text uses *bold* formatting for field labels.
// TelegramNotificationService.php
wp_remote_post(
    "https://api.telegram.org/bot{$botToken}/sendMessage",
    [
        'body' => [
            'chat_id'    => $chatId,
            'text'       => $message,
            'parse_mode' => 'Markdown',
        ],
    ]
);
If either TELEGRAM_BOT_TOKEN or TELEGRAM_CHAT_ID is missing or empty, env() will return null and the Telegram request will silently fail (no exception is thrown). Make sure both variables are set in your .env file before going to production.
A /contact notification looks like this in Telegram:
🚀 *Nouvelle demande de contact*

👤 *Nom:* Marie Dupont
📧 *Email:* marie@example.com
📞 *Téléphone:* +33 6 12 34 56 78

📌 *Type:* Site vitrine

📝 *Message:*
Bonjour, je souhaite un site vitrine pour mon activité de conseil.

Build docs developers (and LLMs) love