Map templates with the API
Four routes manage the mappings of your current project: which template of your provider each Ovok message sends, per language and domain. Reading needs any practitioner; writing needs a project admin.
| Method | Path | Who |
|---|---|---|
GET | /v1/projects/me/email-templates | Any practitioner |
GET | /v1/projects/me/email-templates/:name | Any practitioner |
PUT | /v1/projects/me/email-templates/:name | A project admin |
DELETE | /v1/projects/me/email-templates/:name | A project admin |
:name is one of the template names. An unknown name answers 400 with code UNKNOWN_TEMPLATE and the list in acceptedNames.
Which mapping: language and domain
GET :name, PUT and DELETE identify a mapping by its template and its context, given in the query:
| Query | Description |
|---|---|
language | One of Ovok's locale codes, such as en-US or de-DE. A bare en is stored as en-US. Any other value answers 422, because a mail's language is always one of those. |
domain | A host name such as app.example.com, lower-cased, without scheme or port. |
Leave one out for a mapping that names none. They are matched exactly: ?language=en-US is not the same mapping as no context. Unknown query keys answer 422, so a typo such as ?langauge= can never write the project-wide mapping.
List
curl --get 'https://api.sandbox.ovok.com/v1/projects/me/email-templates' \
--header "Authorization: Bearer ${OVOK_TOKEN}"
The response includes the project's own mappings and the template names without a project mapping:
| Field | Example | Meaning |
|---|---|---|
projectId | 5b1f0c0e-… | Project whose mappings were read. |
mappings[].name | INVITE_TO_PROJECT | Ovok message name. |
mappings[].provider | brevo | Provider for this mapping. |
mappings[].templateId | 12 | Template id at the provider. |
mappings[].language | en-US | Language context, or null when none was set. |
mappings[].domain | null | Domain context, or null when none was set. |
mappings[].subject | null | SMTP subject; null for other providers. |
mappings[].ready | true | False when a required provider secret or EMAIL_FROM is missing. Presence only is checked, not whether the credential works. |
unmapped[] | RESET_PASSWORD, PATIENT_WELCOME | Names without a mapping in this project, in any language or domain. A parent or platform mapping may still apply, and an unmapped patient variant may use its shared template. |
Inherited mappings are not listed, and SMTP html is omitted from this list response.
Read one
curl --get 'https://api.sandbox.ovok.com/v1/projects/me/email-templates/INVITE_TO_PROJECT' \
--header "Authorization: Bearer ${OVOK_TOKEN}" \
--data-urlencode 'language=en-US'
The answer is the mapping with an html field, which is null unless the provider is SMTP. 404 when the template is not mapped for that language and domain, even if a parent project or the platform maps it.
Create or replace
curl --request PUT \
--url 'https://api.sandbox.ovok.com/v1/projects/me/email-templates/INVITE_TO_PROJECT?language=en-US' \
--header "Authorization: Bearer ${OVOK_TOKEN}" \
--header 'Content-Type: application/json' \
--data '{"provider":"brevo","templateId":"12"}'
| Body field | Required | Description |
|---|---|---|
provider | Yes | brevo, sendgrid, resend or smtp. |
templateId | Yes | Your template's id at the provider, up to 200 characters: digits for Brevo, d- and lower-case hex for SendGrid, no whitespace for Resend and SMTP. |
subject | SMTP only | Up to 998 characters. |
html | SMTP only | Up to 200,000 characters. |
Other fields are refused: language and domain belong in the query. The answer is 200 with the mapping as stored, whether it was created or replaced.
Remove
curl --request DELETE \
--url 'https://api.sandbox.ovok.com/v1/projects/me/email-templates/INVITE_TO_PROJECT?language=en-US' \
--header "Authorization: Bearer ${OVOK_TOKEN}"
The answer is 204 with no body.
What can go wrong
| Status | code or message | Cause |
|---|---|---|
400 | UNKNOWN_TEMPLATE | :name is not a template name. The body lists acceptedNames. |
401 | The token is missing or invalid. | |
403 | The caller is not a practitioner, or for PUT and DELETE not a project admin. | |
404 | <name> is not mapped for language … and domain …. | GET :name or DELETE of a mapping the project does not have. (none) means that part was left out. |
409 | PROVIDER_MISMATCH | That language and domain already use another provider. Remove its mappings first, or map with that provider. |
409 | Resource is locked by another write | Another write to the project's mappings is running. Retry; writes are not queued. |
409 | The mappings changed while the server wrote, or the write waited too long. Read them again and retry. | |
422 | INVALID_TEMPLATE_ID | templateId is not valid for the provider. |
422 | INVALID_TEMPLATE_CONTENT | SMTP without a subject or html, a blank html, subject or html for another provider, or SMTP content that does not render with the message's parameters. |
422 | A list of path and message | A field or query value is missing, invalid, or not recognised. |
500 | The mapping could not be saved in this project. |
Gotchas
- Nothing is sent without a mapping. Map the templates before you turn on the flows that send them. See Invitations.
- A mapping can be shadowed. Ovok tries the most specific context first, and within a level your project, then your parent project, then the platform. A parent's or the platform's mapping at a more specific level wins over your own at a less specific one, so
ready: truedoes not promise yours is the one that goes out. See how Ovok picks a mapping. PROVIDER_MISMATCHis per language and domain. One context uses one provider. To switch, remove that context's mappings first, then map with the new provider.- SMTP content is checked when you store it. Ovok test-renders the subject and HTML with the template's example parameters, so a typo answers
422now instead of failing every send later. - The language has to be one Ovok knows. A value outside its locale list could never match a request, so it is refused rather than stored.
- Removing the last mapping of a context removes its ConceptMap. If an older one exists for the same language and domain, the newest is the one that is read, so removing it can bring the older one back.
- Mappings made by hand can be out of reach. A mapping stored with a language or host in a form these routes refuse can still be listed but not addressed. Remove or recreate it with a language and domain written as above.
- Writes are one at a time. Parallel
PUTs to different templates of one project mostly answer409. Send them in turn. - Credentials are not managed here. The routes store mappings only.
readytells you whether the provider's secrets are in place. - Any practitioner can read, including SMTP HTML. Writing is for admins; reading is not restricted to them.