Skip to content
indraft
Start free

Your own objects

The five that matter are built in. The rest are yours.

Companies, contacts, opportunities, interactions and tasks mean the same thing in every Indraft workspace. If the thing your business runs on is not one of those, you define it, and it gets the same history, attribution, and undo as everything else.

Why two tiers

Most CRMs pick one and lose the other

A CRM with a fixed schema understands your data and cannot model your business. A CRM where everything is customisable can model anything and understands none of it, which is why its duplicate detection is a keyword match and its forecast is a spreadsheet formula you configured.

Indraft does both, by being clear about which is which. A Company is a Company here and in every other workspace, so identity resolution can use a normalised domain and a merge can be undone. A Candidate is yours, so it means whatever you decided, and nothing pretends to understand it.

Deciding between the two is one question: would the thing mean the same in somebody else's workspace? A person you email is a Contact anywhere. A Candidate carries your rates, your stages and your process, so a Candidate is yours. You can have both, and a Candidate can point at the Contact who referred them.

One thing to do when you define it. A type of your own does not match anything until you say what sameness means for it, so name the field that identifies a record: an email, or the identifier your other system uses. Then the same candidate submitted twice is one record, on the same terms a Company matches on its domain. Skip it and every write creates, which is right for a Placement and wrong for a Candidate.

Declaring it later is fine, and it is honest about what it finds: if records already share a value, it refuses and names them rather than merging anything. You merge those, then declare it.

Real columns
A field you declare becomes a typed, indexable column, not a row in an attribute table and not a JSON blob. That is what lets a report exist later without a migration.
The same guarantees
Idempotent writes, expected versions, a full change history with who wrote each field, undo, and a place in the export. A record your agent invented is not a second-class record.
Declared relationships
A Candidate has an employer, and the employer is a Company. Named, typed, and checked: a link to a record that does not exist is refused rather than stored and discovered later.
Your types link to each other
Not only to ours. A Placement points at a Candidate and a Job Opening; a Deliverable belongs to a Campaign. Both ends can be types you defined, which is the difference between a model and three disconnected lists.

How it happens

Your agent does the modelling

You do not open an admin panel and drag fields around. You tell your agent what your business tracks, and it defines the type, adds the fields, and starts filling it. The tool set is the same four calls whatever your schema looks like, so an agent that can do this in one workspace can do it in any of them.

A type can grow afterwards. Adding a field leaves every existing record intact, and nothing you have already written is rewritten or lost.

configure_object_type
Define a NEW object type this workspace needs and Indraft does not have: a Candidate, a Campaign, a Unit. To change a type that already exists, use alter_object_type. Typed fields and named relationships to existing records. The canonical types cannot be redefined this way, and a type you define carries the same history, attribution, and undo as everything else.
alter_object_type
Change a type this workspace has ALREADY defined; use configure_object_type to create one. Add a field, declare which field is its identity so duplicates are refused rather than created, or archive and restore it. Declaring an identity over records that already share a value is refused and names them, so nothing is merged by surprise.
list_object_types
The custom object types this workspace has defined, with their fields and relationships. Canonical types (company, contact, opportunity, interaction, task) are not here: they are in get_crm_schema and mean the same thing in every workspace.
list_object_records
Records of one custom object type, newest first, with a cursor for the next page. The type must be one this workspace defined; ask get_crm_schema or list_object_types for the names. Filters and sorts exactly like the built-in lists, on the fields the type declared indexed.
upsert_object_record
Create or update one record of a custom object type. Supply only fields the type declares; an undeclared field is refused rather than ignored, so nothing you send goes missing silently.
archive_object_record
Archive one record of a type this workspace defined for itself, or restore it. For a company or a contact use archive_record instead. Archiving keeps the record readable and exportable and takes it out of lists; it is not a delete.
advance_object_record
Move one record of a custom type to a stage of that type's pipeline. Status (open, won, lost) is derived from the stage, exactly as it is for an opportunity, so this is how a record of your own type is won or lost. The type needs a pipeline first: give it one with configure_pipeline naming the type. Filter list_object_records by _stage_id or _status to read a board.
merge_object_records
Merge a duplicate record of a custom type into a target. References move to the target and the source is archived. You must name both ids: nothing here works out which records are the same, and a custom type has no natural key. Not undoable by revert_change; use unmerge.

Being clear about it

What your own objects do not get

Pipeline maths and duplicate detection stay with opportunities and with companies and contacts, because they rest on what those things specifically are. A stage has a kind, which is how a forecast can mean the same thing in two workspaces. An identity match uses a normalised email or domain, which is how a merge can be safe.

Your own types have neither, and inventing a guess at either would be worse than not having it: a forecast nobody can compare, or a merge that combined two different people because their names matched.

What counts as a record

A record of your own type counts exactly like a company or a contact. Four hundred Candidates is four hundred records, and it is the same number whether you modelled them as their own type or crammed them into a field on something else. Interactions and tasks are not records on either side of that line, so recording what happened stays free of the count.

What it costs

The free plan includes 3 of your own object types, which is enough to model a real business rather than enough to see the feature exists. Paid plans raise the number. Every other guarantee is the same on every plan, including the free one.

No files, whatever the type

A Candidate can have a rate, a stage and a link to a Company. It cannot have a CV attached, and neither can anything else here. Indraft stores no files, no email bodies and no transcripts, on our objects or on yours. Keep the document where it already lives and record the conclusion and a reference to it, which is what your agent should be writing anyway.

Leaving with them

The export carries your type definitions as well as your records, so what comes out describes the schema you designed rather than a pile of rows somebody would have to reverse-engineer. Deciding to leave should not mean deciding to lose the shape of your business.

Next

Tell your agent what you track

Connect it, describe your business in a sentence, and look at what it builds. If the CRM it produces is not one you would keep, you have lost an afternoon and no money.

If you change your mind

A type you no longer want is archived, which takes it out of the schema and every surface and keeps every record readable and exportable. Only after that can it be destroyed, and only by an owner signed in as a person. Nothing an agent holds can do it.