Skip to content

Identity and consent

JustAI connects everything it knows about a person through two values: your user ID and their email address. The user ID joins customer profiles and customer events. The email address is how JustAI reaches the person in Iterable, and it is the address that email consent decisions apply to. Settle both before you connect a data source. JustAI identifies each profile by the exact user ID you send, so a different ID later creates a different person.

Settle these points at kickoff:

Data JustAI matches it on
Customer profile, from the Identify API userId
Customer event, from the Track API userId, matched to the profile with the same user ID
Customer-specific profile file import The user ID mapping confirmed by your JustAI team
CSV upload The email column, plus the user_id column when you include one
Iterable recipient traits.email on the profile
Email consent decision traits.email on the profile
SMS consent decision traits.phone on the profile

Use the ID your own systems give each person, one that never changes and is never reused for someone else. Send exactly the same value from every source: Identify, Track, file imports, and the user_id column in a CSV.

  • Send it as a string. Send "1234", not 1234. Identify and Track reject a number. For a customer-specific file import, confirm the supported ID type with your JustAI team.
  • Match it character for character. JustAI compares IDs exactly. Identify removes leading and trailing spaces, but Track stores the ID as sent, so trim IDs in your source.
  • Do not use values that change. Session IDs, device IDs, and other temporary values split one person into many profiles.

If your systems have no stable ID for each person, talk to your JustAI team before you connect a data source.

Send each person’s email address as traits.email in Identify. JustAI identifies every recipient to Iterable by this address, on every channel. Iterable finds its user by that email, and sends texts and pushes to that user’s phone or devices. The address must be the one Iterable knows the person by. A person without an email address in JustAI can’t receive messages through Iterable, including SMS and push.

By default, two user IDs with the same email address stay two people. Ask your JustAI team whether treating each email address as one person is available and appropriate for your organization. Confirm that setup before relying on it. When it is enabled, an Identify call with an email address that already belongs to another profile joins the two, and both user IDs then read back the same profile. Placeholder values that are not real addresses, such as unknown or N/A, never join profiles.

Some sources assign an anonymousId to visitors before they sign in. Track accepts an event with only an anonymousId, and the event appears in Events > Custom events. JustAI does not use anonymous IDs for anything else:

  • Identify requires userId. An Identify call with a missing, empty, or null userId returns 400. Filter anonymous Identify calls out before they reach JustAI.
  • Identify ignores anonymousId. JustAI has no alias call, and it never links earlier anonymous events to a profile.
  • An event with only an anonymousId never starts, moves, or ends a journey, and never counts as a conversion.

Send the events you want journeys and measurement to use after the person has a user ID, and include that user ID.

Check these points before you connect a full data source:

  • The userId in Track matches the userId in Identify for the same person. If an event’s user ID has no profile, a journey run starts without the person’s traits or email address, and email steps can’t send to them.
  • Each person’s profile exists before their first event. Send Identify first.
  • Every CSV upload has a user_id column, with the header user_id or User ID. A header of userId does not count. Without it, a later Identify call with a user ID creates a second person. See Link people to your user ID.
  • For a customer-specific profile import, agree on an ID mapping that preserves the same user ID. See Amazon S3 file import.
  • traits.email holds the address your Iterable project uses for the person.

To check all of this with one test person, see Test your connection.

Iterable projects identify users by email address (email-based), by user ID (userID-based), or by either (hybrid). JustAI sends to Iterable by email address, so connect an email-based or hybrid project in Iterable’s US data center. JustAI does not support userID-based projects. If your project is userID-based, talk to your JustAI team before you plan your rollout.

For setup, this means:

  • Every person you want to reach needs traits.email in JustAI, for every channel.
  • JustAI does not send your user ID to Iterable. The user IDs you send to JustAI do not need to match user IDs in your Iterable project.

See Connect Iterable for the rest of the Iterable setup.

JustAI checks the consent decisions you send with Identify, and its own suppressions (people blocked from email in JustAI), before it hands an email to Iterable. These checks apply to email only. JustAI does not send email to people suppressed in JustAI. When your organization requires marketing consent, it also does not send email to people without it. A journey run then shows Not sent with “Marketing consent is missing.” or “Sending is blocked for this recipient.” The results of a blast, a one-time send from Blasts, group these people as Unsubscribed and No marketing consent under Not sent.

Your JustAI team confirms with you during onboarding whether marketing consent is required and for which regions.

Consent decisions do not appear in Users. Suppressions do. For a suppressed person, the Subscription column on Users reads Email suppressed, and the person’s page shows an Email badge under Suppressions. To suppress one person by hand, open them in Users, select Edit user, and turn off Email subscription.

For email that JustAI sends through Iterable, Iterable owns unsubscribes:

  • The unsubscribe link in each message is Iterable’s own. Iterable applies its subscription settings for the message type of your sending profile. Keep the unsubscribe link in the templates JustAI creates.
  • Confirm with your JustAI team how Iterable unsubscribes reach your system of record and JustAI. Do not assume a change in one system updates the other or starts a subscription-change journey. Test an unsubscribe with an address you control, then verify the subscription state in Iterable and the suppression or consent state in JustAI before launch.
  • For SMS sent through Iterable, Iterable handles STOP replies.

Keep your own system of record as the source of truth for consent. When a person’s consent changes there, send the decision to JustAI with Identify, and update the person’s subscription settings in Iterable to match.

Identify accepts an optional consent array. Each entry records one decision for one channel. This call records that the person agreed to marketing email through a signup form:

Request
{
"userId": "user-1234",
"messageId": "user-1234:consent:2026-10-12T15:00:00Z",
"timestamp": "2026-10-12T15:00:00Z",
"traits": {
"email": "ada@example.com"
},
"consent": [
{
"channel": "email",
"status": "granted",
"purpose": "marketing",
"basis": "consent",
"source": "signup_form",
"consentedAt": 1791817200000,
"proofRef": "newsletter-form-v3"
}
]
}

Each decision needs a channel (email or sms) and a status (granted, withdrawn, or unknown). The optional fields record the purpose, the legal basis, where the decision came from, when the person made it, and what they agreed to. Unlike the call’s timestamp, consentedAt and expiresAt are epoch milliseconds, not ISO 8601 strings. For every field, its values, and the validation rules, see Consent decisions in the Identify API reference.

  • A decision applies to the address, not the user ID. Email decisions apply to traits.email, trimmed and lowercased. SMS decisions apply to traits.phone. Include the address in the same call unless the profile already has it. If JustAI knows no address for the person, it skips the decision, and the call still returns 200.
  • The newest decision wins. The decision time is consentedAt. If you omit it, or set it more than 5 minutes in the future, JustAI uses the call’s timestamp or the time it receives the call. When two decisions have the same time, withdrawn wins over granted. A decision with status unknown never replaces an existing decision.
  • Implied consent expires. A granted implied_transaction decision lapses 2 years after consentedAt. A granted implied_inquiry decision lapses 6 months after consentedAt. A granted implied_contract decision lapses at the expiresAt you send. If you send an earlier expiresAt for the first two, JustAI uses the earlier date.
  • Some combinations need more fields. A granted implied-consent decision requires consentedAt, and a granted implied_contract decision also requires expiresAt. See Validation rules.
  • Use a new messageId for every consent change. JustAI does not compare consent when it checks for a retry. A call that reuses an earlier ID with the same userId, timestamp, and traits returns "duplicate": true and drops the new decision.

To record a withdrawal from a preference center for a person whose profile already has an email address, send "traits": {} with the consent entry. For a user ID JustAI has not seen, this call creates an empty profile and skips the decision, because JustAI knows no address for it. When you are not sure the profile has the address, include traits.email in the call.