Custom Data: Levels & Tiers
Two ways to extend Portablemind with your own data — custom objects, or your own backend.
Every workspace eventually needs to store or reach data that doesn't fit Portablemind's built-in models — a domain object of your own, or records that already live in a system you run. There are two ways to do that today, and they suit different situations. Neither requires deploying any infrastructure of your own; the difference is where your data lives.
| Tier 1 — Custom Objects | Tier 2 — Your Own Backend | |
|---|---|---|
| Where the data lives | Stored in Portablemind | Stays in your system |
| Best for | New object types you don't have anywhere else | Data that already exists elsewhere, or that must stay under your control |
| Set up by | Defining fields (and, today, via API/agent) | Writing a Dynamic Function, or configuring a webhook |
Tier 1 — Custom Objects (DynamicModel)
Use this when you want to track something Portablemind has no built-in model for — a piece of equipment, a competitor, a lease, a claim, whatever your business needs — and you're fine with it living in your workspace like everything else.
A custom object is a dynamic_model_type (a name you choose, e.g. "competitor_analysis") plus whatever fields you give it. Two things make this more than a generic blob:
- Typed field definitions — instead of an unvalidated bucket of JSON, you can define named fields with types (text, number, date, select, etc.) for a given
dynamic_model_type, the same mechanism already used for custom fields on Tasks, Projects, and Tickets. Once defined, values are validated against the definition. - Associations — custom objects can be linked to each other, or to any other record in your workspace (a Task, a Project, a Party), with a label you choose (
"related_to","blocks","parent_of", ...). This is how you build real relationships between custom objects instead of duplicating data into a single flat record.
Custom objects are immediately queryable by AI agents (they show up like any other model via the standard tool-exposure pattern), and by search — no migration or deploy needed to add a new type or a new field.
How to use it today: there's no dedicated admin screen for this yet — you (or an agent acting for you) create and manage custom objects and their field definitions through the API, or by asking an AI agent to do it for you (an agent has the same executeAction/CRUD access to DynamicModel that Dynamic Functions do). A workspace admin can also drive the underlying custom_field_definitions and dynamic_model_associations endpoints directly if you're integrating from your own tooling.
Tier 2 — Your Own Backend (Dynamic Functions + Webhooks)
Use this when the data already lives somewhere else — your own database, a CRM, an accounting system — or when you'd rather keep it there than copy it into Portablemind. Portablemind doesn't store the data; it talks to your system instead.
There are two directions this goes:
- Pull — a Dynamic Function is your own serverless JavaScript, running in your workspace, that can call out to any external API (
fetch, with OAuth handled for you via a Shared Configuration). Trigger it manually, from the API, on a schedule, or on a platform event (a callback when a record changes) — it reads from or writes to your system on your behalf. - Push — an outbound webhook does the opposite: when something happens in Portablemind (today, a new message in a conversation), we POST it to a URL you configure, signed with HMAC-SHA256 so you can verify it came from us. This is how you keep your own system in sync without polling.
The two compose: a Dynamic Function can pull fresh data in on a schedule, while an outbound webhook pushes activity out in real time.
When to prefer this over Tier 1: your data is sensitive and you'd rather it not leave your infrastructure at all; it already exists in a system of record you're not going to replace; or you need custom logic (validation, transformation, side effects in another system) rather than just storage.
How to use it: see the Dynamic Functions guide for writing pull-side logic, OAuth, schedules, and callbacks. Outbound webhooks are configured per conversation — ask an admin or your integration contact to set one up with the destination URL you want to receive events at, and hold onto the signing secret shown at creation time (it isn't shown again).
Choosing between them
Start with Tier 1 if you're not sure — it's the lower-friction option and works well for anything that's genuinely new data. Reach for Tier 2 only when the data has to stay outside Portablemind, or when keeping it in sync with a system you already run matters more than having it live natively alongside your Tasks, Projects, and Tickets.