Organizations
The account-side registry of your circle — the companies, non-profits, agencies and schools your contacts work for or that you do business with. It is the institutional counterpart to data/contacts (same shape, minus consent), and the anchor lookups like find_by_domain resolve against when an inbound email or lead needs to be matched to a known account.
Working with it
Selecting a Organizations reveals its settings in the properties panel; it has no dedicated full-screen workbench.
How it appears
The same element type rendered as a definition, a circle instance, and a live workspace card.
When to use / not
When to use
- Account-based prospecting: you know a company exists and want to track it before you've found anyone there — an organization can stand alone with no linked contacts yet.
- Deduping and correlating inbound signals against a known account — match a sender's web domain, national org number, reception-desk email, phone or social back to the right organization.
- Holding the roster of who works where: each contact links to at most one organization, and list_contacts gives you everyone at a given account.
- Bulk-migrating an existing account book in or out via CSV import/export.
When not to use
- Storing people and their personal contact channels — that belongs in data/contacts, where the consent fields live; organizations is impersonal account info only.
- Modelling multi-employer history or many orgs per person — a contact links to a single current organization; richer affiliation graphs aren't in scope (reach for graph).
- Persisting arbitrary structured records that aren't institutional accounts — use entity for general typed rows.
Topology
Created from the library and placed inside an app or circle. It is a top-level building block you compose with other elements.
Properties
No configurable properties.
Operations
- activityGET
- add_addressPOST
- add_emailPOST
- add_phonePOST
- add_socialPOST
- attachmentsGET
- batch_statsGET
- composePOST
- contextGET
- createPOST
- deletePOST
- disablePOST
- enablePOST
- export_bundleGET
- export_csvPOST
- find_by_domainPOST
- find_by_emailPOST
- find_by_org_noPOST
- find_by_phonePOST
- find_by_socialPOST
- getPOST
- import_bundlePOST
- import_csvPOST
- intentionGET
- listPOST
- list_contactsPOST
- promotePOST
- readmeGET
- readme_updatePOST
- remove-modifierPOST
- remove_addressPOST
- remove_emailPOST
- remove_phonePOST
- remove_socialPOST
- restorePOST
- schemaGET
- searchPOST
- sourceGET
- source_branchesGET
- source_fixturesPOST
- source_promotePOST
- source_repairPOST
- source_statusGET
- source_validatePOST
- statsPOST
- tagPOST
- treeGET
- untagPOST
- updatePATCH
- update_addressPOST
- update_metaPATCH
- upsertPOST
- versionGET
Composition
Organizations (organizations)
Category: data | Form: | Symbol: Or
Companies, non-profits, agencies, schools — the orgs your contacts belong to
Per-circle registry of organizations. An organization is any corporate or institutional entity that Contacts belong to or that your circle does business with — companies, non-profits, government agencies, schools, clubs. Contacts link to at most one Organization at a time (current employer / affiliation); multi-employer history is a future concern. Core fields: name, legal_name, org_no (e.g. Swedish organisationsnummer or US EIN), domain, industry, size, website, description, logo, tags, custom, notes, owner. Four child groupings (same no-umbrella shape as data/contacts, minus consent — reception-desk contact info is impersonal):
• emails — info@, support@, sales@ style addresses • phones — main switchboard, fax, regional offices • socials — company LinkedIn / X / GitHub / YouTube accounts • addresses — registered (legal), billing, visiting (HQ), shipping, postal
An Organization can exist WITHOUT any known Contacts — useful for account-based prospecting (“we know Acme Corp exists, haven’t found anyone there yet”). Contacts and Organizations are both promoted from data/leads once research turns into a real relationship. Lookups: find_by_domain (‘acme.se’) and find_by_org_no (‘559012-3456’) are the dedup helpers. CSV import/export for bulk loads.
Guide
Per-circle registry of the companies, non-profits, agencies and schools your contacts belong to
What It Does
Organizations is a data element that stores a per-circle registry of corporate and institutional entities — companies, non-profits, government agencies, schools, clubs — that your Contacts belong to or that your circle does business with. It is the account-side counterpart to data/contacts: the same no-umbrella shape, minus consent (reception-desk contact info is impersonal). Each organization carries core fields (name, legal_name, org_no, domain, industry, size, website, description, logo_url, tags, custom, notes, owner) plus four child groupings — emails, phones, socials and addresses.
Storage is per-circle Postgres, auto-bootstrapped on first upsert. The organization row lives alongside its child rows in organization_emails, organization_phones, organization_socials and organization_addresses under circle_{uuid}. The element spec itself carries no per-row data — it is the namespace/identity anchor for the registry, not a storage field, so there are no configurable properties to set.
An Organization can exist without any known Contacts (useful for account-based prospecting), and Contacts link to at most one Organization at a time via an organization_id foreign key. Other elements do not wire to Organizations through flow ports — it is a data-atom with no flow ports, no child bonds and no attached modifiers; data/contacts simply references it by organization_id. Lookups (find_by_domain, find_by_org_no, find_by_email, find_by_phone, find_by_social) act as dedup and inbound-correlation helpers, and CSV import/export covers bulk account-book migrations.
Element Definition
| Field | Value |
|---|---|
| Type | organizations |
| Category | data |
| Form | atom |
| Symbol | Or |
| Icon | domain / #0EA5E9 |
| Storage backend | postgres |
| Has data | true |
| LLM role | data (priority 7) |
| Wirable | false |
Properties
The element spec carries no configurable fields (properties.fields: {}, required: []). The spec is the identity anchor for the per-circle organization registry; all organization data lives in per-circle Postgres tables, not in the spec.
Capabilities
| Capability | Description |
|---|---|
org-registry | Per-circle registry of companies, non-profits, agencies, schools and any other institutional entities contacts belong to or the circle does business with |
dedup-by-domain | find_by_domain normalises the domain (strips protocol/www/trailing slash) and matches; used for dedup during lead promotion and inbound-email correlation |
dedup-by-org-no | find_by_org_no exact-string match on national registry numbers (Swedish organisationsnummer, US EIN, UK CRN, etc.) for strong-identity deduplication |
contact-roster | list_contacts returns all Contacts linked to an organization (people who work there) |
bulk-import-export | CSV import (with header-row column detection) and flat CSV export for bulk account-book migrations |
Error Codes
| Code | Class | Retryable | Description |
|---|---|---|---|
ORG_NOT_FOUND | not_found | No | No organization matching the provided id, domain, org_no, or email |
ORG_DUPLICATE_DOMAIN | conflict | No | Upsert would create a duplicate — same domain already belongs to a different organization id |
ORG_DUPLICATE_ORG_NO | conflict | No | Upsert would create a duplicate — same org_no already belongs to a different organization id |
ORGANIZATIONS_CSV_PARSE_ERROR | validation | No | CSV input could not be parsed — check header row and encoding |
Operations
All operations are POST to /api/{circle}/{slug}/ops/{path}. auth: read ops are read-only queries; auth: write ops mutate.
Core
upsert — POST ops/upsert (write)
Create or update an organization — merges child groupings by natural key. Idempotent on id (when provided), or on a deterministic match against domain or org_no. The emails, phones, socials and addresses arrays upsert their rows (matched by natural key); rows not named in the arrays are preserved. Tags union with existing tags; custom JSON merges shallowly at top level. Required input: name.
get — POST ops/get (read)
Fetch an organization with all child groupings. Required input: id.
list — POST ops/list (read)
Page through organizations (newest first by default). Optional limit (default 100), offset (default 0), tag (filter to a specific tag), industry (match the industry field). Returns organizations and total.
search — POST ops/search (read)
Free-text search across name, legal_name, domain, description, notes. Required input: query; optional limit (default 50). Returns organizations.
find_by_domain — POST ops/find_by_domain (read)
Lookup an organization by web domain — dedup + inbound correlation. Normalises the domain (strips protocol, www prefix, trailing slash) before matching. Required input: domain.
find_by_org_no — POST ops/find_by_org_no (read)
Lookup an organization by national registry number. Exact-string match; callers normalise format (e.g. Swedish 5590123456 vs 559012-3456) before lookup. Required input: org_no.
list_contacts — POST ops/list_contacts (read)
List the Contacts linked to this organization (people who work there). Required input: id; optional limit (default 100). Returns contacts.
delete — POST ops/delete (write)
Delete an organization and all its child rows (hard delete). Any Contacts that were linked have their organization_id cleared — the contacts themselves are not deleted. Required input: id.
tag — POST ops/tag (write)
Add a tag to an organization. Required input: id, tag.
untag — POST ops/untag (write)
Remove a tag from an organization. Required input: id, tag.
stats — POST ops/stats (read)
Aggregate counts. Returns total_organizations, total_with_contacts, total_without_contacts, by_industry, by_size. No required input.
import_csv — POST ops/import_csv (write)
Bulk import organizations from a CSV string (header row required). Recognised columns: name, legal_name, org_no, domain, industry, size, website, description, email, phone, tags (semicolon-separated), notes. Required input: csv. Returns created, updated, skipped.
export_csv — POST ops/export_csv (read)
Export organizations as CSV — flat denormalised shape, one row per organization, with multi-value child groupings semicolon-joined. Optional limit (default 10000; max 100000 per the op hint). Returns csv and rows.
Emails
Reception-desk addresses (info@, support@, sales@) — institutional, no consent fields.
add_email — POST ops/add_email (write)
Attach a reception-desk email to an organization. Idempotent on (organization_id, address). Required input: organization_id, address; optional label (info | support | sales | billing | careers | press | other), primary.
remove_email — POST ops/remove_email (write)
Detach an email from an organization. Required input: organization_id, address.
find_by_email — POST ops/find_by_email (read)
Lookup an organization by one of its reception-desk emails. Required input: address. Returns organization and email.
Phones
add_phone — POST ops/add_phone (write)
Attach a phone number to an organization (main line, fax, regional office). Numbers normalised to E.164 on insert; idempotent on (organization_id, normalised_number). Required input: organization_id, number; optional label (main | fax | support | sales | regional | other), primary.
remove_phone — POST ops/remove_phone (write)
Detach a phone from an organization. Required input: organization_id, number.
find_by_phone — POST ops/find_by_phone (read)
Lookup an organization by phone number (inbound-call correlation). Required input: number. Returns organization and phone.
Socials
Company-level profiles (LinkedIn company page, X account, GitHub org).
add_social — POST ops/add_social (write)
Attach a social profile to an organization. Idempotent on (organization_id, platform, handle_or_url). Platform is an open string (recommended: linkedin, x, github, instagram, facebook, youtube, tiktok, mastodon, threads, bluesky). Required input: organization_id, platform, handle_or_url; optional label.
remove_social — POST ops/remove_social (write)
Detach a social profile from an organization. Required input: organization_id, platform, handle_or_url.
find_by_social — POST ops/find_by_social (read)
Lookup an organization by social profile (platform + handle/URL). Required input: platform, handle_or_url. Returns organization and social.
Addresses
One organization can have many addresses (HQ + regional offices + billing + warehouse), keyed by a generated address_id.
add_address — POST ops/add_address (write)
Attach a physical address to an organization. Every add creates a new row (keyed by a generated address_id); use update_address to modify an existing one. Required input: organization_id; optional kind (registered | billing | visiting | shipping | postal), street1, street2, city, region, postal_code, country (ISO-3166 alpha-2), label.
update_address — POST ops/update_address (write)
Update one address on an organization by address_id. Required input: organization_id, address_id; optional kind, street1, street2, city, region, postal_code, country, label.
remove_address — POST ops/remove_address (write)
Detach an address from an organization by address_id. Required input: organization_id, address_id.
Quick Start
Create the element
POST /api/{circle}/{project}/
Content-Type: application/json
{
"element_type": "organizations",
"slug": "accounts",
"name": "Accounts"
}
Upsert an organization
POST /api/{circle}/accounts/ops/upsert
Content-Type: application/json
{
"name": "Acme AB",
"legal_name": "Acme Aktiebolag",
"org_no": "559012-3456",
"domain": "acme.se",
"industry": "SaaS",
"size": "51-200",
"emails": [{ "address": "info@acme.se", "label": "info", "primary": true }],
"addresses": [{ "kind": "visiting", "street1": "Storgatan 1", "city": "Stockholm", "country": "SE" }],
"tags": ["prospect"]
}
Dedup before creating, then read back
POST /api/{circle}/accounts/ops/find_by_domain
Content-Type: application/json
{ "domain": "acme.se" }
POST /api/{circle}/accounts/ops/list
Content-Type: application/json
{ "limit": 50, "industry": "SaaS" }
Common Mistakes
Assuming a Contact can belong to several organizations.
A Contact links to at most one Organization at a time (current employer / affiliation), via the organization_id foreign key on data/contacts. Multi-employer history is out of scope.
Relying on upsert to dedup an unnormalised org number.
find_by_org_no (and the org_no match in upsert) does exact-string match. Swedish 5590123456 and 559012-3456 are different strings — normalise the format before lookup or upsert, or you risk ORG_DUPLICATE_ORG_NO / a duplicate row.
Expecting consent fields on emails, phones or socials. There are none — organization contact channels are impersonal (reception-desk). Consent lives on individual Contacts, not here.
Using add_address to edit an existing address.
Every add_address creates a new row keyed by a fresh address_id. To change an existing address, call update_address with its address_id.
Capabilities
- org-registry: Per-circle registry of companies, non-profits, agencies, schools and any other institutional entities contacts belong to or the circle does business with
- dedup-by-domain: find_by_domain normalises the domain (strips protocol/www/trailing slash) and matches; used for dedup during lead promotion and inbound-email correlation
- dedup-by-org-no: find_by_org_no exact-string match on national registry numbers (Swedish organisationsnummer, US EIN, UK CRN, etc.) for strong-identity deduplication
- contact-roster: list_contacts returns all Contacts linked to an organization (people who work there)
- bulk-import-export: CSV import (with header-row column detection) and flat CSV export for bulk account-book migrations
Operations
activity
Get /ops/activity | Auth: Read
Get activity events for this element
Scope depends on element capabilities: individual elements query by element_id, project-form elements with activity-scope-members include member activities, circle-level elements with activity-scope-all query the entire circle. Gracefully returns empty list if activities table is missing (old circles).
add_address
Post /ops/add_address | Auth: Write
Attach a physical address to an organization
Every add creates a new row (keyed by a generated address_id). Use
update_addressto modify an existing one.registeredis the legal registered address (what the org_no resolves to);visitingis the HQ street address people actually visit;billingandshippingare business addresses;postalis the PO-box address if different.
add_email
Post /ops/add_email | Auth: Write
Attach a reception-desk email to an organization
Idempotent on (organization_id, address). Re-adding an existing address merges the provided fields (label, primary). No consent fields — these are impersonal addresses.
add_phone
Post /ops/add_phone | Auth: Write
Attach a phone number to an organization (main line, fax, regional office)
Numbers normalised to E.164 on insert. Idempotent on (organization_id, normalised_number). No consent fields.
add_social
Post /ops/add_social | Auth: Write
Attach a social profile to an organization (company LinkedIn, X, GitHub org, YouTube)
Idempotent on (organization_id, platform, handle_or_url). Platform is an open string — recommended set is linkedin, x, github, instagram, facebook, youtube, tiktok, mastodon, threads, bluesky. Socials are pointers; no consent fields.
attachments
Get /ops/attachments | Auth: Read
List all modifiers and resources attached to this element
Returns both modifiers (policy enforcement) and resources (data injection) with is_modifier flag to distinguish. Items in the generated MODIFIER_TYPES list are modifiers; everything else is a resource. Includes cascade_policy and version pin info.
batch_stats
Get /ops/batch_stats | Auth: Read
Get per-element statistics for all children of this element
Returns per-child stats plus an aggregate. Most meaningful on compound or manifest form elements (repositories, circles, projects); atoms have no children so the result is an empty children array with a zeroed aggregate. Uses efficient GROUP BY SQL. Weighted averages for eval scores.
compose
Post /ops/compose | Auth: Execute
Batch add and remove modifiers on this element in a single call
Declarative composition: add modifiers by ref path (slug or path@version) and remove by attachment ID, all in one atomic call on the target element. Each ‘add’ entry resolves the source element, validates topology, attaches with optional priority and cascade policy. Each ‘remove’ entry deletes the attachment row. Returns a summary of what was added and removed. Example: compose({ add: [{ref: “my-prompt”}, {ref: “rate-limit/api@v2”, priority: 50}], remove: [{attachment_id: “uuid”}] })
context
Get /ops/context | Auth: Read
Get connected elements (graph traversal)
Graph traversal showing all connected elements with their relationship type (contains, contained_by, references, referenced_by, attaches, etc.). Use ?depth=N to control traversal depth (default 1) and ?types=actor,data to filter by element types.
create
Post /ops/create | Auth: Write
Create child element
POST to the parent path — element_type goes in the request body, NOT the URL. Both element_type and slug are required and must be non-empty. Name is derived from slug if omitted. Writes to both Git and PostgreSQL. All elements are stored flat under the circle — no intermediate library wrapper rows.
delete
Post /ops/delete | Auth: Write
Delete an organization and all its child rows
Hard delete. Any Contacts that were linked to this organization have their organization_id cleared (contacts themselves are NOT deleted — they remain in the address book as unaffiliated).
disable
Post /ops/disable | Auth: Admin
Disable element (hides and prevents use)
Idempotent — safe to call on already-disabled elements. Optionally pass a reason string. Disabled elements cannot be invoked or executed. Inverse of enable.
enable
Post /ops/enable | Auth: Admin
Enable element (makes usable and visible)
Idempotent — safe to call on already-enabled elements. Transitions element to ready/enabled state. Cannot enable deleted elements. Inverse of disable.
export_bundle
Get /ops/export/bundle | Auth: Read
Export element as downloadable git bundle
On non-root-namespace elements, returns a binary git bundle. On root-namespace (circle) elements, dispatch hands off to the circle’s own export_bundle op, which returns a multi-element JSON envelope with one base64 bundle per child element — this is intentional, not an error.
export_csv
Post /ops/export_csv | Auth: Read
Export organizations as CSV
Flat denormalised shape — one row per organization. Multi-value child groupings are joined: emails semicolon-separated, phones semicolon-separated, etc. Default limit 10 000, max 100 000.
find_by_domain
Post /ops/find_by_domain | Auth: Read
Lookup an organization by web domain — dedup + inbound correlation
Normalises the domain (strips protocol, www prefix, trailing slash) before matching. Used by (a) the data/leads promote op to avoid creating duplicate organizations, (b) inbound email handlers to correlate a sender’s domain to a known organization, (c) UI dedup suggestions during manual entry.
find_by_email
Post /ops/find_by_email | Auth: Read
Lookup an organization by one of its reception-desk emails
Useful when inbound mail comes from an impersonal address (info@acme.com) that doesn’t match any individual Contact — this correlates it back to the Organization.
find_by_org_no
Post /ops/find_by_org_no | Auth: Read
Lookup an organization by national registry number
Strong-identity dedup helper. Org numbers are country-specific (Swedish organisationsnummer, US EIN, UK CRN, etc.) — this op does exact-string match; callers are responsible for normalising format (e.g. Swedish 5590123456 vs 559012-3456) before lookup.
find_by_phone
Post /ops/find_by_phone | Auth: Read
Lookup an organization by phone number
Inbound-call correlation — when an incoming call’s caller-ID doesn’t match any Contact’s personal phone, check if it matches an Organization’s main/regional line.
find_by_social
Post /ops/find_by_social | Auth: Read
Lookup an organization by social profile (platform + handle/URL)
get
Post /ops/get | Auth: Read
Fetch an organization with all child groupings
import_bundle
Post /ops/import/bundle | Auth: Write
Import git bundle into element
Accepts a base64-encoded git bundle in the JSON bundle_base64 field. Use overwrite=true to replace existing elements with same slug (default skips duplicates). Imported elements get new UUIDs. Returns counts of imported/skipped elements and any errors.
import_csv
Post /ops/import_csv | Auth: Write
Bulk import organizations from a CSV string
Header row required. Recognised columns: name, legal_name, org_no, domain, industry, size, website, description, email, phone, tags (semicolon-separated), notes. Each row becomes an Organization (with one email and/or phone child row if those columns were populated). Returns counts (created, updated, skipped).
intention
Get /ops/intention | Auth: Read
Get element intention with full inheritance chain
Returns three levels: direct (this element’s intention), inherited (from category and root), and resolved (final merged intention). Useful for understanding an element’s purpose in context of its hierarchy.
list
Post /ops/list | Auth: Read
Page through organizations (newest first by default)
Without filters, returns all organizations newest-first.
tagfilters to organizations carrying a specific tag.industrymatches the industry field.
list_contacts
Post /ops/list_contacts | Auth: Read
List the Contacts linked to this organization (people who work there)
promote
Post /ops/promote | Auth: Admin
Promote element configuration to a target environment
Only for manifest-form elements (projects). Environments advance: dev → demo → live. dev→demo requires member+ role, demo→live requires admin. Freezes member versions at promotion time (creates snapshot). Persists environment config to spec.environments.
readme
Get /ops/readme | Auth: Read
Get element README.md content
Reads README.md from the element’s git repository. Returns empty content (not an error) if no README exists. Always returns markdown format.
readme_update
Post /ops/readme_update | Auth: Write
Update element README.md content
Creates or overwrites README.md in the element’s git repo. Commits to the draft branch. Content must be provided as a markdown string.
remove-modifier
Post /ops/remove-modifier | Auth: Execute
Remove an attached modifier from this element by attachment ID
Removes a modifier/resource attachment by its row ID. The ID comes from the attachments or context API. This is the reverse of attach — called on the target element, not the source.
remove_address
Post /ops/remove_address | Auth: Write
Detach an address from an organization by address_id
remove_email
Post /ops/remove_email | Auth: Write
Detach an email from an organization
remove_phone
Post /ops/remove_phone | Auth: Write
Detach a phone from an organization
remove_social
Post /ops/remove_social | Auth: Write
Detach a social profile from an organization
restore
Post /ops/restore | Auth: Admin
Restore element to a specific version
Automatically snapshots the current state before restoring (creates a ‘Before restore to vN’ version entry). Writes restored spec to git as .triform/spec.yaml. Git failures warn but don’t fail the operation — DB state is authoritative. Cannot restore deleted elements.
schema
Get /ops/schema | Auth: Read
Get element input/output schema (MCP tools/list compatible)
Returns type-level port schemas from the TypeRegistry — not instance-specific overrides. Includes direction (input/output), required flag, and JSON schema per port. Useful for understanding what data an element accepts and produces.
search
Post /ops/search | Auth: Read
Free-text search across name, legal_name, domain, description, notes
source
Get /ops/source | Auth: Read
Get any file’s content from the element’s git repository
Reads an arbitrary file from the element’s CAS-backed git tree by its relative path. Same store as
readme, just generalized. Path safety: rejects..traversal, leading/, and null bytes. Use this to viewmain.pyfor action elements, asset files for SPAs, etc. Returns empty content (not an error) if the file doesn’t exist.
source_branches
Get /ops/source/branches | Auth: Read
List Source branches for this element
Returns the standard draft/demo/live Source branches, their current commits, and promotion relationships. Use GET /api/{element_path}/ops/source/branches.
source_fixtures
Post /ops/source/fixtures | Auth: Write
Dry-run or apply approved Source seed fixtures
Scans
.triform/fixtures/manifests from the addressed data element Source repo. Defaults to dry_run=true and never imports live runtime data. Apply requires dry_run=false plus confirm=true and dispatches approved records through existing generated element ops.
source_promote
Post /ops/source/promote | Auth: Write
Promote Source branch forward
Promotes draft to demo or demo to live through the generated element op path. Direct Git pushes to demo/live are blocked by Source policy.
source_repair
Post /ops/source/repair | Auth: Write
Inspect or repair the element Source index
Runs Source repair through the element operation path. Defaults to dry_run=true; set dry_run=false only after reviewing a dry-run report.
source_status
Get /ops/source/status | Auth: Read
Get Source control status for this element
Returns the branch-aware clone URL, checkout commands, current draft commit, child source-link count, portable export summary, Source health, warnings, and auth hints for the addressed element. Use the element-first path: GET /api/{element_path}/ops/source/status.
source_validate
Post /ops/source/validate | Auth: Read
Validate Source branch contents
Validates a Source branch before accepting local Git workflow changes or promotion. Defaults to branch=draft and rejects runtime data, generated output, secret material, and unreadable CAS refs.
stats
Post /ops/stats | Auth: Read
Aggregate counts — total orgs, contacts-per-org, by-industry, by-size
tag
Post /ops/tag | Auth: Write
Add a tag to an organization
tree
Get /ops/tree | Auth: Read
Get the element’s position in the graph — ancestors, children, references, and subtree statistics
Uses per-circle ElementGraph cache for O(1) lookups. Returns ancestors (containment chain), children (direct), members (references), referenced_by (reverse refs), attachments, and subtree stats. Default depth is 3, max is 10. Pass ?include_metadata=true for name/state on each node.
untag
Post /ops/untag | Auth: Write
Remove a tag from an organization
update
Patch /ops/update | Auth: Write
Update element
Partial update — send only the fields you want to change.
spec,name, andintentionare all independently optional.specMUST be a JSON object when present; deep-merged into the existing spec by default. Empty{"spec":{}}preserves existing spec content but still records a new version (no-op for content, not for version state). To clear/replace the entire spec wholesale send{"spec":{...},"deep":false}. List-typed spec fields use replace semantics (the patch list replaces the existing list, no array merging). Coordinates Git + DB writes. Slug cannot be changed after creation.
update_address
Post /ops/update_address | Auth: Write
Update one address on an organization by address_id
update_meta
Patch /ops/update_meta | Auth: Write
Update element metadata (lightweight merge — does NOT bump version or snapshot spec)
Shallow JSONB merge into element.meta. Top-level keys in the provided value replace existing meta values; other keys are preserved. Used for UI metadata like canvas positions, panel state, viewer preferences. Wire-shape op_name is
update_meta(distinct fromupdate) so SSE subscribers + the cache auto-invalidator can distinguish lightweight metadata changes from spec edits without inspecting the payload. The MutatingElementStore wrapper stamps this op_name on the lifecycle event emitted byupdate_element_metastorage calls.
upsert
Post /ops/upsert | Auth: Write
Create or update an organization — merges child groupings by natural key
Idempotent on
id(when provided), or on a deterministic match againstdomainororg_no(both strong identities). The emails, phones, socials, and addresses arrays UPSERT their rows — existing rows matching on natural key are merged; new rows are inserted. Rows NOT named in the arrays are preserved. Tags union with existing tags. Custom JSON merges shallowly at top level.
version
Get /ops/version | Auth: Read
Get current version or full history
Returns current version by default. Pass ?history=true for full version history (up to ?limit=N, default 50). Versions are backed by the element_versions table. Every spec update creates a new version entry.
Error Codes
| Code | Class | Retryable | Description |
|---|---|---|---|
ORG_NOT_FOUND | not_found | no | No organization matching the provided id, domain, org_no, or email |
ORG_DUPLICATE_DOMAIN | conflict | no | Upsert would create a duplicate — same domain already belongs to a different organization id |
ORG_DUPLICATE_ORG_NO | conflict | no | Upsert would create a duplicate — same org_no already belongs to a different organization id |
ORGANIZATIONS_CSV_PARSE_ERROR | validation | no | CSV input could not be parsed — check header row and encoding |
Observability
Defined for this element
Metrics
- organizations_inserted_count
- organizations_updated_count
- organizations_deleted_count
- organizations_query_count
- organizations_query_latency_ms
Events
- organizations.organization.inserted
- organizations.organization.updated
- organizations.organization.deleted
- organizations.query.executed
Pricing / cost
Platform default
Operation costs
- create: free
- update: free
- delete: free
- get: free
- list: free
- invoke: 10000 micro-AU
- tool_use: free