What you build and what Omneo provides
Invites has to be called as the referrer, with a token scoped to that one profile. You mint those tokens yourself. Everything else that authenticates you comes from Omneo.
Health checks need no authentication:
GET /invites/api/health returns 200, and GET /invites/api/version returns the service version.
Flow
The refer step
The token exchange needs your Omneo API token, so this chain runs on a server, never in the browser. Any backend you control works. On Shopify, a Shopify App Proxy is the natural home because Shopify tells you which customer is signed in. See Shopify authentication for how the Omneo Shopify extension handles the same problem.1
Identify the referrer server-side
Establish which profile is signed in and what their ID is on your platform. Never trust a customer ID sent from the browser.On a Shopify App Proxy, verify the
signature query parameter against your app’s shared secret before reading logged_in_customer_id, and reject the request if it is empty.2
Exchange the customer ID for an Omneo ID token
Mint a profile-scoped token by external identity. With the Omneo SDK:The same call as raw HTTP:
id is your platform’s customer ID as a string. Tokens are short-lived and exp is a Unix timestamp. Cache the token per referrer until shortly before it expires. Do not mint one per keystroke.A profile that was created on your platform seconds ago may not have synced to Omneo yet. In that window the create call in the next step returns 401. Treat a fresh token followed by 401 as “not synced yet” and show a try-again-shortly message instead of retrying in a loop.3
Create the invite as the referrer
200 Omneo has already sent the email. You send nothing. The response does not echo recipient_first_name or public_message.4
Handle the response
Log the returned invite
id against your customer ID. Omneo support can look up any invite by ID when a referrer reports that a friend did not receive the email.Showing invites remaining
meta.remainingis how many invites the referrer can still send.nullmeans unlimited.meta.eligible_definition.in_rangeisfalsewhen the campaign window is closed. Creating an invite will return400.- “Friends who joined” are the entries in
datawithstatusequal toACCEPTED. datais ordered oldest first byinvited_at.
Lighter alternative: send referrers to Profile Portal
If you would rather not run a backend, link your “Refer a friend” button tohttps://[portal]/refer. The referrer signs in to Profile Portal and sends invites from there. Quota, email, and success messaging are built in. You lose the on-site experience but write no code. Link to /refer without query parameters.
The invitee’s journey
Omneo owns this part. It is described here so you can design around it.- Omneo emails the invitee using your brand’s template. The call to action links to
https://[portal]/join?invite_id={inviteId}&email={recipientEmail}. The join page pre-fillsemail, and alsofirst_name,last_name, andmobile_phoneif present in the query string. - The invitee completes the join form. Profile Portal creates their profile and, server-side, tells Invites the invitation was accepted. Invites checks the email matches, writes the custom attribute
invites.invited_by(the referrer’s profile ID) to the new profile, and marks the inviteACCEPTED. - Other pending invites to that same address, from other referrers, are marked
DECLINED. First accept wins. - Your Reactions fire on the referral. See Referral incentives.
Accepting on your own site
If invitees create their account on your website rather than in Profile Portal, your backend performs the accept using a machine token Omneo issues for server-to-server calls.invite_id from your sign-up page URL, keep it through the form, and call accept only after the customer account exists. recipient_email must equal the invited address exactly. recipient_external_id is the new customer’s ID on your platform. Invites finds or creates the Omneo profile by that ID first, then by email, so it converges with your platform-to-Omneo sync either way.
State errors from validate and accept are listed in Error responses.
Things not to do
- Do not call
POST /api/v1/invites(without/me/). It exists for a legacy integration and does not send the email, enforce the referrer’s quota, or honour opt-outs. Use/api/v1/me/invites. - Do not put the Omneo API token, the machine token, or an ID token in browser JavaScript. All three stay on your server.
- Do not add query parameters to
/referlinks. Link to the portal refer page as-is.
Security checklist
- The Omneo API token and machine token live only in server configuration or a secret manager.
- Every request to your handler is authenticated server-side before a customer ID is trusted. On Shopify, verify the App Proxy
signaturebefore readinglogged_in_customer_id. - ID tokens are minted only for the profile proven to be signed in. Never accept a customer ID from the request body.
- Nothing on your site links to
/referwith query parameters. - Your own email and marketing tooling does not pre-fetch links in Omneo’s invitation emails. The opt-out link is a plain
GETwith no confirmation step. - The referral form is rate-limited per profile. The API’s 60 requests per minute is a backstop, not a UX limit.
- Each returned invite
idis logged with your customer ID so support can trace it.
Go-live checklist
Before you start, Omneo confirms: the Invites service is live for your tenant (GET /invites/api/health returns 200), your Omneo API token is issued, a test profile exists on your platform and in Omneo, and you have a staging host and a disposable inbox for the invitee.
- Sign in as the test profile on your website and submit the referral form with the disposable inbox address.
- Expect
200and an inviteid.GET /api/v1/me/invitesshows it asPENDINGwithmeta.remainingdecremented, ornullif unlimited. - The disposable inbox receives the email. Its call to action links to
https://[portal]/join?invite_id=...&email=.... - Complete the join form.
GET /api/v1/me/invitesas the referrer now shows the invite asACCEPTED. - Omneo confirms the new profile carries
invites.invited_byequal to the referrer’ssource_omneo_id, and that the referral Reaction fired. - Negative checks: submit the same address again and expect a second
PENDINGinvite, or your own de-duplication. Submit an address Omneo has blocked for the test and expect403. Exhaust the quota on a definition with a small maximum and expect400.