Reusable document and recurrence templates
Create a reusable template
/a/Template_new
Save a new reusable preset without creating a business document
When to use this endpoint
Use after assembling editor values that another document or recurrence can reuse. The caller owns the payload schema and must omit object-specific IDs or dates it does not want reused. The server stores the supplied payload; it does not clone the source document.
Authentication and permissions
Authenticate with signed API-key fields or a logged-in CRM session. Template_get, Template_new, Template_setObj and Templates_get require an authenticated tenant context; Template_delete and both table handlers also call the login guard. There is no handler-level administrator, page, role, creator or ownership check.
Templates are shared within the authenticated tenant, not private to created_by. There is no user, department, feature-setting or active/deleted filter. The dispatcher also applies its normal account, authentication and team-access checks; the shared table predicate adds no template-specific row restriction.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
name | String | Yes | Trimmed, nonblank name, at most 100 Unicode characters. Duplicate names are allowed; no uniqueness lookup is performed. |
type | Integer | Yes | Integer-converted positive object type; omitted/blank/null/zero fail. Not an allowlisted enum on the server. |
obj | JSON text | Yes | Nonblank string, trimmed before storage. JSON-encode the editor’s object before signing. JSON syntax is validated before storage, but its schema is not. A native PHP array is rejected; encoded JSON scalars also pass syntax validation. |
Example request
$created = FM_api('Template_new', [
'name' => 'Standard quote',
'type' => '3',
'obj' => json_encode(['notes' => 'Reusable quote notes']),
]);
Example response
{"ok":1,"id":1042}
Success requires a positive insert-helper ID. A failed or throwing insert returns an error without ok/id. An interrupted transport can still leave the caller unsure whether a successful insert committed.
Errors and unusual responses
| Response | Condition |
|---|---|
{"error":"not logged in"} | No authenticated tenant context is available. Invalid signed credentials can be rejected by the dispatcher before the handler runs. |
{"error":"missing or invalid parameter: name"} | Missing/null/blank name after trimming. |
{"error":"parameter too long: name. max length 100 characters"} | Trimmed name exceeds 100 characters. |
{"error":"Unable to create template"} | The insert fails, throws, or returns no positive ID. |
{"error":"missing or invalid parameter: type"} | Integer-converted type is below 1. |
{"error":"missing or invalid parameter: obj"} | Missing, non-string, blank or malformed JSON payload. |
Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.
Behaviour and edge cases
- The CRM2 enum defines 1=recurrence, 2=job, 3=quote, 4=invoice and 5=opportunity. The PHP handlers accept any positive integer, not just that enum. These are saved input presets, not email templates or PDF/Word document designs.
- The payload is stored whole; no field defaults, referenced-record checks, duplicate detection or idempotency key is applied. Retrying creates another row. Creation does not select a default preset or update a source document.
- No direct mobile-app or m-service caller for this template family was found in the source search. The CRM2 widget’s payload is client-defined; storing it does not validate that another document endpoint will accept every field.
Side effects
- Inserts the tenant template with current Unix-second cdate/last_edited and the authenticated user as created_by. No explicit Core_log, deletion audit, event, email, queue or cache-invalidation option is invoked by this handler.
See it in Fieldmotion
CRM1
In CRM1, open a job’s recurrence editor and use Save as Template; filter browser requests for Template_new or Template_setObj. The editor lists type 1 templates through Templates_get and removes job-specific values before saving. CRM2’s recurrence editor uses the same type-1 workflow.
CRM2
CRM2’s widgetTemplate.js loads Templates_get with JSON-encoded id/name/obj fields, parses obj locally, and uses Template_new, Template_setObj and Template_delete from its save/trash controls. Observe these requests in a create dialog whose configured layout includes the Template widget, such as a quote or invoice. The widget is layout-dependent, not present on every screen.
Related endpoints
- Templates_get supplies the selectable presets for one type.
- Template_get reads one stored preset without applying it.
- Template_new creates a separate preset; Template_setObj replaces an existing preset’s payload.
- Template_delete removes the reusable preset, not documents previously created from it.