Meridian handbook
ReferenceConfiguration

endpoints.yaml

Every top-level key of config/sites/<key>/endpoints.yaml: declared endpoints with their path, methods, access, rate limit, spam controls, inputs, validation, steps and response.

config/sites/<key>/endpoints.yaml declares the site’s endpoints: enquiry and contact forms, newsletter sign-up and other actions a page posts to. Each validates its inputs, runs its steps in order and responds with a fragment or a redirect.

endpoints:
  - key: contact
    path: /contact
    methods: [post]
    access: public
    rate_limit: 5/hour/ip
    input:
      email: { type: text, format: email, required: true, label: { en-GB: Your email address } }
      message: { type: text, multiline: true, max: 2000, label: { en-GB: Your message } }
    steps:
      - store: { as: enquiry, retention: 90d }
      - mail: { template: enquiry-receipt, to: $email }
    respond:
      fragment: partials/contact-sent.html
      on_error: partials/contact-form.html

engine-dmo dev endpoint add <key> --from recipe:enquiry (or recipe:newsletter) adds one from a recipe. Forms and submissions covers inputs, steps and responses in full.

The verb writes the endpoint and exits 0, but leaves its templates to you, so engine-dmo check fails until they exist: the respond fragments under partials/, and one email template for each mail step. A mail step’s template: enquiry-receipt is the file emails/enquiry-receipt.html in one of the site’s template roots, such as templates/_shared/emails/enquiry-receipt.html; the check’s message (which is not under templates/emails/) means the emails/ folder of any root.

Give each input’s label in every locale the site serves. check warns about a schema label missing a locale, but not about an endpoint input’s.

KeyTypeDefaultMeaning
endpointslist of objects[]The site’s declared endpoints
endpoints[].accessmember, public, staffpublicpublic, member or staff
endpoints[].cachestringA duration a get response may be cached for
endpoints[].csrfbooleantrueRequire the CSRF token. false only for a machine caller with its own authentication
endpoints[].idstringWritten for youThe element’s stable id. Written by engine-dmo check --fix; never write or change it by hand
endpoints[].inputobjectThe inputs by name, each with a type (text, boolean, relation and the rest), required, limits, label per locale and where it is read from
endpoints[].keystringRequiredThe endpoint’s key: lower case letters, digits and hyphens. Templates name it, as in enquiryForm('contact')
endpoints[].methodslist of stringRequiredget and or post
endpoints[].pathstringRequiredThe path it answers on, with placeholders such as {listing} that input can read from: path
endpoints[].permissionstringThe permission a staff or member caller needs
endpoints[].rate_limitanyThe class default<count>/<window>/<key>: window second, minute, hour or day; key ip, session, person, organisation or endpoint. Such as 5/hour/ip
endpoints[].respondmap of anyRequiredExactly one shape: fragment (a template), location (a redirect), json (a projection) or stream; plus on_error, the template for a submission with errors (not with json)
endpoints[].spam.honeypotbooleanendpoints.defaults.spam.honeypotThe hidden field
endpoints[].spam.min_fill_timestringendpoints.defaults.spam.min_fill_timeThe shortest believable time to fill the form
endpoints[].spam.proof_of_workbooleanendpoints.defaults.spam.proof_of_workThe proof-of-work challenge
endpoints[].stepslist of map of anyRequiredWhat a valid submission does, in order. Core steps: mail, audit, signal, analytics, query, source, job, webhook, plugin; the Forms module adds store and the Newsletter module subscribe
endpoints[].validationlist of objects[]Cross-field rules, as in a schema’s validation
endpoints[].validation[].fieldslist of stringThe inputs the message is shown against
endpoints[].validation[].messagemap of stringRequiredThe message per locale
endpoints[].validation[].rulestringRequiredThe rule expression, such as message != empty
endpoints[].validation[].severitystringerrorerror or warning