> ## 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.

# Connect a provider and place orders

> Connect a reusable provider workspace, then send orders to it.

Connect each provider workspace once with `POST /workspaces`. Use its Peeker
`workspace_id` for every later order.

Workspace creation does not use an `Idempotency-Key`. Orders do.

## Connect a workspace

Credentials are stored and never returned. A successful request returns a
Peeker ID that starts with `wrk_`.

| Provider   | Send when connecting                                          |
| ---------- | ------------------------------------------------------------- |
| EmailBison | `api_url` and a workspace or user `api_key`                   |
| Instantly  | `api_key`                                                     |
| Smartlead  | `label`, main `api_key`, and an optional login pair           |
| PlusVibe   | `api_key`, remote `workspace_id`, and the provider login pair |

<Warning>
  EmailBison requires a workspace or user API key. A super-admin key returns `422
    	emailbison_super_admin_key`.
</Warning>

<Note>
  `credentials.workspace_id` is PlusVibe's own ID. The `workspace_id` used in orders is always the
  Peeker `wrk_...` ID returned by this API.
</Note>

<Tabs>
  <Tab title="Smartlead">
    ```json theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
    {
    	"provider": "smartlead",
    	"label": "Agency Smartlead",
    	"credentials": {
    		"api_key": "<smartlead-main-api-key>",
    		"login_email": "automation@agency.com",
    		"login_password": "<smartlead-login-password>"
    	}
    }
    ```

    `label` and the main API key are required. The login email and password are
    optional, but must be sent together. Do not send `client_id` or `customer` when
    connecting Smartlead.

    The login pair is not part of an order. Smartlead Google orders do not need it.
    Smartlead Microsoft or mixed orders and pre-warmed pool attach do. If one of
    those requests has no saved pair, Peeker returns
    `422 provider_login_credentials_required` before fulfillment starts. Connect
    the same main workspace again with the pair, then retry the unchanged request.
  </Tab>

  <Tab title="EmailBison">
    ```json theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
    {
    	"provider": "emailbison",
    	"credentials": {
    		"api_url": "https://dedi.emailbison.com",
    		"api_key": "<emailbison-workspace-api-key>"
    	}
    }
    ```
  </Tab>

  <Tab title="Instantly">
    ```json theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
    {
    	"provider": "instantly",
    	"credentials": {
    		"api_key": "<instantly-api-key>"
    	}
    }
    ```
  </Tab>

  <Tab title="PlusVibe">
    ```json theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
    {
    	"provider": "plusvibe",
    	"credentials": {
    		"api_key": "<plusvibe-api-key>",
    		"workspace_id": "692577ed8543f416f83ad252",
    		"login_email": "automation@agency.com",
    		"login_password": "<plusvibe-login-password>"
    	}
    }
    ```
  </Tab>
</Tabs>

A new connection returns `201`. Connecting the same provider workspace again
returns `200` with the same `workspace_id`. Different credentials for an
existing provider identity return `409 workspace_credentials_conflict`.

## List connected workspaces

`GET /workspaces` lists both:

* Workspaces connected through the Partner API.
* Regular Peeker workspaces that an owner or admin enabled for Partner API use.

For Smartlead, the list shows the reusable main workspace. Internal client
destinations created by orders do not appear as separate workspaces.

Credentials are never included in list or detail responses.

## Send a Smartlead order

Every order destination has three simple routing fields:

* `provider`: `smartlead`
* `workspace_id`: the main Peeker workspace from `POST /workspaces`
* `client_id`: optional Smartlead client ID

Omit `client_id` to send to the Smartlead main workspace:

```json theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
{
	"destination": {
		"provider": "smartlead",
		"workspace_id": "wrk_01HZX0SK1A2B3C4D5E6F7G8H"
	}
}
```

Include it to send to one client workspace:

```json theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
{
	"destination": {
		"provider": "smartlead",
		"workspace_id": "wrk_01HZX0SK1A2B3C4D5E6F7G8H",
		"client_id": "366903"
	}
}
```

The order always keeps the submitted main `workspace_id` in its public
response. Peeker resolves the client destination behind that ID.

## Place the order

```bash theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
curl --request POST \
  --url https://api.peeker.ai/partner/v1/orders \
  --header 'Authorization: Bearer pk_test_<your-test-key>' \
  --header 'Content-Type: application/json' \
  --header 'Idempotency-Key: <idempotency-key>' \
  --data @order.json
```

```json order.json theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
{
	"destination": {
		"provider": "smartlead",
		"workspace_id": "wrk_01HZX0SK1A2B3C4D5E6F7G8H",
		"client_id": "366903"
	},
	"order": {
		"bundle_id": "bun_01HZX0BK1A2B3C4D5E6F7G8H",
		"domains": ["example.com"],
		"personas": [
			{
				"first_name": "Connor",
				"last_name": "Scale",
				"usernames": ["connor", "connorscale"]
			}
		]
	}
}
```

An order does not accept a Smartlead login, password, email, user, or customer
object. Use either `bundle_id` or custom license fields, never both. On a
custom Google order, set `google_licenses` to `1`, `2`, or `3`. Peeker creates
that many Google inboxes on every submitted domain. For example, 20 domains
with `google_licenses: 2` creates 40 inboxes.

Bundle orders may add `quantity`. If a bundle requires 20 domains,
`"quantity": 2` requires 40 submitted domains and doubles every license count.
Omit `quantity` to order one copy of the bundle. Custom orders do not accept it.

## Choose mailbox usernames

`first_name` and `last_name` are required. `usernames` is optional and contains
only the parts before `@`.

For a Google domain with two inboxes, one supplied username means Peeker keeps
that username and generates the second:

```json theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
{
	"first_name": "Connor",
	"last_name": "Scale",
	"usernames": ["connor"]
}
```

To control both inboxes with one persona, include both usernames in that persona:

```json theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
{
	"first_name": "Connor",
	"last_name": "Scale",
	"usernames": ["connor", "connorscale"]
}
```

If `usernames` is omitted, Peeker generates every username. Supplied usernames
must be unique and cannot exceed the Google inboxes assigned to that persona.

## Normal orders and the pre-warmed pool

`POST /orders` buys and provisions the domains in that order. It never reads,
reserves, attaches, or changes pre-warmed pool inventory.

Only `POST /pool/attach` can assign pre-warmed domains. See
[Assign pre-warmed inboxes](/guides/pre-warmed-pool).

## Retry an order safely

Use one stable `Idempotency-Key` for each order.

| Request                                        | Result                        |
| ---------------------------------------------- | ----------------------------- |
| Same key and same body                         | Returns the original order    |
| Same key and different body                    | `409 idempotency_conflict`    |
| Same key while the first request is processing | `409 idempotency_in_progress` |

The first accepted response can return `created.order: true`. An exact replay
returns `created.order: false` because no new order was created.

For a temporary `500` or `503`, retry the same body with the same key. If a
Smartlead Microsoft order needs a missing login pair, add it through `POST
/workspaces`, then retry the unchanged order with the same key.

See [How orders work](/concepts/orders) for statuses, domain counts, and
cancellations.
