Developers

API do site#

Leia e escreva o conteúdo de um site NAMES LEGAL através de HTTPS: serviços, projetos, publicações do blog, membros da equipa, eventos, ofertas de emprego, FAQ e muito mais. A API faz parte do add-on Acesso API do site.

Início rápido#

  1. Na consola do site, em Módulos e subscrição: ative Acesso API.
  2. Módulos → API: crie uma chave. Copie-a agora — é mostrada apenas uma vez.
  3. Chame a 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 base#

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

<site> é o próprio endereço do site (ecolehorizon.names.legal ou o seu domínio personalizado). Não existe prefixo de idioma no caminho. v1 é a única versão; uma alteração de rutura surgiria como v2 em paralelo.

O URL raiz lista todas as coleções. Uma referência interativa (Swagger) e o esquema OpenAPI estão disponíveis em cada site:

URL Acesso
Referência interativa /api/v1/docs/ Chave de API (qualquer âmbito) ou uma conta de consola
Esquema OpenAPI 3 /api/v1/schema/ Chave de API (qualquer âmbito) ou uma conta de consola

Autenticação#

  1. O proprietário do site ativa o add-on Acesso API.
  2. Na consola, em Módulos → API, cria uma chave e escolhe o seu âmbito. A chave completa é mostrada uma única vez; apenas um prefixo e um hash são armazenados.
  3. Envie a chave em cada pedido.
GET /api/v1/services/ HTTP/1.1
Host: ecolehorizon.names.legal
Authorization: Api-Key nlk_3fa9c2d1_Jx0...

Authorization: Bearer <key> e X-Api-Key: <key> também são aceites. As chaves têm o formato nlk_<8 caracteres hexadecimais>_<secret>.

Âmbitos#

Âmbito Permite
read (predefinido) GET em todas as coleções
write GET, POST, PUT, PATCH

O âmbito aplica-se à chave inteira; não existe um âmbito por coleção. Uma chave pode ser revogada a qualquer momento a partir da consola.

Erros que pode encontrar#

Estado Significado
401 Chave em falta, desconhecida ou revogada: {"detail": "Invalid API key."}
403 O add-on não está ativo, ou uma chave read tentou escrever
404 /docs/ e /schema/ quando o add-on não está ativo
405 DELETE — a eliminação só é feita a partir da consola
429 Limite de pedidos excedido
400 Erro de validação: {"field": ["message"]}

Idioma#

Os campos traduzidos são devolvidos num único idioma de cada vez. Escolha-o com ?lang=:

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

O idioma tem de ser um dos idiomas publicados pelo site; caso contrário, a resposta é 400. Sem lang, é utilizado o idioma predefinido do site. A resposta inclui um cabeçalho Content-Language.

Paginação, filtros e ordenação#

As listas são paginadas por número de página:

{
  "count": 42,
  "next": "https://ecolehorizon.names.legal/api/v1/team/?page=2",
  "previous": null,
  "results": [ ... ]
}
Parâmetro Efeito
page, page_size Número e tamanho da página (predefinição 25, máximo 100)
search Pesquisa de texto integral nos principais campos de texto da coleção
ordering Campo de ordenação, - para ordem descendente: ?ordering=-updated_at
filtros de campo Correspondência exata, por exemplo ?category__slug=bachelor&is_featured=true
since Apenas fichas alteradas desde uma data: ?since=2026-09-01T00:00:00Z

since torna a sincronização incremental económica: guarde o momento da última chamada e passe-o na chamada seguinte.

Limites de pedidos#

  • 120 pedidos por minuto por chave de API (cada chave tem o seu próprio contador).
  • Sessões de consola: 120 por minuto. Chamadas anónimas: 30 por minuto.

Acima do limite, a API responde 429; aguarde e tente novamente.

Coleções#

Caminho Métodos Notas
services/ GET, POST, PUT, PATCH Categoria por category_slug (opcional)
projects/ GET, POST, PUT, PATCH category_slug obrigatório
blog/ GET, POST, PUT, PATCH Apenas publicações publicadas; category_slug obrigatório
team/ GET, POST, PUT, PATCH Apenas membros ativos
testimonials/ GET, POST, PUT, PATCH Apenas testemunhos reais
publications/ GET, POST, PUT, PATCH category_slug opcional
resources/ GET, POST, PUT, PATCH O ficheiro em si é gerido na consola
events/ GET, POST, PUT, PATCH Datas em ISO 8601
jobs/ GET, POST, PUT, PATCH Apenas ofertas ativas; category_slug obrigatório
faq/ GET, POST, PUT, PATCH category_slug opcional
bookable-items/ GET Requer o add-on Marcações
bookings/ POST Cria uma marcação; requer uma chave write

Cada ficha está acessível em <collection>/<id>/. Os campos de cada coleção estão listados na referência abaixo.

Escrita#

  • POST cria, PUT substitui, PATCH atualiza alguns campos.
  • As categorias são lidas como um objeto {"id", "name", "slug"} e escritas com category_slug. Um slug desconhecido é recusado.
  • As imagens e os ficheiros são só de leitura na API: carregue-os na consola, ou deixe o conector de dados transferi-los a partir de um URL.
  • O HTML enviado em campos de texto formatado é limpo: scripts e manipuladores de eventos são removidos.
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>"}'

Marcar um compromisso#

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á no fuso horário do site. Um horário que já não esteja livre é recusado com 400. As novas marcações começam como pending.

Receitas#

Sincronizar uma coleção de forma incremental#

Leia tudo uma vez e depois apenas o que mudou. Guarde o momento da execução anterior e passe-o como 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);
}

Criar ou atualizar uma ficha#

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 em que idioma um campo traduzido é escrito: envie a mesma ficha novamente com ?lang=en para adicionar a versão em inglês.

Erros e limites na prática#

Situação O que fazer
429 Too Many Requests Aguarde o número de segundos indicado no cabeçalho Retry-After e tente novamente.
400 ao escrever Leia o corpo: cada campo lista os seus problemas, {"category_slug": ["Object with slug=x does not exist."]}.
403 com um pedido write A chave é read: crie uma chave read and write.
401 A chave foi revogada ou escrita incorretamente.
Erro de rede ou 5xx Tente novamente com um atraso crescente (1 s, 2 s, 4 s…). As leituras podem ser repetidas em segurança; para POST, verifique primeiro que a ficha ainda não foi criada.

Referência por coleção#

Gerada a partir do código da API: os campos, os direitos de acesso e os parâmetros de consulta são sempre os da plataforma em execução. Os campos traduzidos são lidos e escritos no idioma escolhido com lang.

/api/v1/services/

GETPOSTPUTPATCH

  • Filtros slug category__slug is_featured
  • search title description
  • ordering order title updated_at (predefinição order)
CampoTipo de campoAcesso
id integer apenas leitura
slug string ≤ 200 leitura e escrita
title string ≤ 100 leitura e escrita obrigatório ao criar
description string leitura e escrita obrigatório ao criar
icon string ≤ 50 leitura e escrita obrigatório ao criar
color string ≤ 25 leitura e escrita
category object apenas leitura
category_slug slug só escrita
is_featured boolean leitura e escrita
order integer leitura e escrita
seo_title string ≤ 70 leitura e escrita
seo_description string ≤ 160 leitura e escrita
og_image id apenas leitura
updated_at datetime apenas leitura

/api/v1/projects/

GETPOSTPUTPATCH

  • Filtros slug category__slug status is_featured
  • search title description client technologies
  • ordering order title project_date updated_at (predefinição order)
CampoTipo de campoAcesso
id integer apenas leitura
slug string ≤ 50 leitura e escrita obrigatório ao criar
title string ≤ 150 leitura e escrita obrigatório ao criar
description string leitura e escrita obrigatório ao criar
detailed_description string leitura e escrita
category object apenas leitura
category_slug slug só escrita obrigatório ao criar
client string ≤ 100 leitura e escrita
status choice
completed, in_progress, on_hold, planning
leitura e escrita
project_date string ≤ 20 leitura e escrita
duration string ≤ 50 leitura e escrita
team_size string ≤ 50 leitura e escrita
technologies string ≤ 200 leitura e escrita
tags string ≤ 200 leitura e escrita
image file (URL) apenas leitura
demo_url url ≤ 200 leitura e escrita
project_url url ≤ 200 leitura e escrita
github_url url ≤ 200 leitura e escrita
is_featured boolean leitura e escrita
order integer leitura e escrita
seo_title string ≤ 70 leitura e escrita
seo_description string ≤ 160 leitura e escrita
og_image id apenas leitura
created_at datetime apenas leitura
updated_at datetime apenas leitura

/api/v1/blog/

GETPOSTPUTPATCH

  • Filtros slug category__slug status tags__slug
  • search title excerpt content
  • ordering published_date title updated_at (predefinição -published_date)
CampoTipo de campoAcesso
id integer apenas leitura
slug string ≤ 200 leitura e escrita obrigatório ao criar
title string ≤ 200 leitura e escrita obrigatório ao criar
excerpt string ≤ 500 leitura e escrita obrigatório ao criar
content string leitura e escrita obrigatório ao criar
category object apenas leitura
category_slug slug só escrita obrigatório ao criar
tags list of slug apenas leitura
featured_image file (URL) apenas leitura
published_date datetime leitura e escrita
read_time integer leitura e escrita
status choice
draft, published, featured
leitura e escrita
order integer leitura e escrita
seo_title string ≤ 70 leitura e escrita
seo_description string ≤ 160 leitura e escrita
og_image id apenas leitura
updated_at datetime apenas leitura

/api/v1/team/

GETPOSTPUTPATCH

  • Filtros member_type is_featured
  • search first_name last_name position specialties
  • ordering order last_name updated_at (predefinição order)
CampoTipo de campoAcesso
id integer apenas leitura
first_name string ≤ 100 leitura e escrita obrigatório ao criar
last_name string ≤ 100 leitura e escrita obrigatório ao criar
position string ≤ 150 leitura e escrita obrigatório ao criar
short_bio string ≤ 300 leitura e escrita
bio string leitura e escrita
profile_image file (URL) apenas leitura
email email ≤ 254 leitura e escrita
phone string ≤ 20 leitura e escrita
linkedin url ≤ 200 leitura e escrita
github url ≤ 200 leitura e escrita
twitter url ≤ 200 leitura e escrita
instagram url ≤ 200 leitura e escrita
facebook url ≤ 200 leitura e escrita
website url ≤ 200 leitura e escrita
specialties string ≤ 200 leitura e escrita
years_experience integer leitura e escrita
education string ≤ 200 leitura e escrita
location string ≤ 100 leitura e escrita
languages string ≤ 100 leitura e escrita
member_type choice
founder, lead, senior, developer, designer, manager, consultant, intern
leitura e escrita
is_featured boolean leitura e escrita
order integer leitura e escrita
updated_at datetime apenas leitura

/api/v1/testimonials/

GETPOSTPUTPATCH

  • Filtros rating
  • search name position testimonial
  • ordering order rating updated_at (predefinição order)
CampoTipo de campoAcesso
id integer apenas leitura
name string ≤ 100 leitura e escrita obrigatório ao criar
position string ≤ 100 leitura e escrita obrigatório ao criar
testimonial string leitura e escrita obrigatório ao criar
rating integer leitura e escrita
image file (URL) apenas leitura
order integer leitura e escrita
updated_at datetime apenas leitura

/api/v1/publications/

GETPOSTPUTPATCH

  • Filtros slug category__slug year is_featured
  • search title authors journal abstract
  • ordering order year title updated_at (predefinição order,-year)
CampoTipo de campoAcesso
id integer apenas leitura
slug string ≤ 200 leitura e escrita
title string ≤ 255 leitura e escrita obrigatório ao criar
authors string ≤ 255 leitura e escrita obrigatório ao criar
journal string ≤ 255 leitura e escrita
year string ≤ 10 leitura e escrita obrigatório ao criar
abstract string leitura e escrita
link url ≤ 200 leitura e escrita
category object apenas leitura
category_slug slug só escrita
is_featured boolean leitura e escrita
order integer leitura e escrita
seo_title string ≤ 70 leitura e escrita
seo_description string ≤ 160 leitura e escrita
og_image id apenas leitura
updated_at datetime apenas leitura

/api/v1/resources/

GETPOSTPUTPATCH

  • Filtros slug resource_type is_free
  • search title description
  • ordering order title created_at updated_at (predefinição order)
CampoTipo de campoAcesso
id integer apenas leitura
slug string ≤ 200 leitura e escrita obrigatório ao criar
title string ≤ 200 leitura e escrita obrigatório ao criar
description string leitura e escrita obrigatório ao criar
resource_type choice
guide, ebook, whitepaper, template, checklist, case_study
leitura e escrita
file file (URL) apenas leitura
file_size string apenas leitura
thumbnail file (URL) apenas leitura
is_free boolean leitura e escrita
requires_email boolean leitura e escrita
order integer leitura e escrita
seo_title string ≤ 70 leitura e escrita
seo_description string ≤ 160 leitura e escrita
og_image id apenas leitura
created_at datetime apenas leitura
updated_at datetime apenas leitura

/api/v1/events/

GETPOSTPUTPATCH

  • Filtros slug event_type is_online is_featured
  • search title description location
  • ordering start_date title updated_at (predefinição -start_date)
CampoTipo de campoAcesso
id integer apenas leitura
slug string ≤ 200 leitura e escrita obrigatório ao criar
title string ≤ 200 leitura e escrita obrigatório ao criar
description string leitura e escrita obrigatório ao criar
event_type choice
conference, workshop, webinar, seminar, training, meeting
leitura e escrita
start_date datetime leitura e escrita obrigatório ao criar
end_date datetime leitura e escrita obrigatório ao criar
timezone string ≤ 64 leitura e escrita
location string ≤ 200 leitura e escrita obrigatório ao criar
is_online boolean leitura e escrita
meeting_url url ≤ 200 leitura e escrita
registration_url url ≤ 200 leitura e escrita
registration_deadline datetime leitura e escrita
max_attendees integer leitura e escrita
featured_image file (URL) apenas leitura
is_featured boolean leitura e escrita
order integer leitura e escrita
seo_title string ≤ 70 leitura e escrita
seo_description string ≤ 160 leitura e escrita
og_image id apenas leitura
created_at datetime apenas leitura
updated_at datetime apenas leitura

/api/v1/jobs/

GETPOSTPUTPATCH

  • Filtros 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 (predefinição -published_date)
CampoTipo de campoAcesso
id integer apenas leitura
slug string ≤ 50 leitura e escrita
title string ≤ 200 leitura e escrita obrigatório ao criar
description string leitura e escrita obrigatório ao criar
responsibilities string leitura e escrita
requirements string leitura e escrita obrigatório ao criar
qualifications string leitura e escrita
benefits string leitura e escrita
category object apenas leitura
category_slug slug só escrita obrigatório ao criar
location string ≤ 200 leitura e escrita obrigatório ao criar
contract_type choice
full_time, part_time, contract, freelance, internship, temporary
leitura e escrita
remote_option choice
onsite, remote, hybrid
leitura e escrita
experience_level choice
entry, junior, mid, senior, lead, executive
leitura e escrita
education_level string ≤ 100 leitura e escrita
languages_required string ≤ 200 leitura e escrita
skills_required string leitura e escrita
skills_preferred string leitura e escrita
tags string ≤ 500 leitura e escrita
salary_min decimal leitura e escrita
salary_max decimal leitura e escrita
salary_currency string ≤ 3 leitura e escrita
salary_period choice
hour, month, year
leitura e escrita
expected_start_date date leitura e escrita
application_deadline date leitura e escrita
is_active boolean leitura e escrita
is_featured boolean leitura e escrita
is_urgent boolean leitura e escrita
published_date datetime apenas leitura
seo_title string ≤ 70 leitura e escrita
seo_description string ≤ 160 leitura e escrita
og_image id apenas leitura
created_at datetime apenas leitura
updated_at datetime apenas leitura

/api/v1/faq/

GETPOSTPUTPATCH

  • Filtros category__slug is_featured
  • search question answer
  • ordering order updated_at (predefinição order)
CampoTipo de campoAcesso
id integer apenas leitura
question string ≤ 300 leitura e escrita obrigatório ao criar
answer string leitura e escrita obrigatório ao criar
category object apenas leitura
category_slug slug só escrita
is_featured boolean leitura e escrita
order integer leitura e escrita
updated_at datetime apenas leitura

/api/v1/bookable-items/

GET

CampoTipo de campoAcesso
id integer apenas leitura
label string apenas leitura
duration_minutes integer apenas leitura
price decimal apenas leitura
currency string apenas leitura
updated_at datetime apenas leitura

/api/v1/bookings/

POST

CampoTipo de campoAcesso
item integer leitura e escrita obrigatório ao criar
customer_name string ≤ 120 leitura e escrita obrigatório ao criar
customer_email email leitura e escrita obrigatório ao criar
customer_phone string ≤ 40 leitura e escrita
date date leitura e escrita obrigatório ao criar
time string leitura e escrita obrigatório ao criar
note string leitura e escrita

Recomendações de segurança#

  • Mantenha as chaves no seu servidor. Nunca inclua uma chave numa aplicação móvel ou em código do browser.
  • Utilize uma chave read sempre que não seja necessário escrever.
  • Uma chave por integração: revogar uma não afeta as outras.