> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getmateo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom Entity Journeys

> Learn how to use custom entities to sync external data and trigger journey automations.

Custom entities are schema-driven data objects attached to contacts. They allow you to sync structured data from external systems (e.g. vouchers, tickets, subscriptions) into Hellomateo and automatically trigger journeys when that data is created or updated.

## Prerequisites

Before you can trigger journeys with custom entities, you need to:

1. Create a journey in Hellomateo with a **Custom Entity** trigger node
2. Set the trigger's `event_type` to `custom_entity_created` or `custom_entity_changed`
3. Set the `custom_entity_definition_id` on the trigger node to scope it to a specific entity type
4. Publish the journey and set it to active

## Create a Custom Entity Definition

A custom entity definition describes the shape of your data. Create one via the API:

```bash theme={null}
curl "https://integration.getmateo.com/api/v1/custom_entity_definition" \
  -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Prefer: return=representation" \
  -d '{
    "key": "voucher",
    "name": "Voucher",
    "schema": {
      "type": "object",
      "properties": {
        "voucher_id": { "type": "string" },
        "status": { "type": "string" },
        "code": { "type": "number" }
      },
      "required": ["voucher_id", "status"]
    }
  }'
```

The `key` is a unique, human-readable identifier for the definition. The `schema` field accepts a JSON Schema that validates entity data on write.

## Create a Custom Entity

Creating a custom entity triggers any journey with a `custom_entity_created` trigger scoped to the matching definition:

```bash theme={null}
curl "https://integration.getmateo.com/api/v1/custom_entity" \
  -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Prefer: return=representation" \
  -d '{
    "custom_entity_definition_key": "voucher",
    "contact_id": "CONTACT_UUID",
    "external_id": "VOUCH-12345",
    "data": {
      "voucher_id": "VOUCH-12345",
      "status": "sent",
      "code": 102938405
    }
  }'
```

| Field                          | Type   | Required | Description                                                         |
| ------------------------------ | ------ | -------- | ------------------------------------------------------------------- |
| `custom_entity_definition_key` | string | Yes\*    | Key of the definition. Alternative to `custom_entity_definition_id` |
| `custom_entity_definition_id`  | UUID   | Yes\*    | ID of the definition. Alternative to `custom_entity_definition_key` |
| `contact_id`                   | UUID   | Yes      | The contact this entity belongs to                                  |
| `external_id`                  | string | No       | Your external system's ID for this entity (enables upsert behavior) |
| `data`                         | object | Yes      | The entity payload, validated against the definition's schema       |

\*Provide either `custom_entity_definition_key` or `custom_entity_definition_id`.

## Update a Custom Entity

Updating a custom entity's `data` field triggers any journey with a `custom_entity_changed` trigger scoped to the matching definition. The journey is only triggered when the `data` field actually changes:

```bash theme={null}
curl "https://integration.getmateo.com/api/v1/custom_entity?external_id=eq.VOUCH-12345&custom_entity_definition_key=eq.voucher" \
  -X PATCH \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Prefer: return=representation" \
  -d '{
    "data": {
      "voucher_id": "VOUCH-12345",
      "status": "used",
      "code": 120939485932
    }
  }'
```

## Discovering Custom Entity Journeys

You can query the API to find journeys that have custom entity triggers:

```bash theme={null}
curl "https://integration.getmateo.com/api/v1/journey?select=id,name,status,latest_published_version:latest_published_version_id(id,version,journey_node!inner(id,event_type,custom_entity_definition_id))&latest_published_version.journey_node.event_type=in.(custom_entity_created,custom_entity_changed)" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
```

This returns all journeys with custom entity triggers, including their `custom_entity_definition_id` so you know which entity types they respond to.

## Examples

### Voucher Campaigns

Sync voucher codes from your marketing platform. Use `custom_entity_created` to send the voucher to the contact, and `custom_entity_changed` to trigger a follow-up when the voucher is redeemed.

### ERP Sync

Sync contract or invoice data from your ERP. Trigger a journey when a new contract is created to kick off an onboarding flow.

### Form Submissions

Store structured form submission data as custom entities. Use `custom_entity_created` to trigger a follow-up journey that sends a confirmation and assigns the contact to a sales rep.

## Best Practices

* **Use `external_id` for idempotency**: Set `external_id` to your system's unique identifier (e.g. voucher code) so you can update entities by filtering on it
* **Prefer `custom_entity_definition_key` over UUID**: Keys are human-readable and stable across environments
* **Keep schemas simple**: Only include fields you need in the journey. Complex nested schemas are supported but harder to work with in the expression editor
* **One definition per domain object**: Create separate definitions for orders, tickets, subscriptions, etc. rather than a generic one
* **Test with `custom_entity_created` first**: It's easier to verify since it fires on every insert, while `custom_entity_changed` only fires when `data` actually changes
