Documentation
API and AI-driven management.
A JEIKO site can be run by hand from its admin panel, or by a program. This page covers the second route: how an agent works, what you entrust to it, and every route it has at its disposal.
Documentation
A JEIKO site can be run by hand from its admin panel, or by a program. This page covers the second route: how an agent works, what you entrust to it, and every route it has at its disposal.
An agent has no privileged access to the site. It receives a mandate — a token, roles, an expiry date, a call limit — and goes through the same checks as an administrator working by hand in the interface. It never touches the database directly: there is no back door to open, and nothing to close if the mandate slips out of your hands.
In practice, that means three things.
The manual is generated
The agent starts by reading GET /. That document is not written by hand: routes are read from the router, permissions from the views, block types from the model. So it cannot describe an API that no longer exists.
Everything is logged
Every call leaves a line in the log: the agent, the route, the object touched, the outcome. You know afterwards who wrote what, and the admin panel shows it without anyone reading files on the server.
Refusals are explicit
An unknown key in a request body is refused, never silently swallowed. That is the difference between a call that fails and gets fixed, and a call that succeeds while producing nothing — the costliest defect there is.
An agent cannot delete a page, nor publish one without an explicit step. Neither limit is an oversight: a deleted page cannot be recovered, and going live is an editorial decision.
The manual lives at the root of the API. It is generated from the code — routes are read from the router, permissions from the view classes, block options from the constants the renderer applies. So it cannot describe a route that does not exist, or leave a permission unsaid.
GET https://yoursite.com/api/agent/v1/
Authorization: Bearer jk_ag_<prefix>_<secret>
{
"version": { "numero": "1" },
"points_d_entree": [ … every route, each with its permission … ],
"catalogue_des_blocs": { … every content type … },
"champs_de_page": { … },
"interdits": [ … ]
}
A bearer token, and nothing else. Seven guards stack up before a call reaches a view.
Refusals do not explain themselves: same message, same code, whatever the cause. The precise reason goes to the log, which is for the site owner — spelling it out would tell a hostile caller how close they are.
Each one states the permission it requires: an agent knows before calling whether it is allowed to, rather than finding out from a refusal.
| Method | Path | Purpose | Permission |
|---|---|---|---|
| GET | / | This manual. Read it first. | none — a valid token is enough |
| GET | /guide/ | The same manual, at an address that is easy to remember. | none — a valid token is enough |
| GET | /contrats/ | The exact shape of every call: description, JSON schema of the body and filters, every field described. | none — a valid token is enough |
| GET | /qui-suis-je/ | Who I am, and what I am allowed to do. | none — a valid token is enough |
| GET | /pages/ | The list of the site's pages. | administration_pages.view_page |
| POST | /pages/creer/ | Create a page. It starts as a draft. | administration_pages.add_page |
| GET, PATCH | /pages/<int:page_id>/ | The full tree of a page; PATCH edits its fields. | administration_pages.view_page |
| POST | /pages/<int:page_id>/sections/ | Add a section to a page. | administration_pages.change_page |
| POST | /pages/<int:page_id>/versions/ | Create a page's version in another language, by duplication — a draft, to translate by hand. | administration_pages.add_page |
| GET, PATCH | /langues/ | The multilingual site: the option and the added languages. Removing a language UNPUBLISHES its pages and records. | administration.view_website |
| GET | /pages/<int:page_id>/mesures/ | PageSpeed scores, Core Web Vitals and failed audits. Read-only; mesure_obsolete flags a URL that differs from the current one. | administration_pages.view_page |
| GET, PATCH, DELETE | /sections/<int:section_id>/ | A section and its settings. | administration_pages.change_page |
| POST | /sections/<int:section_id>/lignes/ | Add a row to a section. | administration_pages.change_page |
| GET, PATCH, DELETE | /lignes/<int:ligne_id>/ | A row and its settings. | administration_pages.change_page |
| POST | /lignes/<int:ligne_id>/blocs/ | Add a block to one of the row's columns. | administration_pages.change_page |
| GET, PATCH, DELETE | /blocs/<int:bloc_id>/ | A block and its settings. | administration_pages.change_page |
| PUT | /blocs/<int:bloc_id>/contenu/ | Set or replace a block's content. | administration_pages.change_page |
| POST | /deplacer/<str:niveau>/<int:element_id>/ | Move a section, row or block up or down; or send a row to another section (« vers_section »), a block to another row (« vers_ligne », « colonne »). | administration_pages.change_page |
| GET | /images/ | The media library, read-only. Gives you the IDs to reuse. | administration_pages.view_page |
| POST | /images/creer/ | Upload an image to the media library: as JSON with « fichier_base64 » (what the MCP server uses), or multipart with « fichier ». Plus title, alt or decorative. | administration_pages.add_imagecontent |
| GET | /rdv/types/ | Appointment types. Their duration slices the availability. | calendars.view_appointmenttype |
| POST | /rdv/types/creer/ | Create an appointment type. | calendars.add_appointmenttype |
| GET, PATCH | /rdv/types/<int:type_id>/ | A type: duration, capacity, price, waiting list. | calendars.view_appointmenttype |
| GET | /rdv/disponibilites/ | The time ranges declared available. | calendars.view_availability |
| POST | /rdv/disponibilites/creer/ | Declare a time range — it GENERATES its slots. | calendars.add_availability |
| GET, PATCH, DELETE | /rdv/disponibilites/<int:dispo_id>/ | A time range. Deletion is refused if appointments are booked in it. | calendars.view_availability |
| GET | /rdv/creneaux/ | The generated slots — READ-ONLY. Filters: type, depuis, jusqu_a, ouverts. | calendars.view_availability |
| GET | /rdv/ | Booked appointments. Read-only, with a separate permission: personal data. | calendars.view_appointment |
| GET | /menus/ | Menus, their tree and the categories they serve. | administration_menu.view_menu |
| POST | /menus/creer/ | Create a menu — « copie_de » duplicates an existing one, tree included. | administration_menu.add_menu |
| GET, PATCH | /menus/<int:menu_id>/ | A menu; sending « elements » REPLACES its tree. | administration_menu.view_menu |
| PATCH | /categories/<int:categorie_id>/menus/ | Assign menus to a category — this is what makes sub-sites possible. | administration_menu.change_menu |
| GET, PATCH | /identite/ | Theme colours and site fonts. Partial updates. | administration.view_website |
| GET | /emails/evenements/ | The 67 email events and THEIR KEYS. Read before writing an email. | emailing.view_emailtemplate |
| GET | /emails/ | Configured emails. | emailing.view_emailtemplate |
| POST | /emails/creer/ | Dress an event: subject, body page (unpublished, or already an email template — a live page is refused: it would vanish from the site). Starts INACTIVE. | emailing.add_emailtemplate |
| GET, PATCH | /emails/<int:email_id>/ | An email: subject, body, sender, activation. | emailing.view_emailtemplate |
| GET | /questionnaires/ | Expert questionnaires. | questionnaires_expert.view_experttest |
| POST | /questionnaires/creer/ | Create a questionnaire. It starts INACTIVE. | questionnaires_expert.add_experttest |
| GET, PATCH | /questionnaires/<int:test_id>/ | The full tree: profiles, questions, answers, weights, combinations. | questionnaires_expert.view_experttest |
| POST | /questionnaires/<int:test_id>/profils/ | Add a profile — a possible outcome, with its page. | questionnaires_expert.change_experttest |
| POST | /questionnaires/<int:test_id>/questions/ | Add a question, its answers and their weights. | questionnaires_expert.change_experttest |
| POST | /questionnaires/<int:test_id>/combinaisons/ | Add a combination — settling two close profiles. | questionnaires_expert.change_experttest |
| POST | /questionnaires/<int:test_id>/simuler/ | « Dimensions » mode: build the result page for given scores, without saving anything. | questionnaires_expert.view_experttest |
| PATCH | /profils/<int:profil_id>/ | A profile. Its slug cannot change: it is in the result URL. | questionnaires_expert.change_experttest |
| PATCH, DELETE | /questions/<int:question_id>/ | A question; sending « reponses » REPLACES the list, weights included. Deletion refused once the test has been taken. | questionnaires_expert.change_experttest |
| DELETE | /reponses/<int:reponse_id>/ | Delete a single answer, without rewriting the others. | questionnaires_expert.change_experttest |
| PATCH | /combinaisons/<int:combinaison_id>/ | A combination and its criteria. | questionnaires_expert.change_experttest |
| GET | /categories/ | Categories and subcategories, with their slugs. | administration_pages.view_page |
| POST | /categories/creer/ | Create a category. « afficher_dans_l_url » puts it in page addresses. | administration_pages.add_page |
| GET, PATCH, DELETE | /categories/<int:categorie_id>/ | Correct a category. The slug never changes: it is in the addresses. Deletion only accepts an EMPTY category. | administration_pages.change_page |
| GET | /modeles/ | Record types and their fields. Read before creating one. | custom_objects.view_customobject |
| POST | /modeles/creer/ | Create a record type with its fields, and mark its template page. | custom_objects.add_customobjectmodel |
| GET, PATCH | /modeles/<int:modele_id>/ | A record type; PATCH ADDS fields, never renames one. | custom_objects.view_customobject |
| GET | /types-de-produit/ | Product types — the commercial layer. | shop.view_producttype |
| POST | /types-de-produit/creer/ | Create a product type. « expedition » decides whether it consumes stock. | shop.add_producttype |
| GET, PATCH | /types-de-produit/<int:type_id>/ | Correct a product type. The code never changes: it is in the URLs. | shop.view_producttype |
| GET | /objets/ | Existing records. ?modele=<id-or-slug> to filter, ?langue=en for one language's versions only. | custom_objects.view_customobject |
| GET | /fiches/ | Business alias of /objets/: existing records, with the same ?modele= filter. | custom_objects.view_customobject |
| POST | /objets/creer/ | Create a record. It starts unpublished. | custom_objects.add_customobject |
| GET, PATCH | /objets/<int:objet_id>/ | A record and its values; PATCH edits part of them. | custom_objects.view_customobject |
| POST | /objets/<int:objet_id>/versions/ | Create a record's version in another language, by duplication — unpublished, to translate by hand. | custom_objects.add_customobject |
| GET | /produits/ | Products. | shop.view_product |
| POST | /produits/creer/ | Create a product on an existing record. | shop.add_product |
| GET, PATCH | /produits/<int:produit_id>/ | A product: SKU, price, VAT, stock. | shop.view_product |
One mandate per area, granted and revoked separately. You do not give an agent that writes pages the right to read booked appointments.
The refusals are not decorative precautions: each one closes a case where the database would have accepted something unusable.
The text below can be pasted as is into the instructions of a Claude project, an agent, or any assistant able to call an API. Replace the two values in square brackets with your site's address and the key you created under Settings ▸ AI agents.
The key gives access to your site. Never put it in a public repository, and create one per use: each carries its own roles, expiry date and call limit, and can be revoked on its own.
You can manage a JEIKO site through its API.
Site : [SITE ADDRESS]
Key : [API KEY]
FIRST CALL, BEFORE ANY OTHER
Read the manual. It is generated from the site's code: routes come from
the router, permissions from the view classes, block options from the
constants the renderer applies. So it can neither describe a missing route
nor leave a permission unsaid.
GET [SITE ADDRESS]/api/agent/v1/
Header: Authorization: Bearer [API KEY]
It gives you: the API version, the full list of routes with the permission
each one requires, the catalogue of block types with their options and
fields, the editable fields of a page, and the list of what is forbidden.
GET [SITE ADDRESS]/api/agent/v1/qui-suis-je/
It tells you your roles and permissions. Check it before concluding that an
action is impossible: it may simply not have been granted to you.
STRUCTURE OF A PAGE
page → sections → rows (lignes) → blocks (blocs) → content
Four traps, in order of importance:
1. « colonne » is a COLUMN NUMBER, not a vertical position. The position is
« rang ».
2. The column layout — columns_type, columns_type_tablet, columns_type_phone —
must have AS MANY SEGMENTS AS THE ROW HAS COLUMNS. « 4-4-4 » for three
columns side by side, « 12-12-12 » for the same stacked. A row created with
« colonnes: 3 » is already described that way: only touch it to depart from
it, an « 8-4 » for instance.
3. A link (a tag) cannot wrap blocks. HTML sanitising splits a link that
contains paragraphs, and the card falls apart. Put the link on the title.
4. The style attribute is CUT DOWN to six properties: color, background-color,
text-align, font-weight, font-style, text-decoration. Anything that lays
things out — backgrounds of boxes, borders, margins, sizes, alignment —
goes through the native settings of the section, row or block. CSS is a
last resort, almost never needed.
WHAT YOU CAN DO
Pages create, edit, publish, file into categories, translate
Content text, image, button, form, video, FAQ, tabs, carousels,
pricing tables, galleries…
Media upload images, with a description (alt)
Store record types, records, products, product types
Menus tree, duplication, assignment to categories
Identity theme colours, fonts on three devices
Emails subject and body of the sixty-seven events
Questionnaires profiles, questions, weights, combinations
Appointments types and availability
Each area is a separate role. If a route answers 403, you do not have that
role — it is not a mistake on your part.
WHAT YOU CANNOT DO, AND MUST NOT WORK AROUND
· delete a page — no route, no permission
· publish on creation — pages, records, products and questionnaires start
as drafts; going live is a separate call
· read questionnaire attempts, leads or email send logs: this is personal
data
WORKING RULES
· An unknown key is REFUSED, never ignored — in content as in settings. If
you get a 400, read the message: it names the accepted keys. Background
colours and images all live under « fond ».
· Sending a list — « elements », « champs », « reponses » — REPLACES the whole
list. Not sending it leaves the existing one untouched.
· Read back what you write. A write can succeed without producing anything;
reading back is the only way to notice.
· Check the real rendering on phone and tablet before saying it is done.
Many defects only show at 390 pixels wide.
· Write the search metadata as soon as you create a page. Nobody comes back
to add it.
WHEN IN DOUBT
The manual is authoritative, not this text. It is generated from the site
you are managing and describes its exact version.
Using Claude — claude.ai, the mobile app or Claude Code? The connector is simpler than this text to paste: no key to copy, and access is withdrawn in one click. See Connect Claude to your site.