Upload a template
curl -H "X-Api-Key: $KEY" -F template=@invoice.docx -F name=invoice-2026 \ http://localhost:9027/v1/templatesimport { openAsBlob } from 'node:fs';
const form = new FormData();form.append('template', await openAsBlob('invoice.docx'), 'invoice.docx');form.append('name', 'invoice-2026');
const response = await fetch('http://localhost:9027/v1/templates', { method: 'POST', headers: { 'X-Api-Key': process.env.KEY }, body: form,});if (!response.ok) throw new Error(await response.text());console.log(await response.json());import os
import requests
response = requests.post( "http://localhost:9027/v1/templates", headers={"X-Api-Key": os.environ["KEY"]}, files=[("template", open("invoice.docx", "rb"))], data={"name": "invoice-2026"},)response.raise_for_status()print(response.json())package main
import ( "bytes" "io" "log" "mime/multipart" "net/http" "os" "path/filepath")
func main() { var body bytes.Buffer form := multipart.NewWriter(&body) attach(form, "template", "invoice.docx") form.WriteField("name", "invoice-2026") form.Close()
request, err := http.NewRequest("POST", "http://localhost:9027/v1/templates", &body) if err != nil { log.Fatal(err) } request.Header.Set("X-Api-Key", os.Getenv("KEY")) request.Header.Set("Content-Type", form.FormDataContentType())
response, err := http.DefaultClient.Do(request) if err != nil { log.Fatal(err) } defer response.Body.Close() if response.StatusCode >= 300 { message, _ := io.ReadAll(response.Body) log.Fatalf("%s: %s", response.Status, message) } if _, err := io.Copy(os.Stdout, response.Body); err != nil { log.Fatal(err) }}
// attach adds the file at path to the form as the named field.func attach(form *multipart.Writer, field, path string) { file, err := os.Open(path) if err != nil { log.Fatal(err) } defer file.Close() part, err := form.CreateFormFile(field, filepath.Base(path)) if err != nil { log.Fatal(err) } if _, err := io.Copy(part, file); err != nil { log.Fatal(err) }}Stores a template and returns its id. Syntax is checked now, without data, so a broken template is refused here rather than at its first render. The content never changes: to change a template, store the new one and use its id.
Authorizations
Section titled “Authorizations”Request Bodyrequired
Section titled “Request Bodyrequired”The multipart form POST /v1/templates accepts.
object
A name for it, in place of the file’s. The extension stays the file’s.
The template: DOCX, XLSX, PPTX, ODT, ODS, ODP, PDF or a text format.
Responses
Section titled “Responses”Stored
A stored template.
object
RFC 3339.
Pass as templateId to /v1/render, /v1/render/batch or /v1/templates/validate,
or point an alias at it with PUT /v1/aliases/{name}.
Hex SHA-256 of the content.
Example
{ "format": "docx", "id": "01966f3e-7c1a-7d3c-9a44-1d2f5a6b7c8d", "name": "invoice.docx"}Not a template format
The JSON body of every error response.
object
A stable, machine-readable kind.
What went wrong, for a person.
Example
{ "error": "invalid_request", "message": "unknown step 'teleport'"}This caller’s quota is used up
The JSON body of every error response.
object
A stable, machine-readable kind.
What went wrong, for a person.
Example
{ "error": "invalid_request", "message": "unknown step 'teleport'"}Too large
The JSON body of every error response.
object
A stable, machine-readable kind.
What went wrong, for a person.
Example
{ "error": "invalid_request", "message": "unknown step 'teleport'"}The template has syntax errors
The JSON body of every error response.
object
A stable, machine-readable kind.
What went wrong, for a person.
Example
{ "error": "invalid_request", "message": "unknown step 'teleport'"}RUSTICDOC_STORE is not set
The JSON body of every error response.
object
A stable, machine-readable kind.
What went wrong, for a person.
Example
{ "error": "invalid_request", "message": "unknown step 'teleport'"}The store cannot be reached
The JSON body of every error response.
object
A stable, machine-readable kind.
What went wrong, for a person.
Example
{ "error": "invalid_request", "message": "unknown step 'teleport'"}