API Demandes de devis
Cette API permet à n'importe quel site web (landing page, site vitrine, formulaire de contact…)
d'envoyer une demande de devis directement dans la base
Requests de Cleaning Service. Chaque demande est enregistrée,
rattachée automatiquement à un prospect, et une tâche commerciale de suivi est créée.
Endpoint
Envoyez une requête POST avec un corps application/json.
Le CORS est ouvert (Access-Control-Allow-Origin: *), l'appel peut donc être
effectué directement depuis le navigateur du visiteur.
Authentification
Aucun token n'est nécessaire : l'endpoint est public pour faciliter l'intégration côté site tiers. La provenance est identifiée automatiquement grâce au domaine émetteur (voir Sources automatiques). Une protection anti-bot par honeypot est en place (voir Anti-spam).
Sources automatiques (le domaine émetteur)
Chaque demande est rattachée à une source : le domaine du site qui l'a envoyée. Si ce domaine n'existe pas encore, il est créé automatiquement dans la base des sources — aucune configuration préalable n'est nécessaire.
Le domaine est déterminé dans cet ordre de priorité :
- le champ
source_domaindu corps JSON (recommandé), ex.cleanoffice.ch - sinon, le domaine extrait de
source_url - sinon, l'en-tête HTTP
Origin - sinon, l'en-tête HTTP
Referer
source_domain explicitement
pour garantir un rattachement correct, même si l'appel est fait côté serveur.
Champs acceptés
Tous les champs sont optionnels sauf qu'il faut fournir au moins un moyen de contact
(email ou phone). Les champs inconnus sont conservés
tels quels dans raw_json.
| Champ | Type | Requis | Description |
|---|---|---|---|
| string | requis* | Email du demandeur (*ou phone) | |
| phone | string | requis* | Téléphone (*ou email). Alias : tel, telephone |
| name | string | optionnel | Nom complet (découpé en prénom/nom). Ou utilisez first_name + last_name |
| first_name | string | optionnel | Prénom |
| last_name | string | optionnel | Nom |
| company | string | optionnel | Société. Alias : company_name, societe |
| service | string | optionnel | Prestation souhaitée (bureaux, fin de chantier, vitres…). Alias : prestation, subject |
| message | string | optionnel | Message libre. Alias : comment, details |
| address | string | optionnel | Adresse. Alias : adresse |
| postal_code | string | optionnel | NPA / code postal. Alias : zip, npa |
| city | string | optionnel | Ville. Alias : ville |
| surface | string | optionnel | Surface indicative (m²). Alias : area, m2 |
| frequency | string | optionnel | Fréquence souhaitée. Alias : frequence |
| budget | string | optionnel | Budget indicatif |
| preferred_date | string | optionnel | Date d'intervention souhaitée. Alias : date |
| source_domain | string | recommandé | Domaine du site émetteur, ex. cleanoffice.ch |
| source_url | string | optionnel | URL de la page d'origine. Alias : page_url, url |
| source_label | string | optionnel | Nom lisible du site. Alias : site_name |
| utm_source | string | optionnel | Suivi campagne |
| utm_medium | string | optionnel | Suivi campagne |
| utm_campaign | string | optionnel | Suivi campagne |
| company_website | string | honeypot | Champ piège anti-bot : doit rester vide (voir Anti-spam) |
Exemples
cURL
# Envoi d'une demande de devis curl -X POST https://api.cs-sa.ch/public/quote-requests \ -H "Content-Type: application/json" \ -d '{ "source_domain": "cleanoffice.ch", "name": "Marie Dupont", "email": "marie@exemple.ch", "phone": "+41 79 123 45 67", "company": "Exemple SA", "service": "Nettoyage de bureaux", "city": "Genève", "postal_code": "1200", "surface": "250 m2", "message": "Bonjour, je souhaite un devis pour l'entretien de nos bureaux." }'
JavaScript (fetch)
await fetch("https://api.cs-sa.ch/public/quote-requests", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ source_domain: "cleanoffice.ch", name: form.name.value, email: form.email.value, phone: form.phone.value, service: form.service.value, message: form.message.value, source_url: location.href }) });
Formulaire HTML prêt à coller
Exemple complet de formulaire de demande de devis, avec envoi en JavaScript et champ honeypot.
<form id="devis">
<input name="name" placeholder="Nom" required />
<input name="email" type="email" placeholder="Email" required />
<input name="phone" placeholder="Téléphone" />
<input name="service" placeholder="Prestation souhaitée" />
<textarea name="message" placeholder="Votre message"></textarea>
<!-- honeypot anti-bot : garder caché en CSS -->
<input name="company_website" tabindex="-1" autocomplete="off"
style="position:absolute;left:-9999px" />
<button type="submit">Demander un devis</button>
</form>
<script>
document.getElementById("devis").addEventListener("submit", async (e) => {
e.preventDefault();
const f = e.target;
const payload = Object.fromEntries(new FormData(f).entries());
payload.source_domain = location.hostname;
payload.source_url = location.href;
const r = await fetch("https://api.cs-sa.ch/public/quote-requests", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload)
});
if (r.ok) { f.reset(); alert("Merci ! Votre demande a bien été envoyée."); }
else { alert("Une erreur est survenue, réessayez."); }
});
</script>Réponses
201 · Succès
{
"ok": true,
"id": 42,
"source": "cleanoffice.ch",
"prospect_id": 18,
"task_id": 143
}
400 · Contact manquant
{
"error": "missing_contact",
"message": "Un email ou un téléphone est requis."
}
| Code | Signification |
|---|---|
| 201 | Demande enregistrée |
| 400 | missing_contact — ni email ni téléphone fourni |
| 500 | internal_error — erreur serveur (réessayer) |
Anti-spam (honeypot)
Ajoutez un champ caché nommé company_website à votre formulaire, masqué
en CSS (ex. position:absolute;left:-9999px). Un humain ne le remplira jamais ;
un robot oui. Si ce champ est rempli, la demande est silencieusement ignorée
(réponse 201 mais rien n'est enregistré) — cela évite d'alerter le bot.
Que se passe-t-il après l'envoi ?
- 1 La source (le domaine émetteur) est retrouvée ou créée automatiquement.
- 2 La demande est enregistrée dans la base
Requests(payload complet conservé). - 3 Un prospect est créé (ou réutilisé si l'email/téléphone existe déjà).
- 4 Une tâche commerciale de suivi (priorité haute) est générée.
- 5 La demande apparaît dans le manager (menu Demandes) et dans l'app vendeurs (onglet Alertes).