Skip to content

Custom Integration

The Custom integration connects JustAI to any system that can make an HTTP request — a homegrown messaging pipeline, an in-app surface, a website, or an ESP we don’t yet integrate with natively. Instead of JustAI pushing content into your ESP, your system calls the Generate API and uses the copy in the response.

  1. Your system calls POST /api/generate/:org_slug with a template_id, a user_id, and (optionally) personalization fields.
  2. JustAI selects the best variant for that user — running the A/B split and ranking algorithms — and returns the copy as copy.vars (e.g. subject, body).
  3. Your system delivers the message through your own channel.
  4. You report downstream events (sends, opens, clicks, conversions) back to JustAI via webhooks or a data export, joined on the tracking_id.

See the API Quickstart for authentication and key management.

On your template’s Configure tab, under Integration Settings:

  1. Set Integration to Custom.
  2. Choose your Templating Logic (see below).
  3. Configure the AB Test Configuration — for custom integrations we recommend AB Test Within JustAI (internal splitting) unless you already have your own experimentation system. See Template Configuration for the tradeoffs.

Most copy needs personalization: “Hi Alice” instead of “Hi there”. To make that work, variants are authored with placeholders — markers in the text that get replaced with real values (a first name, a plan type, a discount amount) before the message is sent. The Templating Logic setting controls which placeholder syntax JustAI uses when writing your variants, and — just as importantly — where the placeholders get filled in: by JustAI at request time, or by your system after the response comes back.

Liquid is a widely used templating language (originally from Shopify, also used by Customer.io and Braze). Placeholders are named variables in double curly braces, and the language supports conditional logic:

{% if first_name %}Hi {{ first_name }},{% else %}Hi there,{% endif %}
your {{ plan_type }} plan is ready.

With Liquid, JustAI renders the copy for you. Pass the values in the fields parameter of your Generate request:

{
"template_id": "welcome-email",
"user_id": "user_123",
"fields": {
"first_name": "Alice",
"plan_type": "premium"
}
}

The response contains the final, ready-to-send text: "Hi Alice, your premium plan is ready." If a field is missing, the variant’s if/else fallback handles it gracefully ("Hi there, ...").

Choose Liquid if your system has the personalization values available at the time it calls the Generate API. This is the recommended default: you get named, readable placeholders, built-in fallbacks for missing values, and a response you can send as-is with no further processing.

Sprintf uses numbered, positional placeholders — the %1$s-style format specifiers supported by printf-style formatters such as sprintf in PHP, String.format in Java, and POSIX printf in C:

Hi %1$s, your %2$s plan is ready.

With Sprintf, JustAI does not render the copy. The response returns the text with the placeholders intact, and your system substitutes the values using its own formatter. Make sure your formatter supports the numbered %1$s syntax — for example, Python’s % operator does not, so Python clients should convert the placeholders first (e.g. %1$s{0} and render with str.format).

Choose Sprintf if your system renders the copy itself — because the personalization values only exist inside your delivery pipeline (so you can’t pass them to the Generate API), or because your stack has no Liquid implementation to render with (e.g. PHP) — or if you already render printf-style strings, for example via a localization or message-catalog system.

LiquidSprintf
Placeholder styleNamed: {{ first_name }}Positional: %1$s
Who fills in the valuesJustAI, from the fields in your Generate requestYour system, after receiving the response
Missing-value fallbacksBuilt in ({% if %}...{% else %})None — handle defaults in your code
RequirementField values must be available when you call the APIYour delivery code must format the string
Best forMost integrations (recommended default)Rendering the copy yourself: values only exist at send time, no Liquid library for your stack, or existing printf-style rendering

The placeholders available to your variants come from the fields defined in your template’s metadata (name plus a description of what the value contains). The AI only uses fields you’ve defined, and treats them as nullable. Fields are set up with the JustAI team during template creation — reach out if you need to add or change them.

To measure performance, pass a stable tracking_id in each Generate request and use the same ID when reporting downstream events. If you don’t provide one, JustAI generates a UUID and returns it in the response — persist it so your events can be joined. We’ll work with your engineering team to pick an ID that matches your event model; see the Generate API for details.