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

# Assign SmartInfra to Campaigns

> Attach a Multi or Single SmartInfra (dedicated IPs) to many campaigns in a single request

<Note>
  **SmartServers API**: Dedicated IP infrastructure feature. Contact [support@smartlead.ai](mailto:support@smartlead.ai) for access.
</Note>

## Overview

Attaches your dedicated sending infrastructure to the campaigns you list, so a dedicated IP can be rolled out across a large batch of campaigns in one call instead of one campaign at a time in the dashboard.

Both kinds of infrastructure on the SmartInfra page are supported, and you pick between them by which ID you send:

| Dashboard tab     | Send        | What gets attached                                                     |
| ----------------- | ----------- | ---------------------------------------------------------------------- |
| Multi SmartInfra  | `infra_id`  | Every dedicated IP in that SmartInfra, with auto-rotation between them |
| Single SmartInfra | `server_id` | That one dedicated IP                                                  |

**Key Features**:

* Assigns hundreds of campaigns per request
* Enables sender auto-rotation automatically when the SmartInfra holds more than one server
* Propagates the campaign's client to the SmartInfra and its servers

<Note>
  One SmartInfra can serve as many campaigns as you like — that is the normal way to use it, and there is no limit. The restriction runs the other way: a single campaign can only belong to one Multi SmartInfra, because that SmartInfra determines both the pool of IPs it rotates through and which client owns it. A campaign may instead hold up to four Single SmartInfra servers.
</Note>

<Warning>
  This endpoint only creates new assignments. A campaign that already belongs to a different SmartInfra is rejected with `409`, and a campaign already attached to the SmartInfra you named is rejected with `208` — neither is silently overwritten. To move a campaign between SmartInfras, or to swap a Multi SmartInfra for a Single one, use the SmartInfra page in the dashboard.
</Warning>

<Warning>
  All campaigns in one request must belong to the same client. Because assigning campaigns also transfers client ownership of the SmartInfra and its servers, a request mixing campaigns from two different clients is rejected with `400` and nothing is written. Campaigns that are not assigned to any client can be included freely. If your campaigns span several clients, send one request per client.
</Warning>

<Note>
  Requests are all-or-nothing. Every campaign is validated before anything is written, so a single invalid or already-assigned campaign causes the whole request to fail without assigning any of the others.
</Note>

<Info>
  Neither ID is available from the public API yet. Open the SmartInfra page in the dashboard and read the ID from the URL of the row you want to assign — from the **Multi SmartInfra** tab for `infra_id`, or the **Single SmartInfra** tab for `server_id`.
</Info>

## Query Parameters

<ParamField query="api_key" type="string" required>
  Your SmartLead API key
</ParamField>

## Request Body

Send exactly one of `infra_id` or `server_id`, plus `campaign_ids`.

<ParamField body="infra_id" type="number">
  The Multi SmartInfra to assign, which attaches all of its dedicated IPs. Must belong to the authenticated user. Cannot be combined with `server_id`.
</ParamField>

<ParamField body="server_id" type="number">
  The Single SmartInfra to assign, which attaches that one dedicated IP. Must belong to the authenticated user and must not be part of a Multi SmartInfra — use `infra_id` for those. Cannot be combined with `infra_id`.
</ParamField>

<ParamField body="campaign_ids" type="array">
  Campaign IDs to attach the infrastructure to. Every campaign must belong to the authenticated user.

  Example: `[5614, 5615, 5616]`
</ParamField>

<ParamField body="client_id" type="number">
  Assign the SmartInfra to every campaign belonging to this client instead of naming campaigns individually. When the client has no campaigns yet, the SmartInfra is still reserved for that client. Supported with `infra_id` only; supply `campaign_ids` when using `server_id`.
</ParamField>

<RequestExample>
  ```bash cURL theme={null}
  # Multi SmartInfra — attaches every dedicated IP in the SmartInfra
  curl -X POST "https://smartservers.smartlead.ai/api/v1/smart-infra/mapping?api_key=YOUR_KEY" \
    -H "Content-Type: application/json" \
    -d '{"infra_id": 42, "campaign_ids": [5614, 5615, 5616]}'

  # Single SmartInfra — attaches one dedicated IP
  curl -X POST "https://smartservers.smartlead.ai/api/v1/smart-infra/mapping?api_key=YOUR_KEY" \
    -H "Content-Type: application/json" \
    -d '{"server_id": 907, "campaign_ids": [5614, 5615, 5616]}'
  ```

  ```python Python theme={null}
  import requests

  API_KEY = "YOUR_API_KEY"
  BASE_URL = "https://smartservers.smartlead.ai"

  payload = {
      "infra_id": 42,
      "campaign_ids": [5614, 5615, 5616]
  }

  response = requests.post(
      f"{BASE_URL}/api/v1/smart-infra/mapping",
      params={"api_key": API_KEY},
      json=payload
  )

  print(response.status_code, response.json())
  ```

  ```javascript JavaScript theme={null}
  const API_KEY = 'YOUR_API_KEY';
  const BASE_URL = 'https://smartservers.smartlead.ai';

  const response = await fetch(
    `${BASE_URL}/api/v1/smart-infra/mapping?api_key=${API_KEY}`,
    {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        infra_id: 42,
        campaign_ids: [5614, 5615, 5616]
      })
    }
  );

  console.log(response.status, await response.json());
  ```
</RequestExample>

## Response Codes

<ResponseField name="201" type="Created">
  All campaigns were assigned to the SmartInfra
</ResponseField>

<ResponseField name="200" type="Success">
  `client_id` was supplied and the SmartInfra is now reserved for that client, which currently has no campaigns to assign
</ResponseField>

<ResponseField name="208" type="Already Reported">
  At least one campaign is already assigned to this SmartInfra
</ResponseField>

<ResponseField name="400" type="Bad Request">
  Invalid request body, neither or both of `infra_id` and `server_id` were sent, the SmartInfra has no servers, the `server_id` belongs to a Multi SmartInfra, or the SmartInfra belongs to a client that the listed campaigns do not
</ResponseField>

<ResponseField name="401" type="Unauthorized">
  Invalid or missing API key. Check your authentication.
</ResponseField>

<ResponseField name="403" type="Forbidden">
  The SmartInfra, one of its servers, or the client does not belong to you
</ResponseField>

<ResponseField name="404" type="Not Found">
  No SmartInfra exists for the given `infra_id`, no server exists for the given `server_id`, or at least one campaign does not exist. Campaigns belonging to another account are reported the same way.
</ResponseField>

<ResponseField name="409" type="Conflict">
  At least one campaign is already assigned to a different SmartInfra, or would exceed the limit of four Single SmartInfra servers
</ResponseField>

<ResponseField name="500" type="Internal Server Error">
  Server error occurred. Please try again or contact support if the issue persists.
</ResponseField>

<ResponseExample>
  ```json 201 - Created theme={null}
  {
    "statusCode": 201,
    "success": true,
    "message": "Smart infra campaign mapping created successfully"
  }
  ```

  ```json 200 - Client Reserved theme={null}
  {
    "statusCode": 200,
    "success": false,
    "message": "Client mapped with the server(s)"
  }
  ```

  ```json 208 - Already Assigned theme={null}
  {
    "statusCode": 208,
    "success": false,
    "message": "Method Not Allowed",
    "error": "Smart server campaign mapping is already exists"
  }
  ```

  ```json 401 - Unauthorized theme={null}
  {
    "statusCode": 401,
    "success": false,
    "message": "Unauthorized",
    "error": "Invalid API Key"
  }
  ```

  ```json 409 - Conflict theme={null}
  {
    "statusCode": 409,
    "success": false,
    "message": "Method Not Allowed",
    "error": "Campaign is already mapped to another infra. One campaign can only be mapped to one infra (max 4 servers)."
  }
  ```
</ResponseExample>

## Best Practices

<Tip>
  **Assign Before Launch**: Attach the SmartInfra while campaigns are still drafts, so the dedicated IP is in place before the first email sends
</Tip>

<Tip>
  **Send Only Unassigned Campaigns**: The request is rejected as a whole if any campaign is already assigned, so filter your list down to campaigns that need the SmartInfra
</Tip>

<Tip>
  **Batch In Chunks**: Split very large rollouts into batches of a few hundred campaigns to keep each request comfortably inside the request timeout
</Tip>

## Validation Rules

A campaign can hold either one Multi SmartInfra or up to four Single SmartInfra servers. Any SmartInfra can serve any number of campaigns. Every campaign you list must belong to your account.

Requests are validated in full before anything is written, so a rejected request leaves no partial assignment behind.

## Implementation Details

One mapping is created per dedicated IP for each campaign, so a Multi SmartInfra holding three IPs and a list of ten campaigns produces thirty mappings, while a Single SmartInfra produces ten. `auto_rotate_servers` is turned on for those campaigns whenever the SmartInfra holds more than one IP, letting SmartLead rotate sends across them.

When a listed campaign belongs to a client, that client is also applied to the SmartInfra and to each of its servers.

**Response Format**: object

## Related Endpoints

* [Get All Campaigns](/api-reference/campaigns/get-all)
* [Get Campaign by ID](/api-reference/campaigns/get-by-id)
* [Add Email Accounts to Campaign](/api-reference/campaigns/add-email-accounts)
