# Conversions

> Capture high-value outcomes as leads, with the real delivery result, idempotency and attribution.

A **conversion** is a high-value outcome: a signup, a demo request, a purchase. Unlike a plain event, a conversion is its own record, attributed to the visitor and enriched into a **lead**. Leads trigger the notification email and your integrations (HubSpot, Hyperflow, Zapier, Brevo).

## Capturing a conversion

```typescript
async function onSubmit(form) {
  orwel.identify({ email: form.email, name: form.name });

  const { success, reason } = await orwel.conversion('demo_request', {
    email: form.email,
    company: form.company,
  });

  if (!success) console.warn('Orwel conversion not delivered:', reason);
  showThanks(); // flip the UI only after the await
}
```

`conversion()` returns `Promise<{ success: boolean; reason?: string }>`. Callers that ignore it keep working, but awaiting it before you unmount the form makes sure the request is not cut off.

## What happens when you call it

<Steps>
  <Step title="Waits for the visitor id">
    The SDK waits up to 5 seconds for the visitor id to resolve, so the conversion can be attached to the visitor and their history. If it never resolves, nothing is sent and the result is `{ success: false, reason: 'visitor_unresolved' }`. Sending it anyway would create a lead with nobody behind it.
  </Step>
  <Step title="Adds a conversionId">
    Each conversion gets a client generated UUID. The server deduplicates on it, so a retried or double fired submit creates one lead, not two.
  </Step>
  <Step title="Attaches attribution">
    The persisted first and last touch UTMs and ad click ids travel with the conversion. See [Attribution](/docs/sdk/attribution).
  </Step>
  <Step title="Sends now and reports back">
    The queue is flushed immediately and the promise resolves with the real outcome.
  </Step>
</Steps>

| Result | Meaning |
| --- | --- |
| `{ success: true }` | The server acknowledged the conversion. |
| `{ success: false, reason: 'visitor_unresolved' }` | The visitor id did not resolve in time. Nothing was sent. |
| `{ success: false, reason: 'delivery_failed' }` | The request was sent but not acknowledged (network, timeout or rejection). |
| `{ success: false, reason: 'error' }` | Something failed inside the SDK. |

If the input is invalid (code not snake_case, properties not an object, invalid email), `conversion()` throws instead.

## Always send an email

The server looks for an email (or a phone) in the conversion properties or in the visitor's traits from `identify()`. Without one, the conversion is stored but the lead cannot be enriched, no notification email is sent, and integrations like HubSpot skip it.

## Conversion codes

Use snake_case codes that describe the outcome: `demo_request`, `newsletter_signup`, `contact_form`, `purchase`. Unlike `track()`, conversion codes are not gated by the workspace catalog, so any valid code is accepted.

If the conversion has a value, pass `amount` and `currency`. They are stored with the lead, and a conversion with a payment signal (`amount`, `plan`, `order_id`, or codes like `purchase`) moves the visitor to the customer stage.

```typescript
await orwel.conversion('purchase', { email, amount: 499, currency: 'USD', plan: 'growth' });
```

## `track` vs `conversion`

| | `track` | `conversion` |
| --- | --- | --- |
| Purpose | Any behavioral signal | High-value outcome, lead |
| Returns | `{ success, eventId }` right away | `Promise<{ success, reason? }>` after the server answers |
| Code must be in the catalog | Yes | No |
| Stored as | `events` | `conversions` and `leads` |
| Triggers | Journeys and features | Lead enrichment, notification email, integrations |

## Testing

Send conversions with the [development key](/docs/guides/dev-mode) while you build: they are stored as test leads with a **Dev** badge, and no email or integration fires. Dev mode shows each one with warnings such as a missing email or missing attribution.

## Next steps

<CardGroup cols={2}>
  <Card title="Attribution" icon="crosshairs" href="/sdk/attribution">
    How leads get their source and campaign.
  </Card>
  <Card title="Troubleshooting" icon="stethoscope" href="/guides/troubleshooting">
    What to do when a conversion fails.
  </Card>
</CardGroup>
