# Scenario 1: a client signs up (/docs/embed/client-signs-up)

A new client fills in **your** sign-up form. In the same request your server creates their Happierleads website, then their first page opens the install screen.

<Tabs items={['Diagram', 'API calls']}>
<Tab value="Diagram">

<EmbedFlow only="signup" />

</Tab>
<Tab value="API calls">

### 1. Your sign-up, exactly as today [#1-your-sign-up-exactly-as-today]

`POST /signup` on your own app: create the user and their company. Your users never get a Happierleads password.

### 2–3. Create their website [#23-create-their-website]

With your master key. The domain may be empty: the install screen asks for it. The answer is `201 { websiteId }`.

<ApiPlayground method="post" path="/admin/websites" tool="" args={`{ "name": "Acme Ltd", "domain": "acme.example" }`} />

### 4. Save the websiteId on YOUR customer [#4-save-the-websiteid-on-your-customer]

Before any other call. It is the only link between your client and their website.

```js
const { websiteId } = await res.json();
await db.companies.update(company.id, { happierleadsWebsiteId: websiteId });
```

### 5–6. Their leads and email accounts [#56-their-leads-and-email-accounts]

<ApiPlayground method="put" path="/admin/websites/set-limits/{websiteId}" tool="" args={`{ "websiteId": "64b7f0a1c2d3e4f5a6b7c8d9", "credits": 500, "emailAccounts": 2 }`} />

### 7–8. Trial until the end date [#78-trial-until-the-end-date]

<ApiPlayground method="put" path="/admin/websites/toggle-limits/{websiteId}" tool="" args={`{ "websiteId": "64b7f0a1c2d3e4f5a6b7c8d9", "trialEnabled": true, "trialExpireDate": "{{days:14}}", "enableWebsiteLimits": true }`} />

When they pay, your billing webhook [switches them to paid](/docs/embed/switch-to-paid).

### 9. Send them to your Leads page [#9-send-them-to-your-leads-page]

An ordinary redirect inside your own app; nothing goes to Happierleads.

```js
res.redirect('/visitors'); // your page with the iframe
```

### 10–14. Your page asks your server for a one-time link [#1014-your-page-asks-your-server-for-a-one-time-link]

Your page calls **your** endpoint. Your server checks the user is signed in, reads `company.happierleadsWebsiteId` from **your** database (never from the request), and asks us for a link with your embed key:

```js title="server.js"
app.get('/api/leads-embed', requireLogin, async (req, res) => {
  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({ websiteId: req.user.company.happierleadsWebsiteId, view: req.query.view || 'auto' }),
  });
  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 }); // works once, 60 seconds
});
```

The call to us, from your server only, with your embed key. Try it on sample data (change `view`, or send another `websiteId` to see the refusal); the **JavaScript** and **Python** tabs have the server code:

<ApiPlayground method="post" path="/v3/embed/sessions" tool="" args={`{ "websiteId": "64b7f0a1c2d3e4f5a6b7c8d9", "view": "auto" }`} />

Every field and `view`: [Open a screen](/docs/embed/open-a-screen).

### 15. The screen loads [#15-the-screen-loads]

```html
<iframe id="hl" title="Website visitors" style="width:100%;height:100%;border:0"></iframe>
<script>
  fetch('/api/leads-embed?view=auto').then((r) => r.json()).then(({ url }) => { document.getElementById('hl').src = url; });
</script>
```

A new client has no pixel yet, so `view: "auto"` opens the install screen: their snippet and a Verify button. More: [Show it in an iframe](/docs/embed/iframe).

</Tab>
</Tabs>

**Next:** [Scenario 2: a client logs in](/docs/embed/client-logs-in).
