Skip to main content
This page covers the mental model behind the API. Read it before diving into the endpoint reference.

Canonical objects

Every entity in Structural is stored as a canonical object - a platform-agnostic shape with:
  • A typed, prefixed ID (e.g., pay_xK9mN2vL8gM3y6P for a payment)
  • An object discriminator ("payment", "project", "invoice", etc.)
  • An external_ids map preserving each platform’s native identifiers for lossless round-trip conversion
When you read objects via GET /api/v1/objects, the data field contains the canonical view. The platform_data field contains the raw platform payload. The mappings array is a service-layer join showing which platforms the entity is linked to - it is not a stored field on the canonical object itself.

Entity types

Structural supports different entity types depending on the endpoint:
SurfaceEntity types
/connect + /objectsproject, customer, contract, invoice, payment
/propagateproject, customer, contract, invoice, payment
/transformproject, customer, contract, invoice, payment, employee, time_entry, change_order, budget_line_item
/transform accepts 9 entity types because it is a stateless translation primitive - it does not require entity data to be seeded via /connect.

Platform connections

Call POST /api/v1/connect with {"platform": "procore"} to seed that platform’s data. Check the result with GET /api/v1/connections. Each customer can connect both Procore and Dynamics; the order does not matter.

Entity reconciliation

When both platforms are connected, Structural automatically matches entities across systems using business keys (check numbers, invoice numbers, contract numbers). The same real-world entity appears as one canonical object whose mappings array contains both platforms’ native IDs. You do not need to pair entities manually. The mappings array on each GET /api/v1/objects response tells you which platform IDs refer to the same entity.

Two write paths

Structural offers two ways to write data:

/transform - stateless preview

Pass in platform data, get back the canonical form and the target platform’s representation. Nothing is persisted. Use this when you want to:
  • Preview what a cross-platform translation looks like
  • Validate your data shape before committing
  • Get Structural’s canonical representation without side effects

/propagate - stateful write-through

Write a change through the canonical layer and fan it out to every connected platform. This persists data. Use this when you want the change to actually land in connected platforms. Rule of thumb: use /transform to preview, use /propagate to commit.