Appearance
Blueprints
A blueprint is one JSON file that describes how an organization is set up: its custom fields, seed records, forms, webhooks, dashboard, branding and bid statuses.
Without one, setting up a new organization means clicking through Settings screen by screen, and there's no way to copy a working setup to the next customer. A blueprint makes that setup declarative, portable, and repeatable: you can preview what it would change, apply it, and export a live organization back out as one.
There is no blueprint screen in the app
Blueprints are an API capability, used by scripts, by us during onboarding, and by the AI assistant. Everything a blueprint configures is also editable in the app afterwards. The blueprint just gets you there in one step.
The four rules
Everything about how blueprints behave follows from these:
Merge-patch. Only what you name is touched. A blueprint containing one custom field changes that field and nothing else. It is not a full description of the org, so leaving something out never removes it.
Natural keys, never ids. A field is matched by its key, a webhook by its url, a form or customer by name. That's what makes a blueprint portable between organizations, where internal ids would mean nothing.
Removal is explicit. Nothing is deleted unless an item says archived: true. There is no "sync" that prunes whatever isn't listed.
Idempotent. Applying the same blueprint twice is safe. The second run reports everything as noop. This is what makes re-applying an updated blueprint a normal operation rather than a risk.
What a blueprint can contain
| Section | Declares |
|---|---|
custom_fields | Field definitions on any record type |
entities | Seed records: customers, properties, projects, employees, subcontractors, trades, compliance docs, rates |
forms | Full form definitions, draft or published |
webhooks | Organization-level event webhooks |
form_webhooks | Per-form webhooks |
dashboards.org | The organization's home dashboard |
branding | App name, logo text, colours, fonts |
bid_statuses | The subcontractor bid pipeline |
Plus blueprint_version (always 1) and optional name / description labels.
Unknown keys are rejected rather than ignored, so a typo fails loudly instead of silently doing nothing.
What it deliberately doesn't cover
Work-order types, the status registry, document templates, estimate templates, saved views, detail layouts, users, roles and API keys are not in a blueprint. They're configured in the app. Nor can you seed work orders, estimates, invoices, leads or contracts; you can define custom fields on those, but not create records.
Applying one
Always two steps.
1. Plan: a dry run. Returns an operation per item (create, update, noop, archive, error) plus a summary and a plan_hash. Nothing changes.
2. Apply: pass the blueprint, optionally with the plan_hash you were given.
POST /v1/blueprint/plan scope: blueprint:read
POST /v1/blueprint/apply scope: blueprint:applyBoth scopes must be granted explicitly on an API key. See Developer settings.
Two ways apply refuses to run:
- Any validation error stops everything (422). Nothing is written, so a blueprint with one bad field doesn't half-configure your org.
- A stale
plan_hash(409) means the org changed between plan and apply. It is optional. Omit it and you get no such protection.
Apply is not a transaction
There's no rollback. If something fails mid-run, items already applied stay applied, the failure is reported, and anything depending on it is skipped. Fix the blueprint and apply again. That's what idempotency is for.
Archiving is not uniform
Worth knowing before you write archived: true:
- Custom fields and seed records are soft-archived, so they're recoverable.
- Webhooks and form webhooks are permanently deleted.
Exporting an organization
GET /v1/blueprint/export snapshots a live org into a blueprint you can apply elsewhere. Refs are reversed back to names, and internal ids, timestamps and computed values are stripped so the result is portable.
An export contains real customer data
The entities section includes every live customer, employee and subcontractor: names, emails, phone numbers, addresses. An export is a configuration and CRM dump, not just settings. Treat it like a database export: don't paste one into a ticket, a chat, or an AI tool you wouldn't hand the customer list to.
Secrets are never exported. Webhook signing secrets aren't even read from the database during export, and a newly created webhook's secret appears once in the apply result and nowhere else.
Canon fields
Some field definitions are marked canon, meaning they're authored and maintained by Blok rather than by your organization. The estimating cost model is the main example: roughly thirty fields on estimates and estimate lines that the billing and document code reads by name.
What that means in practice:
| You can | You can't |
|---|---|
| Stop using a canon field (archive it) | Rename it, retype it, or change its options |
| Choose whether it prints on customer-facing documents | Delete it |
| Add your own fields alongside | Convert one of your fields into a canon field |
This is enforced in the database, not just the interface.
Archiving a canon field sticks. Re-applying the blueprint won't quietly bring it back. And your "show on documents" choice is never overwritten by a re-apply, so tuning that in the app is safe.
The trade-off: canon field ids are a contract the estimating engine depends on. Opting out of one means owning that part of the workflow yourself. It works, you're just off the paved road.
Starter templates
Five are shipped, available from GET /v1/blueprint/templates and browsable at blokblueprints.my-tlt-app.com:
- Blok canon: Estimating. The canon estimating field set: header defaults, line classification, cost buildup, and formula display columns. Also the only template that seeds the bid-status pipeline.
- Coatings subcontractor: the richest starter, modelled on a real operator: lead pipeline, coatings-specific job fields, a formula-driven sell price, a T&M rate card, four published field forms, and a dashboard.
- Solo contractor: a lean setup: a few fields, two rates, a daily job log.
- Crew: crew roles and certifications, daily log, timesheet and safety forms.
- Multi-crew GC: project phases, subcontractor ratings and licences, a trades list, sub sign-in and safety audit forms.
Gotchas
A key can't be reused after archiving. Re-declaring an archived field's key is a hard error. Restore the old one or pick a new key.
Duplicate natural keys are fatal. Two customers with the same name make that name ambiguous, and blueprint updates for it fail until you resolve it. Same for two items sharing a key inside one blueprint.
A required custom field can block seed records. Declaring a field required and then seeding a record without a value fails that record, even if the record doesn't mention custom fields at all. The plan surfaces this before you apply.
bid_statuses replaces the whole list, rather than merging. Omitting a status removes it. (The four system statuses re-appear automatically.)
branding merges deeply. You can set a colour but not unset one.
Section order is fixed, not document order. You can reference a customer or form created in the same blueprint, but only those four types can be referenced by name at all: customers, trades, subcontractors and forms.
Updating a published form bumps its version. Past submissions keep the version they were captured under.