Developers

API du site#

Lisez et écrivez le contenu d'un site NAMES LEGAL via HTTPS : services, projets, articles de blog, membres de l'équipe, événements, offres d'emploi, FAQ et plus encore. L'API fait partie du module complémentaire Accès API du site.

Démarrage rapide#

  1. Dans la console du site, Add-ons & abonnement : activez Accès API.
  2. Modules → API : créez une clé. Copiez-la maintenant — elle ne s'affiche qu'une seule fois.
  3. Appelez l'API :
KEY="nlk_3fa9c2d1_Jx0..."
curl -H "Authorization: Api-Key $KEY" "https://ecolehorizon.names.legal/api/v1/team/?lang=fr"
{
  "count": 12,
  "next": "https://ecolehorizon.names.legal/api/v1/team/?lang=fr&page=2",
  "previous": null,
  "results": [
    {"id": 4, "first_name": "Awa", "last_name": "Diop", "position": "Mathematics teacher",
     "profile_image": "https://ecolehorizon.names.legal/media/demo/team/awa.jpg",
     "updated_at": "2026-09-20T08:12:44+02:00"}
  ]
}

URL de base#

https://<site>/api/v1/

<site> est l'adresse propre du site (ecolehorizon.names.legal ou son domaine personnalisé). Il n'y a pas de préfixe de langue dans le chemin. v1 est la seule version ; un changement non rétrocompatible arriverait sous la forme v2, en parallèle.

L'URL racine liste toutes les collections. Une référence interactive (Swagger) et le schéma OpenAPI sont disponibles sur chaque site :

URL Accès
Référence interactive /api/v1/docs/ Clé API (tout scope) ou un compte console
Schéma OpenAPI 3 /api/v1/schema/ Clé API (tout scope) ou un compte console

Authentification#

  1. Le propriétaire du site active le module complémentaire Accès API.
  2. Dans la console, Modules → API, il crée une clé et choisit son scope. La clé complète est affichée une seule fois ; seuls un préfixe et un hachage sont conservés.
  3. Envoyez la clé avec chaque requête.
GET /api/v1/services/ HTTP/1.1
Host: ecolehorizon.names.legal
Authorization: Api-Key nlk_3fa9c2d1_Jx0...

Authorization: Bearer <key> et X-Api-Key: <key> sont également acceptés. Les clés ressemblent à nlk_<8 caractères hexadécimaux>_<secret>.

Scopes#

Scope Autorise
read (par défaut) GET sur toutes les collections
write GET, POST, PUT, PATCH

Le scope s'applique à toute la clé ; il n'y a pas de scope par collection. Une clé peut être révoquée à tout moment depuis la console.

Erreurs que vous pouvez rencontrer#

Statut Signification
401 Clé absente, inconnue ou révoquée : {"detail": "Invalid API key."}
403 Le module complémentaire n'est pas actif, ou une clé read a tenté d'écrire
404 /docs/ et /schema/ lorsque le module complémentaire n'est pas actif
405 DELETE — la suppression se fait uniquement depuis la console
429 Limite de débit dépassée
400 Erreur de validation : {"field": ["message"]}

Langue#

Les champs traduits sont renvoyés dans une langue à la fois. Choisissez-la avec ?lang= :

curl -H "Authorization: Api-Key $KEY" "https://ecolehorizon.names.legal/api/v1/services/?lang=fr"

La langue doit être l'une de celles publiées par le site ; sinon la réponse est 400. Sans lang, la langue par défaut du site est utilisée. La réponse porte un en-tête Content-Language.

Pagination, filtres et tri#

Les listes sont paginées par numéro de page :

{
  "count": 42,
  "next": "https://ecolehorizon.names.legal/api/v1/team/?page=2",
  "previous": null,
  "results": [ ... ]
}
Paramètre Effet
page, page_size Numéro et taille de page (par défaut 25, maximum 100)
search Recherche plein texte sur les principaux champs textuels de la collection
ordering Champ de tri, - pour l'ordre décroissant : ?ordering=-updated_at
filtres de champ Correspondance exacte, par exemple ?category__slug=bachelor&is_featured=true
since Uniquement les fiches modifiées depuis une date : ?since=2026-09-01T00:00:00Z

since rend la synchronisation incrémentale peu coûteuse : conservez l'horodatage de votre dernier appel et transmettez-le la fois suivante.

Limites de débit#

  • 120 requêtes par minute et par clé API (chaque clé a son propre compteur).
  • Sessions console : 120 par minute. Appels anonymes : 30 par minute.

Au-delà de la limite, l'API répond 429 ; patientez et réessayez.

Collections#

Chemin Méthodes Remarques
services/ GET, POST, PUT, PATCH Catégorie via category_slug (facultatif)
projects/ GET, POST, PUT, PATCH category_slug obligatoire
blog/ GET, POST, PUT, PATCH Articles publiés uniquement ; category_slug obligatoire
team/ GET, POST, PUT, PATCH Membres actifs uniquement
testimonials/ GET, POST, PUT, PATCH Témoignages réels uniquement
publications/ GET, POST, PUT, PATCH category_slug facultatif
resources/ GET, POST, PUT, PATCH Le fichier lui-même se gère dans la console
events/ GET, POST, PUT, PATCH Dates au format ISO 8601
jobs/ GET, POST, PUT, PATCH Offres actives uniquement ; category_slug obligatoire
faq/ GET, POST, PUT, PATCH category_slug facultatif
bookable-items/ GET Nécessite le module complémentaire Appointments
bookings/ POST Crée une réservation ; nécessite une clé write

Chaque fiche est accessible à <collection>/<id>/. Les champs de chaque collection sont listés dans la référence ci-dessous.

Écriture#

  • POST crée, PUT remplace, PATCH met à jour certains champs.
  • Les catégories sont lues comme un objet {"id", "name", "slug"} et écrites avec category_slug. Un slug inconnu est refusé.
  • Les images et fichiers sont en lecture seule dans l'API : chargez-les depuis la console, ou laissez le connecteur de données les télécharger depuis une URL.
  • Le HTML envoyé dans les champs de texte enrichi est nettoyé : les scripts et gestionnaires d'événements sont retirés.
curl -X POST "https://ecolehorizon.names.legal/api/v1/faq/?lang=fr" \
  -H "Authorization: Api-Key $KEY" -H "Content-Type: application/json" \
  -d '{"question": "Quand ont lieu les inscriptions ?", "answer": "<p>Du 1er au 30 juin.</p>"}'

Réserver un rendez-vous#

curl -X POST "https://ecolehorizon.names.legal/api/v1/bookings/" \
  -H "Authorization: Api-Key $KEY" -H "Content-Type: application/json" \
  -d '{"item": 3, "customer_name": "Awa Diop", "customer_email": "awa@example.com",
       "date": "2026-10-02", "time": "14:30"}'

time est exprimé dans le fuseau horaire du site. Un créneau qui n'est plus disponible est refusé avec 400. Les nouvelles réservations démarrent au statut pending.

Recettes#

Reproduire une collection de façon incrémentale#

Lisez tout une première fois, puis seulement ce qui a changé. Conservez l'horodatage de votre précédente exécution et transmettez-le comme since.

Python

import time
import requests

BASE = "https://ecolehorizon.names.legal/api/v1/"
HEADERS = {"Authorization": "Api-Key nlk_3fa9c2d1_Jx0..."}

def fetch_all(collection, since=None, lang="fr"):
    url = f"{BASE}{collection}/"
    params = {"lang": lang, "page_size": 100, "ordering": "updated_at"}
    if since:
        params["since"] = since
    while url:
        response = requests.get(url, headers=HEADERS, params=params, timeout=15)
        if response.status_code == 429:
            time.sleep(int(response.headers.get("Retry-After", "5")))
            continue
        response.raise_for_status()
        data = response.json()
        yield from data["results"]
        url, params = data["next"], None   # "next" already carries the parameters

for member in fetch_all("team", since="2026-09-01T00:00:00Z"):
    print(member["id"], member["first_name"], member["last_name"])

JavaScript (Node.js 18+)

const BASE = "https://ecolehorizon.names.legal/api/v1/";
const HEADERS = { Authorization: "Api-Key nlk_3fa9c2d1_Jx0..." };

async function* fetchAll(collection, since, lang = "fr") {
  const first = new URL(`${BASE}${collection}/`);
  first.search = new URLSearchParams({ lang, page_size: "100", ordering: "updated_at",
                                       ...(since ? { since } : {}) });
  let url = first.toString();
  while (url) {
    const response = await fetch(url, { headers: HEADERS });
    if (response.status === 429) {
      const wait = Number(response.headers.get("Retry-After") || 5);
      await new Promise((resolve) => setTimeout(resolve, wait * 1000));
      continue;
    }
    if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
    const data = await response.json();
    yield* data.results;
    url = data.next;
  }
}

for await (const post of fetchAll("blog", "2026-09-01T00:00:00Z")) {
  console.log(post.id, post.title);
}

Créer ou mettre à jour une fiche#

PHP

<?php
$base = 'https://ecolehorizon.names.legal/api/v1/';
$headers = ['Authorization: Api-Key nlk_3fa9c2d1_Jx0...', 'Content-Type: application/json'];

function call($method, $url, $headers, $body = null) {
    $ch = curl_init($url);
    curl_setopt_array($ch, [CURLOPT_CUSTOMREQUEST => $method, CURLOPT_HTTPHEADER => $headers,
                            CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 15]);
    if ($body !== null) curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
    $answer = curl_exec($ch);
    $status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
    curl_close($ch);
    return [$status, json_decode($answer, true)];
}

// Create an event (in French)
[$status, $event] = call('POST', $base . 'events/?lang=fr', $headers, [
    'title' => 'Journée portes ouvertes',
    'slug' => 'journee-portes-ouvertes-2026',
    'description' => '<p>Visite du campus et rencontre avec les enseignants.</p>',
    'start_date' => '2026-11-14T09:00:00+01:00',
    'end_date' => '2026-11-14T16:00:00+01:00',
    'location' => 'Campus de Genève',
]);

// Change only the location later
call('PATCH', $base . "events/{$event['id']}/?lang=fr", $headers, ['location' => 'Aula']);

lang détermine la langue dans laquelle un champ traduit est écrit : renvoyez la même fiche avec ?lang=en pour ajouter la version anglaise.

Erreurs et limites en pratique#

Situation Que faire
429 Too Many Requests Attendez le nombre de secondes indiqué dans l'en-tête Retry-After, puis réessayez.
400 à l'écriture Lisez le corps de la réponse : chaque champ liste ses problèmes, {"category_slug": ["Object with slug=x does not exist."]}.
403 sur une requête write La clé est read : créez une clé read and write.
401 La clé a été révoquée ou mal saisie.
Erreur réseau ou 5xx Réessayez avec un délai croissant (1 s, 2 s, 4 s…). Les lectures peuvent être répétées sans risque ; pour un POST, vérifiez d'abord que la fiche n'a pas été créée.

Référence par collection#

Générée à partir du code de l'API : les champs, droits d'accès et paramètres de requête sont toujours ceux de la plateforme en cours d'exécution. Les champs traduits sont lus et écrits dans la langue choisie avec lang.

/api/v1/services/

GETPOSTPUTPATCH

  • Filtres slug category__slug is_featured
  • search title description
  • ordering order title updated_at (par défaut order)
ChampType de champAccès
id integer lecture seule
slug string ≤ 200 lecture et écriture
title string ≤ 100 lecture et écriture obligatoire à la création
description string lecture et écriture obligatoire à la création
icon string ≤ 50 lecture et écriture obligatoire à la création
color string ≤ 25 lecture et écriture
category object lecture seule
category_slug slug écriture seule
is_featured boolean lecture et écriture
order integer lecture et écriture
seo_title string ≤ 70 lecture et écriture
seo_description string ≤ 160 lecture et écriture
og_image id lecture seule
updated_at datetime lecture seule

/api/v1/projects/

GETPOSTPUTPATCH

  • Filtres slug category__slug status is_featured
  • search title description client technologies
  • ordering order title project_date updated_at (par défaut order)
ChampType de champAccès
id integer lecture seule
slug string ≤ 50 lecture et écriture obligatoire à la création
title string ≤ 150 lecture et écriture obligatoire à la création
description string lecture et écriture obligatoire à la création
detailed_description string lecture et écriture
category object lecture seule
category_slug slug écriture seule obligatoire à la création
client string ≤ 100 lecture et écriture
status choice
completed, in_progress, on_hold, planning
lecture et écriture
project_date string ≤ 20 lecture et écriture
duration string ≤ 50 lecture et écriture
team_size string ≤ 50 lecture et écriture
technologies string ≤ 200 lecture et écriture
tags string ≤ 200 lecture et écriture
image file (URL) lecture seule
demo_url url ≤ 200 lecture et écriture
project_url url ≤ 200 lecture et écriture
github_url url ≤ 200 lecture et écriture
is_featured boolean lecture et écriture
order integer lecture et écriture
seo_title string ≤ 70 lecture et écriture
seo_description string ≤ 160 lecture et écriture
og_image id lecture seule
created_at datetime lecture seule
updated_at datetime lecture seule

/api/v1/blog/

GETPOSTPUTPATCH

  • Filtres slug category__slug status tags__slug
  • search title excerpt content
  • ordering published_date title updated_at (par défaut -published_date)
ChampType de champAccès
id integer lecture seule
slug string ≤ 200 lecture et écriture obligatoire à la création
title string ≤ 200 lecture et écriture obligatoire à la création
excerpt string ≤ 500 lecture et écriture obligatoire à la création
content string lecture et écriture obligatoire à la création
category object lecture seule
category_slug slug écriture seule obligatoire à la création
tags list of slug lecture seule
featured_image file (URL) lecture seule
published_date datetime lecture et écriture
read_time integer lecture et écriture
status choice
draft, published, featured
lecture et écriture
order integer lecture et écriture
seo_title string ≤ 70 lecture et écriture
seo_description string ≤ 160 lecture et écriture
og_image id lecture seule
updated_at datetime lecture seule

/api/v1/team/

GETPOSTPUTPATCH

  • Filtres member_type is_featured
  • search first_name last_name position specialties
  • ordering order last_name updated_at (par défaut order)
ChampType de champAccès
id integer lecture seule
first_name string ≤ 100 lecture et écriture obligatoire à la création
last_name string ≤ 100 lecture et écriture obligatoire à la création
position string ≤ 150 lecture et écriture obligatoire à la création
short_bio string ≤ 300 lecture et écriture
bio string lecture et écriture
profile_image file (URL) lecture seule
email email ≤ 254 lecture et écriture
phone string ≤ 20 lecture et écriture
linkedin url ≤ 200 lecture et écriture
github url ≤ 200 lecture et écriture
twitter url ≤ 200 lecture et écriture
instagram url ≤ 200 lecture et écriture
facebook url ≤ 200 lecture et écriture
website url ≤ 200 lecture et écriture
specialties string ≤ 200 lecture et écriture
years_experience integer lecture et écriture
education string ≤ 200 lecture et écriture
location string ≤ 100 lecture et écriture
languages string ≤ 100 lecture et écriture
member_type choice
founder, lead, senior, developer, designer, manager, consultant, intern
lecture et écriture
is_featured boolean lecture et écriture
order integer lecture et écriture
updated_at datetime lecture seule

/api/v1/testimonials/

GETPOSTPUTPATCH

  • Filtres rating
  • search name position testimonial
  • ordering order rating updated_at (par défaut order)
ChampType de champAccès
id integer lecture seule
name string ≤ 100 lecture et écriture obligatoire à la création
position string ≤ 100 lecture et écriture obligatoire à la création
testimonial string lecture et écriture obligatoire à la création
rating integer lecture et écriture
image file (URL) lecture seule
order integer lecture et écriture
updated_at datetime lecture seule

/api/v1/publications/

GETPOSTPUTPATCH

  • Filtres slug category__slug year is_featured
  • search title authors journal abstract
  • ordering order year title updated_at (par défaut order,-year)
ChampType de champAccès
id integer lecture seule
slug string ≤ 200 lecture et écriture
title string ≤ 255 lecture et écriture obligatoire à la création
authors string ≤ 255 lecture et écriture obligatoire à la création
journal string ≤ 255 lecture et écriture
year string ≤ 10 lecture et écriture obligatoire à la création
abstract string lecture et écriture
link url ≤ 200 lecture et écriture
category object lecture seule
category_slug slug écriture seule
is_featured boolean lecture et écriture
order integer lecture et écriture
seo_title string ≤ 70 lecture et écriture
seo_description string ≤ 160 lecture et écriture
og_image id lecture seule
updated_at datetime lecture seule

/api/v1/resources/

GETPOSTPUTPATCH

  • Filtres slug resource_type is_free
  • search title description
  • ordering order title created_at updated_at (par défaut order)
ChampType de champAccès
id integer lecture seule
slug string ≤ 200 lecture et écriture obligatoire à la création
title string ≤ 200 lecture et écriture obligatoire à la création
description string lecture et écriture obligatoire à la création
resource_type choice
guide, ebook, whitepaper, template, checklist, case_study
lecture et écriture
file file (URL) lecture seule
file_size string lecture seule
thumbnail file (URL) lecture seule
is_free boolean lecture et écriture
requires_email boolean lecture et écriture
order integer lecture et écriture
seo_title string ≤ 70 lecture et écriture
seo_description string ≤ 160 lecture et écriture
og_image id lecture seule
created_at datetime lecture seule
updated_at datetime lecture seule

/api/v1/events/

GETPOSTPUTPATCH

  • Filtres slug event_type is_online is_featured
  • search title description location
  • ordering start_date title updated_at (par défaut -start_date)
ChampType de champAccès
id integer lecture seule
slug string ≤ 200 lecture et écriture obligatoire à la création
title string ≤ 200 lecture et écriture obligatoire à la création
description string lecture et écriture obligatoire à la création
event_type choice
conference, workshop, webinar, seminar, training, meeting
lecture et écriture
start_date datetime lecture et écriture obligatoire à la création
end_date datetime lecture et écriture obligatoire à la création
timezone string ≤ 64 lecture et écriture
location string ≤ 200 lecture et écriture obligatoire à la création
is_online boolean lecture et écriture
meeting_url url ≤ 200 lecture et écriture
registration_url url ≤ 200 lecture et écriture
registration_deadline datetime lecture et écriture
max_attendees integer lecture et écriture
featured_image file (URL) lecture seule
is_featured boolean lecture et écriture
order integer lecture et écriture
seo_title string ≤ 70 lecture et écriture
seo_description string ≤ 160 lecture et écriture
og_image id lecture seule
created_at datetime lecture seule
updated_at datetime lecture seule

/api/v1/jobs/

GETPOSTPUTPATCH

  • Filtres slug category__slug contract_type remote_option experience_level is_featured is_urgent
  • search title description location skills_required
  • ordering published_date title updated_at (par défaut -published_date)
ChampType de champAccès
id integer lecture seule
slug string ≤ 50 lecture et écriture
title string ≤ 200 lecture et écriture obligatoire à la création
description string lecture et écriture obligatoire à la création
responsibilities string lecture et écriture
requirements string lecture et écriture obligatoire à la création
qualifications string lecture et écriture
benefits string lecture et écriture
category object lecture seule
category_slug slug écriture seule obligatoire à la création
location string ≤ 200 lecture et écriture obligatoire à la création
contract_type choice
full_time, part_time, contract, freelance, internship, temporary
lecture et écriture
remote_option choice
onsite, remote, hybrid
lecture et écriture
experience_level choice
entry, junior, mid, senior, lead, executive
lecture et écriture
education_level string ≤ 100 lecture et écriture
languages_required string ≤ 200 lecture et écriture
skills_required string lecture et écriture
skills_preferred string lecture et écriture
tags string ≤ 500 lecture et écriture
salary_min decimal lecture et écriture
salary_max decimal lecture et écriture
salary_currency string ≤ 3 lecture et écriture
salary_period choice
hour, month, year
lecture et écriture
expected_start_date date lecture et écriture
application_deadline date lecture et écriture
is_active boolean lecture et écriture
is_featured boolean lecture et écriture
is_urgent boolean lecture et écriture
published_date datetime lecture seule
seo_title string ≤ 70 lecture et écriture
seo_description string ≤ 160 lecture et écriture
og_image id lecture seule
created_at datetime lecture seule
updated_at datetime lecture seule

/api/v1/faq/

GETPOSTPUTPATCH

  • Filtres category__slug is_featured
  • search question answer
  • ordering order updated_at (par défaut order)
ChampType de champAccès
id integer lecture seule
question string ≤ 300 lecture et écriture obligatoire à la création
answer string lecture et écriture obligatoire à la création
category object lecture seule
category_slug slug écriture seule
is_featured boolean lecture et écriture
order integer lecture et écriture
updated_at datetime lecture seule

/api/v1/bookable-items/

GET

ChampType de champAccès
id integer lecture seule
label string lecture seule
duration_minutes integer lecture seule
price decimal lecture seule
currency string lecture seule
updated_at datetime lecture seule

/api/v1/bookings/

POST

ChampType de champAccès
item integer lecture et écriture obligatoire à la création
customer_name string ≤ 120 lecture et écriture obligatoire à la création
customer_email email lecture et écriture obligatoire à la création
customer_phone string ≤ 40 lecture et écriture
date date lecture et écriture obligatoire à la création
time string lecture et écriture obligatoire à la création
note string lecture et écriture

Recommandations de sécurité#

  • Conservez les clés sur votre serveur. Ne diffusez jamais une clé dans une application mobile ou dans du code exécuté dans le navigateur.
  • Utilisez une clé read partout où vous n'avez pas besoin d'écrire.
  • Une clé par intégration : en révoquer une ne casse pas les autres.