> ## Documentation Index
> Fetch the complete documentation index at: https://docs.peeker.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Create a bundle, check domains, place an order, and listen for webhooks.

The standard partner flow starts with a sandbox key (`pk_test_…`), checks whether the domains are usable, imports any domains the customer already owns, places the order, and listens for webhooks. Sandbox orders complete quickly and never bill.

<Snippet file="responsibility-split.mdx" />

## Real partner smoke test

Use this three-call sequence first when you are wiring the API from your own app:

1. `POST /domains/availability` - confirm the domains are valid and usable.
2. `POST /domains/import` - attach customer-owned domains to your partner inventory.
3. `POST /orders` - create or reuse the customer by email and start provisioning.

That sequence is what Peeker's Partner API E2E suite runs before it exercises the rest of the endpoint matrix. Create bundles when you want reusable order templates; for the first smoke test, a custom order with `google_licenses` or `microsoft_licenses` is usually faster.

## Steps in detail

<AccordionGroup>
  <Accordion title="1. Create your bundles" defaultOpen>
    A bundle is a saved order size. Send `name` and `monthly_sending_volume`; optionally add `google_percent` and `microsoft_percent`. Bundles default to weekday-only sending (`send_on_weekends: false`) and 2 Google inboxes/domain. Use the returned `bun_…` ID on orders. The response also tells you how many Google and Microsoft domains the customer must pick.

    ```bash cURL theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
    curl -X POST "https://api.peeker.ai/partner/v1/bundles" \
      -H "Authorization: Bearer pk_test_<your-key>" \
      -H "Content-Type: application/json" \
      --data '
    {
      "name": "Starter - 25k emails/month",
      "monthly_sending_volume": 25000,
      "send_on_weekends": false,
      "google_inboxes_per_domain": 2
    }'
    ```

    ```json 201 Created theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
    {
    	"data": {
    		"id": "bun_01HZX0BU1A2B3C4D5E6F7G8H",
    		"name": "Starter - 25k emails/month",
    		"monthly_sending_volume": 25000,
    		"google_percent": null,
    		"microsoft_percent": null,
    		"send_on_weekends": false,
    		"google_inboxes_per_domain": 2,
    		"effective": {
    			"google_percent": 50,
    			"microsoft_percent": 50
    		},
    		"required_domains": {
    			"google": 15,
    			"microsoft": 4,
    			"total": 19
    		},
    		"status": "active",
    		"created_at": "2026-05-08T12:00:00Z"
    	}
    }
    ```
  </Accordion>

  <Accordion title="2. Check domain availability">
    Generate domain candidates yourself, or let the customer search. Send up to 50 per call. Available rows include price, renewal price, and `usable_for`; unavailable rows include a `reason`.

    ```bash cURL theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
    curl -X POST "https://api.peeker.ai/partner/v1/domains/availability" \
      -H "Authorization: Bearer pk_test_<your-key>" \
      -H "Content-Type: application/json" \
      --data '
    {
      "domains": [
        "acme-mail.com",
        "team-acme.com"
      ]
    }'
    ```

    ```json 200 OK theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
    {
    	"data": {
    		"domains": [
    			{
    				"domain": "acme-mail.com",
    				"available": true,
    				"price_cents": 1300,
    				"renewal_price_cents": 1500,
    				"currency": "usd",
    				"usable_for": ["google", "microsoft"]
    			},
    			{
    				"domain": "team-acme.com",
    				"available": true,
    				"price_cents": 1300,
    				"renewal_price_cents": 1500,
    				"currency": "usd",
    				"usable_for": ["google"]
    			}
    		]
    	}
    }
    ```

    <Warning>
      Microsoft domains must include `"microsoft"` in `usable_for`. Match the bundle's `required_domains.microsoft` count before checkout. Filter or flag Google-only rows when the customer still needs Microsoft-capable domains.
    </Warning>
  </Accordion>

  <Accordion title="3. Submit the order">
    `POST /orders` provisions everything in one call. You pass:

    * **`bundle_id`** - the bundle from step 1; resolves the license mix.
    * **`user`** - an email to create/reuse, or an existing `usr_…` user ID.
    * **`sequencer`** - Smartlead routing plus the login credentials Peeker uses internally for provider submission.
    * **`forwarding_url`** - the default redirect for every domain in the order.
    * **`domains`** - the available domains you picked, selected to satisfy the bundle's Microsoft split.
    * **`personas`** - names and required `profile_picture_url` keys used to generate inbox names.

    Smartlead orders require both `sequencer.login_email` and `sequencer.login_password`; a Smartlead client ID or API key alone is not enough for Peeker to submit the provider work.

    Re-sending the exact same body returns the original order - no second charge, no duplicate provisioning. Orders dedupe for 24 hours.

    ```bash cURL theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
    curl -X POST "https://api.peeker.ai/partner/v1/orders" \
      -H "Authorization: Bearer pk_test_<your-key>" \
      -H "Content-Type: application/json" \
      --data '
    {
      "user": "alex@acme.com",
      "bundle_id": "bun_01HZX0BU…",
      "sequencer": {
        "provider": "smartlead",
        "client_id": 366903,
        "login_email": "peeker@yourcompany.com",
        "login_password": "<your-dedicated-login>"
      },
      "forwarding_url": "https://acme.com",
      "domains": [
        "acme-mail.com",
        "team-acme.com"
      ],
      "personas": [
        {
          "first_name": "Alex",
          "last_name": "Rivera",
          "profile_picture_url": ""
        },
        {
          "first_name": "Sam",
          "last_name": "Lee",
          "profile_picture_url": ""
        }
      ]
    }'
    ```

    ```json 200 OK theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
    {
    	"data": {
    		"id": "ord_01HZX0OR1A2B3C4D5E6F7G8H",
    		"user_id": "usr_01HZX0C6Z3K4M5N6P7Q8R9S0",
    		"email": "alex@acme.com",
    		"bundle_id": "bun_01HZX0BU…",
    		"status": "in_progress",
    		"domain_count": 2,
    		"costs": {
    			"total_cents": 6800,
    			"currency": "usd"
    		},
    		"created_at": "2026-05-08T12:00:00Z"
    	}
    }
    ```
  </Accordion>

  <Accordion title="4. Listen for the webhook">
    Configure your endpoint in the [Partner portal → Webhooks](https://app.peeker.com/partner/webhooks) **before** placing the order. Events fire in this sequence:

    ```
    order.in_progress  →  domain.connected (one per domain)  →  order.completed
    ```

    The `order.completed` payload is the full order. [Verify the signature](/webhooks#verify-the-signature) before trusting any payload.

    ```json Webhook · order.completed theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
    {
    	"id": "evt_01HZX0EV2A2B3C4D5E6F7G8H",
    	"type": "order.completed",
    	"created_at": "2026-05-08T12:14:33Z",
    	"data": {
    		"id": "ord_01HZX0OR1A2B3C4D5E6F7G8H",
    		"status": "completed",
    		"domain_count": 2
    	}
    }
    ```

    <Note>
      Live orders return `order.in_progress` immediately. Google and Microsoft orders typically complete within 24 hours - Google can take up to 48 hours when domains need to run through Peeker's recovery flow. Sandbox completes in seconds.
    </Note>
  </Accordion>
</AccordionGroup>

## What's next

<CardGroup cols={2}>
  <Card title="Importing domains & ordering" href="/guides/importing-domains">
    The separate flow for domains the customer already owns - import, not availability check.
  </Card>

  <Card title="Buying domains & ordering" href="/guides/buying-domains">
    More detail on the registrar-sourced order path.
  </Card>

  <Card title="Best practices" href="/best-practices">
    Rate limits, errors, paging, idempotency, pending actions.
  </Card>
</CardGroup>
