Embed Happierleads screens
Open a screen: the one-time link
One endpoint on your server asks for a link every time your page shows an embedded screen.
Add one endpoint to your server. Your page calls it every time it shows a screen; it checks your user is signed in, then asks us for a link with your embed key.
The call
POST /v3/embed/sessions, with Authorization: Bearer $HL_EMBED_KEY.
POST
/v3/embed/sessionsSample data · runs on your server with your embed keyTry:
Request body
Website IdThe client's website, from your database (not needed with scope account).
ViewThe screen to open. auto: install until the pixel works, then leads.
Scopeaccount: the admin view of every website (your own staff only).
curl -X POST "https://rest-admin.happierleads.com/v3/embed/sessions" \ -H "Authorization: Bearer $HL_EMBED_KEY" \ -H "Content-Type: application/json" \ -d '{ "websiteId": "64b7f0a1c2d3e4f5a6b7c8d9", "view": "auto"}'Response
Press Send request to try it with sample data.
The url works once, within 60 seconds. Put it straight into the iframe; never store it, never log it.
| Field | Required | What it is |
|---|---|---|
websiteId | Yes (unless scope is account) | The signed-in user's company website. Always from your database, never from the request. |
view | No, default auto | The screen to open (below). |
scope | No, default website | account opens the admin view of every website of your account: your own staff only. |
user.email | No | Only if you switched on CSV export: the export's file link is emailed there. Without it the Export button is hidden. |
No personal data needed
Send only the website and the screen. We never need your users' names or emails.
Which screen: view
view | Opens |
|---|---|
auto | The install screen until their pixel works, then their leads. Use this by default. |
leads | Their leads |
install | The tracking-pixel install screen: their snippet and a Verify button |
automations · integrations · settings · qualify · engage | An extra screen, only if you ticked it in Embed settings |
One iframe per screen, each behind its own menu item in your app.
Your endpoint
app.get('/api/leads-embed', requireLogin, async (req, res) => {
const staff = req.user.isStaff; // your rule: who may see every website
const view = ['auto', 'leads', 'install'].includes(req.query.view) ? req.query.view : 'auto';
const r = await fetch(`${process.env.HL_API_BASE}/v3/embed/sessions`, {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.HL_EMBED_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify(staff ? { scope: 'account' } : { websiteId: req.user.company.happierleadsWebsiteId, view }),
});
if (!r.ok) return res.status(502).json({ error: 'Could not open this screen' });
res.set('Cache-Control', 'no-store').json({ url: (await r.json()).url });
});- Not signed in:
requireLoginanswers401before anything reaches us. - A company with no website yet (signed up while our API was down): create it on the spot (Create a website), then continue.
- Keep our name out of your route:
/api/leads-embed, not/api/happierleads.
Errors
| Status | Why | What to do |
|---|---|---|
400 | Unknown view, a screen you didn't tick, or a website outside your account | Check the status message |
401 | Wrong or revoked embed key, or embedding is switched off | Check HL_EMBED_KEY and Embed settings |
Next: show it in an iframe.