Ortto
Datafly Signal delivers your first-party events to Ortto server-side using the Custom Activity API. Each event upserts the person in Ortto (matched by email, with phone as a fallback) and records a timestamped custom activity against them, ready to drive journeys, segments, and reports.
Because delivery is server-to-server, no Ortto tracking pixel runs in the browser, and identity fields are sent from your own first-party data rather than scraped client-side.
Why route Ortto through Datafly Signal
- Profiles are updated from the server, not the browser. Events reach Ortto even when a tracker blocker or a failed page unload would have dropped a client-side call, so the profile reflects what actually happened.
- Delivery is batched, rate-limited, and retried. Signal buffers to Kafka, respects the Ortto rate limit, and retries on 429 or transient failure rather than dropping the event.
- Presets for Retail and B2B / SaaS. The mapping starts from a working configuration for your vertical instead of a blank field map.
- One consent decision governs every destination. Ortto is gated by the same consent state as the rest of your stack, so a withdrawal applies everywhere at once.
Prerequisites
- An Ortto account with the Custom Activity API available on your plan.
- A custom (private) API key with activity write access. Create one in Ortto under Settings → API keys. This is not the public tracking-code key.
- One or more custom activity definitions created in Ortto (Activities → New activity). Each definition has an activity ID in the form
act:cm:<slug>(for exampleact:cm:order-completed). You will map your Signal events to these IDs. - Your Ortto instance region, which determines the API host (see below).
Configuration
| Field | Required | Description |
|---|---|---|
| Custom API Key | Yes | Ortto custom API key, sent in the X-Api-Key header. |
| API Host (region) | Yes | api.ap3api.com (default), api.au.ap3api.com (Australia), or api.eu.ap3api.com (Europe). |
| Merge Strategy | No | How to update an existing person: 1 append only, 2 overwrite existing (recommended), 3 ignore. Sent as a number when set; Ortto defaults to 2. |
Pick the host that matches the region your Ortto instance is pinned to. A mismatched region returns 401 or 404.
Configure in Signal
- In the Signal management UI, go to Integrations and add Ortto.
- Paste your Custom API Key and select the API Host for your region.
- Choose a preset (Retail or B2B / SaaS) or start from the default mapping.
- For each event in the preset, set vendor event name to the matching Ortto activity ID (
act:cm:<slug>) from your Ortto activity definitions. - Attach the integration to your pipeline and publish.
API Endpoint
POST https://api.ap3api.com/v1/activities/create
X-Api-Key: <your-custom-api-key>
Content-Type: application/jsonAustralia and Europe instances use api.au.ap3api.com and api.eu.ap3api.com respectively.
Identity Signals
Server-side delivery to the Ortto Custom Activity API (/v1/activities/create). Each Signal event upserts the person by email (merge_by str::email; plain text, trimmed and lowercased, because Ortto keys the person on it) with first and last name and the source IP, and records a custom activity (act:cm:<event>) with typed attributes: text as str, money as int x1000, quantities as whole numbers. Events without an email are not sent.
| Field | Source | Notes |
|---|---|---|
fields.str::email | traits.email | Plain text, trimmed and lowercased; the merge key (merge_by: ["str::email"]). Required. |
fields.str::first / str::last | traits.first_name / last_name | |
location.source_ip | context.ip | For Ortto’s geo lookup. |
phn::phone | not sent | Ortto types it as {c, n}, which Signal cannot build from an E.164 number yet (#1483). |
Event Mapping
Blueprint 0.6.0, reviewed against the vendor’s documentation on 2026-09-23. Each preset maps the events below; every other event is dropped. Events use the canonical names from the event specs (transaction_id, value, items[], search_term); the legacy order_id, revenue and flat product fields are still read as a fallback.
Retail / E-commerce (ecommerce)
Retail funnel as Ortto custom activities: page viewed, product viewed and added, checkout started and order completed with the conversion value. Each activity upserts the person by email (merge_by str::email; str::email is sent in plain text, trimmed and lowercased, because Ortto keys the person on it; events without an email are not sent), with first and last name and the visitor IP for geo. Attribute types follow Ortto’s typed IDs: text as str:cm:, money and decimals as int x1000 (int::v, int:cm:price), quantities as whole numbers. Create each act:cm: activity and its attributes in Ortto first.
| Datafly event | Vendor event / call | Fields |
|---|---|---|
page | act:cm:page-viewed | str:cm:page-url, str:cm:page-title, str:cm:referrer |
view_item | act:cm:product-viewed | str:cm:product-id, str:cm:product-name, str:cm:category, str:cm:brand, int:cm:price, int:cm:quantity |
add_to_cart | act:cm:product-added | str:cm:product-id, str:cm:product-name, str:cm:category, str:cm:brand, int:cm:price, int:cm:quantity |
begin_checkout | act:cm:checkout-started | int::v, str:cm:currency |
purchase | act:cm:order-completed | str:cm:order-id, int::v, str:cm:currency, str:cm:coupon |
B2B / SaaS (saas)
Account lifecycle as Ortto custom activities: page viewed, signed up, logged in, trial and subscription started. Each activity upserts the person by email (merge_by str::email; str::email is sent in plain text, trimmed and lowercased, because Ortto keys the person on it; events without an email are not sent), with first and last name and the visitor IP for geo. Attribute types follow Ortto’s typed IDs: text as str:cm:, money and decimals as int x1000 (int::v, int:cm:price), quantities as whole numbers. Create each act:cm: activity and its attributes in Ortto first.
| Datafly event | Vendor event / call | Fields |
|---|---|---|
page | act:cm:page-viewed | str:cm:page-url, str:cm:page-title |
sign_up | act:cm:signed-up | str:cm:method |
login | act:cm:logged-in | str:cm:method |
trial_started | act:cm:trial-started | str:cm:plan |
subscription_started | act:cm:subscription-started | str:cm:plan, int::v, str:cm:currency, str:cm:coupon |
Default (default)
Page views, sign-ups and orders as Ortto custom activities. Each activity upserts the person by email (merge_by str::email; str::email is sent in plain text, trimmed and lowercased, because Ortto keys the person on it; events without an email are not sent), with first and last name and the visitor IP for geo. Attribute types follow Ortto’s typed IDs: text as str:cm:, money and decimals as int x1000 (int::v, int:cm:price), quantities as whole numbers. Create each act:cm: activity and its attributes in Ortto first.
| Datafly event | Vendor event / call | Fields |
|---|---|---|
page | act:cm:page-viewed | str:cm:page-url, str:cm:page-title, str:cm:referrer |
sign_up | act:cm:signed-up | str:cm:method |
purchase | act:cm:order-completed | str:cm:order-id, int::v, str:cm:currency, str:cm:coupon |
An identified purchase (preset ecommerce) is delivered as:
POST https://api.eu.ap3api.com/v1/activities/create{
"activities": [
{
"activity_id": "act:cm:order-completed",
"attributes": {
"int::v": 439990,
"str:cm:coupon": "SUMMER",
"str:cm:currency": "GBP",
"str:cm:order-id": "T-1001"
},
"fields": {
"str::email": "jane.doe@example.com",
"str::first": "Jane",
"str::last": "Doe"
},
"location": {
"source_ip": "203.0.113.7"
}
}
],
"merge_by": [
"str::email"
]
}Testing
- Send a test event from a page running Datafly.js (or use the management UI Event Debugger).
- In Ortto, open People, find the person by email, and confirm the activity appears on their Activity timeline.
- Confirm the activity attributes (order ID, value, currency) are populated as expected.
- A successful call returns
200. A400usually means an unknownactivity_idor a missing required field;401/403indicate a bad or under-scoped key, or the wrong region host.
Troubleshooting
401/403— the API key is invalid, lacks activity write access, or you selected the wrong region host. Verify the key in Settings → API keys and confirm the host matches your instance region.400unknown activity — theactivity_idin your event mapping does not exist in Ortto. Create the activity definition first, then copy itsact:cm:<slug>ID into the mapping.- Person not matched — confirm the email trait is set before the event fires and that
merge_byisstr::email. Without a match key, Ortto cannot attach the activity to a person. - Activity missing despite a
200— Ortto limits activities to 50 per activity per contact per 24 hours. High-frequency events (such as page views) on a single contact can hit this cap; map noisy events sparingly. - Wrong currency amount —
int::vexpects an integer in cents. Make sure your value mapping multiplies by 100.