Developers

API del sito#

Legga e scriva il contenuto di un sito NAMES LEGAL tramite HTTPS: servizi, progetti, articoli del blog, membri del team, eventi, offerte di lavoro, FAQ e altro. L'API fa parte dell'add-on Accesso API del sito.

Guida rapida#

  1. Nella console del sito, Moduli aggiuntivi e abbonamento: attivi Accesso API.
  2. Moduli → API: crei una chiave. La copi subito: viene mostrata una sola volta.
  3. Chiami 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 di base#

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

<site> è l'indirizzo proprio del sito (ecolehorizon.names.legal o il suo dominio personalizzato). Non c'è alcun prefisso di lingua nel percorso. v1 è l'unica versione; una modifica non retrocompatibile arriverebbe come v2 accanto ad essa.

L'URL radice elenca ogni raccolta. Un riferimento interattivo (Swagger) e lo schema OpenAPI sono disponibili su ogni sito:

URL Accesso
Riferimento interattivo /api/v1/docs/ Chiave API (qualsiasi ambito) o un account console
Schema OpenAPI 3 /api/v1/schema/ Chiave API (qualsiasi ambito) o un account console

Autenticazione#

  1. Il titolare del sito attiva l'add-on Accesso API.
  2. Nella console, Moduli → API, crea una chiave e ne sceglie l'ambito. La chiave completa viene mostrata una sola volta; vengono conservati solo un prefisso e un hash.
  3. Invii la chiave con ogni richiesta.
GET /api/v1/services/ HTTP/1.1
Host: ecolehorizon.names.legal
Authorization: Api-Key nlk_3fa9c2d1_Jx0...

Sono accettati anche Authorization: Bearer <key> e X-Api-Key: <key>. Le chiavi hanno la forma nlk_<8 caratteri esadecimali>_<secret>.

Ambiti#

Ambito Consente
read (predefinito) GET su ogni raccolta
write GET, POST, PUT, PATCH

L'ambito si applica all'intera chiave; non esiste un ambito per singola raccolta. Una chiave può essere revocata in qualsiasi momento dalla console.

Errori che potrebbe incontrare#

Stato Significato
401 Chiave mancante, sconosciuta o revocata: {"detail": "Invalid API key."}
403 L'add-on non è attivo, oppure una chiave read ha tentato di scrivere
404 /docs/ e /schema/ quando l'add-on non è attivo
405 DELETE — l'eliminazione si effettua solo dalla console
429 Limite di frequenza superato
400 Errore di validazione: {"field": ["message"]}

Lingua#

I campi tradotti vengono restituiti in una lingua alla volta. La scelga con ?lang=:

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

La lingua deve essere una di quelle pubblicate dal sito; in caso contrario la risposta è 400. Senza lang, viene utilizzata la lingua predefinita del sito. La risposta contiene un'intestazione Content-Language.

Paginazione, filtri e ordinamento#

Gli elenchi sono paginati per numero di pagina:

{
  "count": 42,
  "next": "https://ecolehorizon.names.legal/api/v1/team/?page=2",
  "previous": null,
  "results": [ ... ]
}
Parametro Effetto
page, page_size Numero e dimensione della pagina (predefinito 25, massimo 100)
search Ricerca full-text sui principali campi testuali della raccolta
ordering Campo di ordinamento, - per ordine decrescente: ?ordering=-updated_at
filtri sui campi Corrispondenza esatta, ad esempio ?category__slug=bachelor&is_featured=true
since Solo le schede modificate a partire da una data: ?since=2026-09-01T00:00:00Z

since rende economica la sincronizzazione incrementale: memorizzi l'orario della Sua ultima chiamata e lo passi alla successiva.

Limiti di frequenza#

  • 120 richieste al minuto per chiave API (ogni chiave ha un proprio contatore).
  • Sessioni console: 120 al minuto. Chiamate anonime: 30 al minuto.

Superato il limite, l'API risponde 429; attenda e riprovi.

Raccolte#

Percorso Metodi Note
services/ GET, POST, PUT, PATCH Categoria tramite category_slug (facoltativo)
projects/ GET, POST, PUT, PATCH category_slug obbligatorio
blog/ GET, POST, PUT, PATCH Solo articoli pubblicati; category_slug obbligatorio
team/ GET, POST, PUT, PATCH Solo membri attivi
testimonials/ GET, POST, PUT, PATCH Solo testimonianze reali
publications/ GET, POST, PUT, PATCH category_slug facoltativo
resources/ GET, POST, PUT, PATCH Il file stesso è gestito nella console
events/ GET, POST, PUT, PATCH Date in ISO 8601
jobs/ GET, POST, PUT, PATCH Solo posizioni aperte; category_slug obbligatorio
faq/ GET, POST, PUT, PATCH category_slug facoltativo
bookable-items/ GET Richiede l'add-on Appuntamenti
bookings/ POST Crea una prenotazione; richiede una chiave write

Ogni scheda è raggiungibile all'indirizzo <collection>/<id>/. I campi di ogni raccolta sono elencati nel riferimento seguente.

Scrittura#

  • POST crea, PUT sostituisce, PATCH aggiorna alcuni campi.
  • Le categorie vengono lette come un oggetto {"id", "name", "slug"} e scritte con category_slug. Uno slug sconosciuto viene rifiutato.
  • Immagini e file sono di sola lettura nell'API: li carichi nella console, oppure lasci che il connettore di dati li scarichi da un URL.
  • L'HTML inviato nei campi di testo formattato viene ripulito: script e gestori di eventi vengono rimossi.
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>"}'

Prenotare un appuntamento#

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 è espresso nel fuso orario del sito. Uno slot non più disponibile viene rifiutato con 400. Le nuove prenotazioni iniziano come pending.

Ricette#

Sincronizzare una raccolta in modo incrementale#

Legga tutto una prima volta, poi solo ciò che è cambiato. Memorizzi l'orario della Sua esecuzione precedente e lo passi come 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);
}

Creare o aggiornare una scheda#

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 decide in quale lingua viene scritto un campo tradotto: invii di nuovo la stessa scheda con ?lang=en per aggiungere la versione inglese.

Errori e limiti in pratica#

Situazione Cosa fare
429 Too Many Requests Attenda il numero di secondi indicato nell'intestazione Retry-After, poi riprovi.
400 in scrittura Legga il corpo: ogni campo elenca i propri problemi, {"category_slug": ["Object with slug=x does not exist."]}.
403 con una richiesta write La chiave è read: crei una chiave read and write.
401 La chiave è stata revocata o digitata in modo errato.
Errore di rete o 5xx Riprovi con un ritardo crescente (1 s, 2 s, 4 s…). Le letture possono essere riprovate in sicurezza; per POST, verifichi prima che la scheda non sia già stata creata.

Riferimento per raccolta#

Generato dal codice dell'API: campi, diritti di accesso e parametri di query sono sempre quelli della piattaforma in esecuzione. I campi tradotti vengono letti e scritti nella lingua scelta con lang.

/api/v1/services/

GETPOSTPUTPATCH

  • Filtri slug category__slug is_featured
  • search title description
  • ordering order title updated_at (predefinito order)
CampoTipo di campoAccesso
id integer sola lettura
slug string ≤ 200 lettura e scrittura
title string ≤ 100 lettura e scrittura obbligatorio in creazione
description string lettura e scrittura obbligatorio in creazione
icon string ≤ 50 lettura e scrittura obbligatorio in creazione
color string ≤ 25 lettura e scrittura
category object sola lettura
category_slug slug solo scrittura
is_featured boolean lettura e scrittura
order integer lettura e scrittura
seo_title string ≤ 70 lettura e scrittura
seo_description string ≤ 160 lettura e scrittura
og_image id sola lettura
updated_at datetime sola lettura

/api/v1/projects/

GETPOSTPUTPATCH

  • Filtri slug category__slug status is_featured
  • search title description client technologies
  • ordering order title project_date updated_at (predefinito order)
CampoTipo di campoAccesso
id integer sola lettura
slug string ≤ 50 lettura e scrittura obbligatorio in creazione
title string ≤ 150 lettura e scrittura obbligatorio in creazione
description string lettura e scrittura obbligatorio in creazione
detailed_description string lettura e scrittura
category object sola lettura
category_slug slug solo scrittura obbligatorio in creazione
client string ≤ 100 lettura e scrittura
status choice
completed, in_progress, on_hold, planning
lettura e scrittura
project_date string ≤ 20 lettura e scrittura
duration string ≤ 50 lettura e scrittura
team_size string ≤ 50 lettura e scrittura
technologies string ≤ 200 lettura e scrittura
tags string ≤ 200 lettura e scrittura
image file (URL) sola lettura
demo_url url ≤ 200 lettura e scrittura
project_url url ≤ 200 lettura e scrittura
github_url url ≤ 200 lettura e scrittura
is_featured boolean lettura e scrittura
order integer lettura e scrittura
seo_title string ≤ 70 lettura e scrittura
seo_description string ≤ 160 lettura e scrittura
og_image id sola lettura
created_at datetime sola lettura
updated_at datetime sola lettura

/api/v1/blog/

GETPOSTPUTPATCH

  • Filtri slug category__slug status tags__slug
  • search title excerpt content
  • ordering published_date title updated_at (predefinito -published_date)
CampoTipo di campoAccesso
id integer sola lettura
slug string ≤ 200 lettura e scrittura obbligatorio in creazione
title string ≤ 200 lettura e scrittura obbligatorio in creazione
excerpt string ≤ 500 lettura e scrittura obbligatorio in creazione
content string lettura e scrittura obbligatorio in creazione
category object sola lettura
category_slug slug solo scrittura obbligatorio in creazione
tags list of slug sola lettura
featured_image file (URL) sola lettura
published_date datetime lettura e scrittura
read_time integer lettura e scrittura
status choice
draft, published, featured
lettura e scrittura
order integer lettura e scrittura
seo_title string ≤ 70 lettura e scrittura
seo_description string ≤ 160 lettura e scrittura
og_image id sola lettura
updated_at datetime sola lettura

/api/v1/team/

GETPOSTPUTPATCH

  • Filtri member_type is_featured
  • search first_name last_name position specialties
  • ordering order last_name updated_at (predefinito order)
CampoTipo di campoAccesso
id integer sola lettura
first_name string ≤ 100 lettura e scrittura obbligatorio in creazione
last_name string ≤ 100 lettura e scrittura obbligatorio in creazione
position string ≤ 150 lettura e scrittura obbligatorio in creazione
short_bio string ≤ 300 lettura e scrittura
bio string lettura e scrittura
profile_image file (URL) sola lettura
email email ≤ 254 lettura e scrittura
phone string ≤ 20 lettura e scrittura
linkedin url ≤ 200 lettura e scrittura
github url ≤ 200 lettura e scrittura
twitter url ≤ 200 lettura e scrittura
instagram url ≤ 200 lettura e scrittura
facebook url ≤ 200 lettura e scrittura
website url ≤ 200 lettura e scrittura
specialties string ≤ 200 lettura e scrittura
years_experience integer lettura e scrittura
education string ≤ 200 lettura e scrittura
location string ≤ 100 lettura e scrittura
languages string ≤ 100 lettura e scrittura
member_type choice
founder, lead, senior, developer, designer, manager, consultant, intern
lettura e scrittura
is_featured boolean lettura e scrittura
order integer lettura e scrittura
updated_at datetime sola lettura

/api/v1/testimonials/

GETPOSTPUTPATCH

  • Filtri rating
  • search name position testimonial
  • ordering order rating updated_at (predefinito order)
CampoTipo di campoAccesso
id integer sola lettura
name string ≤ 100 lettura e scrittura obbligatorio in creazione
position string ≤ 100 lettura e scrittura obbligatorio in creazione
testimonial string lettura e scrittura obbligatorio in creazione
rating integer lettura e scrittura
image file (URL) sola lettura
order integer lettura e scrittura
updated_at datetime sola lettura

/api/v1/publications/

GETPOSTPUTPATCH

  • Filtri slug category__slug year is_featured
  • search title authors journal abstract
  • ordering order year title updated_at (predefinito order,-year)
CampoTipo di campoAccesso
id integer sola lettura
slug string ≤ 200 lettura e scrittura
title string ≤ 255 lettura e scrittura obbligatorio in creazione
authors string ≤ 255 lettura e scrittura obbligatorio in creazione
journal string ≤ 255 lettura e scrittura
year string ≤ 10 lettura e scrittura obbligatorio in creazione
abstract string lettura e scrittura
link url ≤ 200 lettura e scrittura
category object sola lettura
category_slug slug solo scrittura
is_featured boolean lettura e scrittura
order integer lettura e scrittura
seo_title string ≤ 70 lettura e scrittura
seo_description string ≤ 160 lettura e scrittura
og_image id sola lettura
updated_at datetime sola lettura

/api/v1/resources/

GETPOSTPUTPATCH

  • Filtri slug resource_type is_free
  • search title description
  • ordering order title created_at updated_at (predefinito order)
CampoTipo di campoAccesso
id integer sola lettura
slug string ≤ 200 lettura e scrittura obbligatorio in creazione
title string ≤ 200 lettura e scrittura obbligatorio in creazione
description string lettura e scrittura obbligatorio in creazione
resource_type choice
guide, ebook, whitepaper, template, checklist, case_study
lettura e scrittura
file file (URL) sola lettura
file_size string sola lettura
thumbnail file (URL) sola lettura
is_free boolean lettura e scrittura
requires_email boolean lettura e scrittura
order integer lettura e scrittura
seo_title string ≤ 70 lettura e scrittura
seo_description string ≤ 160 lettura e scrittura
og_image id sola lettura
created_at datetime sola lettura
updated_at datetime sola lettura

/api/v1/events/

GETPOSTPUTPATCH

  • Filtri slug event_type is_online is_featured
  • search title description location
  • ordering start_date title updated_at (predefinito -start_date)
CampoTipo di campoAccesso
id integer sola lettura
slug string ≤ 200 lettura e scrittura obbligatorio in creazione
title string ≤ 200 lettura e scrittura obbligatorio in creazione
description string lettura e scrittura obbligatorio in creazione
event_type choice
conference, workshop, webinar, seminar, training, meeting
lettura e scrittura
start_date datetime lettura e scrittura obbligatorio in creazione
end_date datetime lettura e scrittura obbligatorio in creazione
timezone string ≤ 64 lettura e scrittura
location string ≤ 200 lettura e scrittura obbligatorio in creazione
is_online boolean lettura e scrittura
meeting_url url ≤ 200 lettura e scrittura
registration_url url ≤ 200 lettura e scrittura
registration_deadline datetime lettura e scrittura
max_attendees integer lettura e scrittura
featured_image file (URL) sola lettura
is_featured boolean lettura e scrittura
order integer lettura e scrittura
seo_title string ≤ 70 lettura e scrittura
seo_description string ≤ 160 lettura e scrittura
og_image id sola lettura
created_at datetime sola lettura
updated_at datetime sola lettura

/api/v1/jobs/

GETPOSTPUTPATCH

  • Filtri 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 (predefinito -published_date)
CampoTipo di campoAccesso
id integer sola lettura
slug string ≤ 50 lettura e scrittura
title string ≤ 200 lettura e scrittura obbligatorio in creazione
description string lettura e scrittura obbligatorio in creazione
responsibilities string lettura e scrittura
requirements string lettura e scrittura obbligatorio in creazione
qualifications string lettura e scrittura
benefits string lettura e scrittura
category object sola lettura
category_slug slug solo scrittura obbligatorio in creazione
location string ≤ 200 lettura e scrittura obbligatorio in creazione
contract_type choice
full_time, part_time, contract, freelance, internship, temporary
lettura e scrittura
remote_option choice
onsite, remote, hybrid
lettura e scrittura
experience_level choice
entry, junior, mid, senior, lead, executive
lettura e scrittura
education_level string ≤ 100 lettura e scrittura
languages_required string ≤ 200 lettura e scrittura
skills_required string lettura e scrittura
skills_preferred string lettura e scrittura
tags string ≤ 500 lettura e scrittura
salary_min decimal lettura e scrittura
salary_max decimal lettura e scrittura
salary_currency string ≤ 3 lettura e scrittura
salary_period choice
hour, month, year
lettura e scrittura
expected_start_date date lettura e scrittura
application_deadline date lettura e scrittura
is_active boolean lettura e scrittura
is_featured boolean lettura e scrittura
is_urgent boolean lettura e scrittura
published_date datetime sola lettura
seo_title string ≤ 70 lettura e scrittura
seo_description string ≤ 160 lettura e scrittura
og_image id sola lettura
created_at datetime sola lettura
updated_at datetime sola lettura

/api/v1/faq/

GETPOSTPUTPATCH

  • Filtri category__slug is_featured
  • search question answer
  • ordering order updated_at (predefinito order)
CampoTipo di campoAccesso
id integer sola lettura
question string ≤ 300 lettura e scrittura obbligatorio in creazione
answer string lettura e scrittura obbligatorio in creazione
category object sola lettura
category_slug slug solo scrittura
is_featured boolean lettura e scrittura
order integer lettura e scrittura
updated_at datetime sola lettura

/api/v1/bookable-items/

GET

CampoTipo di campoAccesso
id integer sola lettura
label string sola lettura
duration_minutes integer sola lettura
price decimal sola lettura
currency string sola lettura
updated_at datetime sola lettura

/api/v1/bookings/

POST

CampoTipo di campoAccesso
item integer lettura e scrittura obbligatorio in creazione
customer_name string ≤ 120 lettura e scrittura obbligatorio in creazione
customer_email email lettura e scrittura obbligatorio in creazione
customer_phone string ≤ 40 lettura e scrittura
date date lettura e scrittura obbligatorio in creazione
time string lettura e scrittura obbligatorio in creazione
note string lettura e scrittura

Raccomandazioni di sicurezza#

  • Conservi le chiavi sul Suo server. Non includa mai una chiave in un'app mobile o nel codice del browser.
  • Utilizzi una chiave read ovunque non sia necessario scrivere.
  • Una chiave per ogni integrazione: revocarne una non compromette le altre.