JsonFabrica

Templates

Template CRUD and document generation

The 3-shape create+generate response

POST /v1/templates returns different shapes depending on whether the request included a generate field:

  1. generate absent — a plain TemplateDto (unchanged, backward compatible).
  2. generate present and generation succeeds — { template, generation }.
  3. generate present but generation fails at runtime — { template, generationError } — the template is still persisted; only the immediate generation attempt failed.

The most-hit error codes on template creation/generation are NO_PLACEHOLDERS (a template body with only literal text, no function calls), UNKNOWN_FUNCTION (a body references a function outside the v1 catalog), and GENERATION_FAILED (a runtime evaluation error, e.g. a missing required getParam).

MethodPathSummary
GET/v1/templatesList templates
POST/v1/templatesCreate a template (optionally generate immediately — feature 1b)
POST/v1/templates/generateAd-hoc/debug generate — generate directly from a raw body, no persistence (feature 1a)
GET/v1/templates/{templateId}Get a template by id
PUT/v1/templates/{templateId}Update a template
DELETE/v1/templates/{templateId}Delete a template
POST/v1/templates/{templateId}/generateGenerate a document from a template
GET/v1/templates

List templates

ParamInTypeRequiredDescription
namequerystringNo—
statusquery`active` | `archived`No—
tagsquerystringNoComma-separated list of tags
cursorquerystringNo—
limitqueryintegerNo—

Responses

200Page of templates

object

{
  "items": [
    {
      "templateId": "tpl_9f3a1c2e",
      "tenantId": "tenant-acme-01",
      "name": "Order Confirmation",
      "body": "Hello <getParam('name')>, order #<createSeq('orderNo')>",
      "tags": [
        "orders",
        "email"
      ],
      "validated": true,
      "status": "active",
      "createdAt": "2026-07-23T09:00:00.000Z",
      "updatedAt": "2026-07-23T09:00:00.000Z"
    }
  ],
  "nextCursor": "eyJvZmZzZXQiOjIwfQ=="
}
401Missing, malformed, or invalid API key

ErrorEnvelope

{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Missing or invalid API key",
    "details": {}
  }
}
POST/v1/templates

Create a template (optionally generate immediately — feature 1b)

When the request body includes an optional `generate` field, a document is generated from the newly-created template in the same call (see `CreateTemplateResponseDto` for the resulting 3-way response shape). Without `generate`, behavior is unchanged from create-only.

Request body — CreateTemplateRequestDto

Create only (unchanged, backward compatible)

{
  "name": "Order Confirmation",
  "description": "Sends a friendly order confirmation with a generated order number",
  "body": "Hello <getParam('name')>, order #<createSeq('orderNo')>",
  "tags": [
    "orders",
    "email"
  ]
}

One-shot create + generate (feature 1b)

{
  "name": "Invoice",
  "body": "{ \"id\": \"<getRandomNumber(1,1000)>\" }",
  "generate": {
    "seed": 42
  }
}

Responses

201Template created. Response is a plain `TemplateDto` when `generate` was omitted, or `{ template, generation }` / `{ template, generationError }` when `generate` was present (see `CreateTemplateResponseDto`).

CreateTemplateResponseDto

generate omitted

{
  "templateId": "tpl_9f3a1c2e",
  "tenantId": "tenant-acme-01",
  "name": "Order Confirmation",
  "description": "Sends a friendly order confirmation with a generated order number",
  "body": "Hello <getParam('name')>, order #<createSeq('orderNo')>",
  "tags": [
    "orders",
    "email"
  ],
  "validated": true,
  "status": "active",
  "createdAt": "2026-07-23T09:00:00.000Z",
  "updatedAt": "2026-07-23T09:00:00.000Z"
}

generate present, succeeded

{
  "template": {
    "templateId": "tpl_1a2b3c4d",
    "tenantId": "tenant-acme-01",
    "name": "Invoice",
    "body": "{ \"id\": \"<getRandomNumber(1,1000)>\" }",
    "tags": [],
    "validated": true,
    "status": "active",
    "createdAt": "2026-07-25T10:00:00.000Z",
    "updatedAt": "2026-07-25T10:00:00.000Z"
  },
  "generation": {
    "data": {
      "id": "731"
    },
    "meta": {
      "seed": 42,
      "templateId": "tpl_1a2b3c4d",
      "generatedAt": "2026-07-25T10:00:00.000Z"
    }
  }
}

generate present, template persisted but generation failed at runtime

{
  "template": {
    "templateId": "tpl_5e6f7a8b",
    "tenantId": "tenant-acme-01",
    "name": "NeedsParam",
    "body": "{ \"v\": \"<getParam('sku')>\" }",
    "tags": [],
    "validated": true,
    "status": "active",
    "createdAt": "2026-07-25T10:00:00.000Z",
    "updatedAt": "2026-07-25T10:00:00.000Z"
  },
  "generationError": {
    "code": "GENERATION_FAILED",
    "message": "getParam: parameter 'sku' was not provided and has no default"
  }
}
400`VALIDATION_ERROR` (missing `name`/`body`), `INVALID_TEMPLATE` (structural problems incl. unbalanced for/if blocks or a template with zero placeholders — code `NO_PLACEHOLDERS` in `details`), or `UNKNOWN_FUNCTION` (body references a function outside the v1 catalog). Template is never saved in any of these cases, even if `generate` was present.

ErrorEnvelope

Missing required field

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "\"name\" is required",
    "details": {
      "field": "name"
    }
  }
}

Template has no placeholders

{
  "error": {
    "code": "INVALID_TEMPLATE",
    "message": "Template body must contain at least one placeholder (e.g. <getName()>) — a template with only literal text cannot generate varying data",
    "details": {
      "reason": "Template body must contain at least one placeholder (e.g. <getName()>) — a template with only literal text cannot generate varying data",
      "code": "NO_PLACEHOLDERS"
    }
  }
}

Body references an unknown function

{
  "error": {
    "code": "UNKNOWN_FUNCTION",
    "message": "Unknown function 'notAFunction'",
    "details": {
      "name": "notAFunction"
    }
  }
}
401Missing, malformed, or invalid API key

ErrorEnvelope

{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Missing or invalid API key",
    "details": {}
  }
}
POST/v1/templates/generate

Ad-hoc/debug generate — generate directly from a raw body, no persistence (feature 1a)

Generates a document from a raw template body without creating a template record. Useful for quickly iterating on template syntax. Goes through the same billing/usage metering as persisted-template generation (keyed on tenantId, not templateId) — not a free bypass of usage billing. `createSeq`/durable sequence side effects still apply; callers should set `sequenceNamespace`/`variableNamespace` (e.g. `"debug"`) to avoid colliding with real tenant sequences.

Request body — AdhocGenerateRequestDto

{
  "body": "{ \"name\": \"<getRandomFullName()>\" }",
  "seed": 42,
  "sequenceNamespace": "debug",
  "variableNamespace": "debug"
}

Responses

200Generated document

AdhocGenerateResponseDto

{
  "data": {
    "name": "Jane Doe"
  },
  "meta": {
    "seed": 42,
    "generatedAt": "2026-07-25T10:00:00.000Z"
  }
}
400`INVALID_TEMPLATE`/`UNKNOWN_FUNCTION` (malformed body, same static validation as template create) or `GENERATION_FAILED` (runtime evaluation error) — same error taxonomy as `POST /v1/templates/{templateId}/generate`.

ErrorEnvelope

Runtime evaluation error

{
  "error": {
    "code": "GENERATION_FAILED",
    "message": "getParam: parameter 'who' was not provided and has no default",
    "details": {
      "reason": "getParam: parameter 'who' was not provided and has no default"
    }
  }
}

Static validation — template has no placeholders

{
  "error": {
    "code": "INVALID_TEMPLATE",
    "message": "Template body must contain at least one placeholder (e.g. <getName()>) — a template with only literal text cannot generate varying data",
    "details": {
      "reason": "Template body must contain at least one placeholder (e.g. <getName()>) — a template with only literal text cannot generate varying data",
      "code": "NO_PLACEHOLDERS"
    }
  }
}

Static validation — unknown function reference

{
  "error": {
    "code": "UNKNOWN_FUNCTION",
    "message": "Unknown function 'notAFunction'",
    "details": {
      "name": "notAFunction"
    }
  }
}
401Missing, malformed, or invalid API key

ErrorEnvelope

{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Missing or invalid API key",
    "details": {}
  }
}
GET/v1/templates/{templateId}

Get a template by id

ParamInTypeRequiredDescription
templateIdpathstringYes—

Responses

200Template

TemplateDto

401Missing, malformed, or invalid API key

ErrorEnvelope

{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Missing or invalid API key",
    "details": {}
  }
}
404Resource does not exist

ErrorEnvelope

{
  "error": {
    "code": "NOT_FOUND",
    "message": "Template tpl_missing not found",
    "details": {}
  }
}
PUT/v1/templates/{templateId}

Update a template

ParamInTypeRequiredDescription
templateIdpathstringYes—

Request body — object

{
  "body": "Hello <getParam('name')>, your order #<createSeq('orderNo')> is confirmed!"
}

Responses

200Updated template

TemplateDto

400Validation or template/generation error

ErrorEnvelope

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "\"name\" is required",
    "details": {
      "field": "name"
    }
  }
}
401Missing, malformed, or invalid API key

ErrorEnvelope

{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Missing or invalid API key",
    "details": {}
  }
}
404Resource does not exist

ErrorEnvelope

{
  "error": {
    "code": "NOT_FOUND",
    "message": "Template tpl_missing not found",
    "details": {}
  }
}
DELETE/v1/templates/{templateId}

Delete a template

ParamInTypeRequiredDescription
templateIdpathstringYes—

Responses

200The removed template record

TemplateDto

401Missing, malformed, or invalid API key

ErrorEnvelope

{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Missing or invalid API key",
    "details": {}
  }
}
404Resource does not exist

ErrorEnvelope

{
  "error": {
    "code": "NOT_FOUND",
    "message": "Template tpl_missing not found",
    "details": {}
  }
}
POST/v1/templates/{templateId}/generate

Generate a document from a template

ParamInTypeRequiredDescription
templateIdpathstringYes—

Request body — GenerateRequestDto

{
  "seed": 123456789,
  "params": {
    "name": "Jane Doe"
  },
  "sequenceNamespace": "default",
  "variableNamespace": "default"
}

Responses

200Generated document

GenerateResponseDto

{
  "data": "Hello Jane Doe, order #1001",
  "meta": {
    "seed": 123456789,
    "templateId": "tpl_9f3a1c2e",
    "generatedAt": "2026-07-23T09:05:00.000Z"
  }
}
400Validation or template/generation error

ErrorEnvelope

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "\"name\" is required",
    "details": {
      "field": "name"
    }
  }
}
401Missing, malformed, or invalid API key

ErrorEnvelope

{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Missing or invalid API key",
    "details": {}
  }
}
404Resource does not exist

ErrorEnvelope

{
  "error": {
    "code": "NOT_FOUND",
    "message": "Template tpl_missing not found",
    "details": {}
  }
}
422Generation error (e.g. resource limits exceeded). `code` is one of `LOOP_LIMIT_EXCEEDED` (default 10,000 iterations), `NODE_LIMIT_EXCEEDED` (default 100,000 node evaluations), `EVALUATION_TIMEOUT` (default 2,000 ms), `OUTPUT_LIMIT_EXCEEDED` (cumulative rendered-output byte cap, default 8 MiB) or `GENERATION_ERROR`. `details` carries the `limit` that was exceeded plus a `kind` discriminator (`loopIterations` | `nodeEvaluations` | `timeout` | `outputBytes`).

ErrorEnvelope

{
  "error": {
    "code": "OUTPUT_LIMIT_EXCEEDED",
    "message": "Template produced more than the maximum of 8388608 bytes of output",
    "details": {
      "limit": 8388608,
      "kind": "outputBytes",
      "producedBytes": 8388621
    }
  }
}