> This page is for Developers.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.emnify.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.emnify.com/_mcp/server.

> Create virtual device representations (endpoints) with service profiles, tariff profiles, and SIM assignments via the API.

After [registering SIMs](/developers/connectivity/register-sims), you need to create a virtual representation of the device associated with the SIM.
In the emnify REST API, this is called an *endpoint*.

You can create one endpoint using the [Create an Endpoint](/developers/api/endpoint/create-endpoint) API call, or multiple endpoints at once (up to 2,000) using the [Bulk Create Endpoint](/developers/api/endpoint/bulk-create-endpoint) API call.

> **Note**
>
> This guide uses the [Postman API platform](https://quickstarts.postman.com/) for example purposes.
> Each time you use the emnify REST API, you must authenticate in Postman.
>
> For more information, see [How to use the REST API via Postman](https://www.emnify.com/developer-blog/postman-emnify-api) on the emnify Developer Blog.

Alternatively, you can create devices via the emnify Portal.
For step-by-step instructions, see [Create a device](/quickstart/create-device) in the Portal documentation.

## Individual endpoint

> **Note**
>
> Execute this operation sequentially - wait for each request to complete before starting the next.
> For bulk operations, see [Multiple endpoints](#multiple-endpoints).

To create a new request in Postman, click **+New** in the upper left corner.
Name the request `Endpoint creation` and add it to a new collection called `Endpoints`.

Then follow these steps to set up your request:

Select the **POST** HTTP method.

Set the request URL as `https://cdn.emnify.net/api/v1/endpoint`

Navigate to the **Headers** tab.
Insert `Content-Type` and `Authorization` as **Keys** and add the respective **Values** `application/json` and `Bearer TOKEN`.
Replace `TOKEN` with your [`auth_token`](/developers/auth/application-tokens) and make sure there's a non-breaking space between `Bearer` and the token value.

Go to the **Body** tab and select **raw**.
Make sure the format is set to **JSON**.
Then, specify the endpoint details.

To get your endpoint online immediately, set the endpoint status to **Enabled** and activate the SIM card:

```json {4, 14}
{
  "name": "ENDPOINT_NAME",
  "status": {
    "id": 0
  },
  "service_profile": {
    "id": 123
  },
  "tariff_profile": {
    "id": 456
  },
  "sim": {
    "id": 123456,
    "activate": true
  }
}
```

Keep in mind that a monthly cost is charged for each activated SIM card, even if the endpoint status is set to **Disabled**.

If you don't plan on using the endpoint right away, set the endpoint status to **Disabled** and don't activate the SIM:

```json {4, 14}
{
  "name": "ENDPOINT_NAME",
  "status": {
    "id": 1
  },
  "service_profile": {
    "id": 123
  },
  "tariff_profile": {
    "id": 456
  },
  "sim": {
    "id": 567890,
    "activate": false
  }
}
```

> **Info**
>
> When a `sim` object is provided, the SIM is activated by default. To assign the SIM without activating it, you must explicitly set `activate` to `false`. Omitting the property activates the SIM.

To complete the request, click **Send**.

> **Success**
>
> A `200 OK` response status indicates the successful creation of the endpoint.
>
> #### Example response body
>
> ```json maxLines=10
> {
>   "created": "2026-01-26T09:56:39.741+0000",
>   "last_updated": "2026-01-26T09:56:39.741+0000",
>   "name": "ENDPOINT_NAME",
>   "ip_address": "198.51.100.235",
>   "id": 12345678,
>   "tag_assignments": [],
>   "sim": {
>     "id": 567890,
>     "iccid": "8988303000008013931",
>     "iccid_with_luhn": "89883030000080139311",
>     "imsi": "295050901198207",
>     "msisdn": "423663921003632",
>     "sim_profile_type": {
>       "id": 1
>     }
>   },
>   "ip_address_space": {
>     "id": 1234
>   }
> }
> ```

## Multiple endpoints

The [Bulk Create Endpoint](/developers/api/endpoint/bulk-create-endpoint) API call lets you:

* Create up to 2,000 endpoints in a single request
* Process multiple endpoints safely without sequential execution constraints
* Save time compared to creating endpoints individually

> **Info**
>
> If you previously used Postman's Runner to create endpoints sequentially (calling `/api/v1/endpoint` repeatedly), we recommend migrating to the bulk endpoint for better efficiency and reliability.

### Choose your workflow

Choose the workflow that matches your needs:

* Comfortable with JSON? → Use [Workflow A: Send JSON directly](#workflow-a-send-json-directly)
* Have data in spreadsheet, small dataset (fewer than 50 endpoints)? → Use [Workflow B: Convert CSV to JSON manually](#workflow-b-convert-csv-to-json-manually)
* Have data in spreadsheet, large dataset (50+ endpoints)? → Use [Workflow C: Automate CSV to JSON with Postman Runner](#workflow-c-automate-csv-to-json-with-postman-runner)
* Need to create more than 2,000 endpoints? → See [Create more than 2,000 endpoints](#create-more-than-2000-endpoints)

### Workflow A: Send JSON directly

> **Note**
>
> **Best for**: Developers comfortable working directly with JSON.

#### Set up the bulk request in Postman

> **Warning**
>
> Check the [rate limits](/developers/api-guidelines/rate-limits) before executing bulk operations.

To create a new request in Postman, click **+New** in the upper left corner.
Name the request `Bulk endpoint creation` and add it to your `Endpoints` collection.

Then follow these steps:

Select the **POST** HTTP method.

Set the request URL as `https://cdn.emnify.net/api/v2/endpoint/multi`

Navigate to the **Headers** tab and set:

* `Content-Type`: `application/json`
* `Authorization`: `Bearer TOKEN` (replace `TOKEN` with your [auth token](/developers/auth/application-tokens))

Go to the **Body** tab and select **raw**.
Make sure the format is set to **JSON**.

Structure your request body as described in the following section.

#### Structure the request body

The bulk endpoint uses a different structure than individual endpoint creation.
Shared properties (service profile, tariff profile, status) are defined once at the root level, and variable endpoint details go in the `endpoints` array.
Properties within the `endpoints` array can be adjusted per endpoint.
For example, you can create one endpoint with a SIM attached and one without, have different tags for each endpoint, etc.

To get your endpoints online immediately, set the endpoint status to **Enabled** (`"id": 0`) and activate the SIMs:

```json {9, 18, 27}
{
  "service_profile": {
    "id": 123
  },
  "tariff_profile": {
    "id": 456
  },
  "status": {
    "id": 0
  },
  "endpoints": [
    {
      "name": "ENDPOINT_NAME_1",
      "tag_assignments": [1, 2],
      "imei": "123456789012345",
      "sim": {
        "id": 3595575,
        "activate": true
      }
    },
    {
      "name": "ENDPOINT_NAME_2",
      "tag_assignments": [1, 2],
      "imei": "123456789012346",
      "sim": {
        "id": 3595576,
        "activate": true
      }
    }
  ]
}
```

> **Info**
>
> `tag_assignments` takes the IDs of tags that already exist in your organization.
> Unlike the deprecated `tags` property, it doesn't create missing tags, and you can't send both properties in the same request.

Keep in mind that a monthly cost is charged for each activated SIM card, even if the endpoint status is set to **Disabled**.

> **Tip**
>
> You can also create endpoints in [factory test mode](/developers/connectivity/factory-test-mode) to avoid incurring costs during testing.

If you don't plan on using the endpoints right away, set the endpoint status to **Disabled** (`"id": 1`) and don't activate the SIMs:

```json {9, 16, 23}
{
  "service_profile": {
    "id": 123
  },
  "tariff_profile": {
    "id": 456
  },
  "status": {
    "id": 1
  },
  "endpoints": [
    {
      "name": "Endpoint-001",
      "sim": {
        "id": 3595575,
        "activate": false
      }
    },
    {
      "name": "Endpoint-002",
      "sim": {
        "id": 3595576,
        "activate": false
      }
    }
  ]
}
```

> **Info**
>
> When a `sim` object is provided, the SIM is activated by default. To assign a SIM without activating it, you must explicitly set `activate` to `false`. Omitting the property activates the SIM.

> **Tip**
>
> To make your request reusable, use [Postman collection variables](https://learning.postman.com/docs/sending-requests/variables/variables/#defining-collection-variables) for shared properties like `service_profile_id` and `tariff_profile_id`.

#### Execute the bulk request

Verify your JSON structure:

* Shared properties are at the root level
* Each endpoint in the `endpoints` array has a unique `sim.id`
* If provided, `imei` values are unique across all endpoints

> **Info**
>
> The bulk endpoint enforces uniqueness for `sim.id` and `imei` values.
> If any duplicates are found, the entire bulk request fails.
> Review the error response to identify and correct the duplicate values before retrying.

Click **Send** to execute the request.

> **Success**
>
> A `201 CREATED` response indicates successful creation of all endpoints.
> The response body contains an array with details for each created endpoint.

### Workflow B: Convert CSV to JSON manually

> **Note**
>
> **Best for**: Users with endpoint data in spreadsheets who have a small dataset (fewer than 20 endpoints) and prefer manual conversion.

#### Organize data in a CSV file

To organize your data in a CSV file, create a table in a spreadsheet software (like Excel or Google Sheets) that includes the necessary endpoint details:

In the first row, insert the properties as columns.

**Shared properties** (same for all endpoints in this batch):

* `service_profile_id`
* `tariff_profile_id`
* `status_id` (0 = Enabled, 1 = Disabled)

**Variable properties** (unique to each endpoint):

* `name`
* `tag_assignments`
* `imei`
* `imei_lock`
* `sim`
* `ip_address`

> **Info**
>
> Optional properties like `tag_assignments` and `imei` can be left empty if not needed.
> See the [API reference](/developers/api/endpoint/bulk-create-endpoint) for requirements and property details.

Fill in the corresponding data for your endpoints.
Each row represents one endpoint.
Ensure shared property values are consistent across all rows.

Save it as a CSV file (`.csv`).

> **Info**
>
> You can include up to 2,000 endpoints in a single bulk request.
> If you have more, [split them into multiple CSV files](#create-more-than-2000-endpoints).

#### Map CSV columns to the JSON body

Since the bulk endpoint only accepts JSON, you need to convert your CSV data into the required JSON format.

Open your CSV file

For each row, create an object in the `endpoints` array:

* Map `endpoint_name` to `name`
* Map `sim_id` to `sim.id`
* Map `sim_activate` to `sim.activate`
* Map optional columns like `tag_assignments` and `imei`

Set the shared properties once at the root level using values from your CSV

#### Example mapping

The following example illustrates how to convert a single CSV row into the corresponding JSON structure.

CSV row:

| service\_profile\_id | tariff\_profile\_id | status\_id | endpoint\_name | sim\_id | sim\_activate |
| -------------------- | ------------------- | ---------- | -------------- | ------- | ------------- |
| 123                  | 456                 | 0          | Endpoint-001   | 3595575 | true          |
| 123                  | 456                 | 0          | Endpoint-002   | 3595576 | false         |

Maps to JSON:

```json
{
  "service_profile": { "id": 123 },
  "tariff_profile": { "id": 456 },
  "status": { "id": 0 },
  "endpoints": [
    {
      "name": "Endpoint-001",
      "sim": {
        "id": 3595575,
        "activate": true
      }
    },
    {
      "name": "Endpoint-002",
      "sim": {
        "id": 3595576,
        "activate": false
      }
    }
  ]
}
```

#### Send the request

After manually converting your CSV data to JSON:

1. Set up the bulk request in Postman following [Workflow A: Set up the bulk request](#set-up-the-bulk-request-in-postman)
2. Paste your converted JSON into the request body
3. Verify the JSON structure (ensure unique `sim.id` and `imei` values)
4. Click **Send** to execute the request

> **Success**
>
> A `201 CREATED` response indicates successful creation of all endpoints.

### Workflow C: Automate CSV to JSON with Postman Runner

> **Note**
>
> **Best for**: Users with endpoint data in CSV files and large datasets (20+ endpoints) who want to automate the conversion process.

#### Prepare the CSV file

Organize your CSV file following the structure in [Workflow B: Organize data in a CSV file](#organize-data-in-a-csv-file).
This workflow automates the conversion to JSON using Postman Runner, saving time for large datasets.

#### Create the collector request

To automate CSV to JSON conversion, create two requests in the same collection/folder and run them via **Runner** with a CSV data file.

In Postman, create a new request in the same collection/folder as your bulk request.

Name the request `Bulk CSV — Collect rows`.

Set:

* **Method**: `GET`
* **URL**: `https://postman-echo.com/get`

> **Info**
>
> This is a harmless echo endpoint provided by Postman for testing purposes.
> Its response doesn't matter and it only exists to run the script once per CSV row.

Open the **Tests** tab and paste the following script:

```javascript
// Read the current CSV row for this iteration
const row = pm.iterationData.toObject();

// Load stored endpoints (persisted across iterations)
const endpoints = JSON.parse(pm.collectionVariables.get('bulkEndpoints') || '[]');

// Store shared properties (same for all endpoints in the CSV)
const shared = {
  service_profile: { id: parseInt(row.service_profile_id, 10) },
  tariff_profile:  { id: parseInt(row.tariff_profile_id, 10) },
  status:          { id: parseInt(row.status_id, 10) }
};

// Add this row as one endpoint object
endpoints.push({
  name: row.endpoint_name,
  sim: {
    id: parseInt(row.sim_id, 10),
    activate: row.sim_activate === true || String(row.sim_activate).toLowerCase() === 'true'
  }
});

// Persist state for the next iteration
pm.collectionVariables.set('bulkShared', JSON.stringify(shared));
pm.collectionVariables.set('bulkEndpoints', JSON.stringify(endpoints));

// Add at least one test so Runner displays results
pm.test('Collected one CSV row', function () {
  pm.expect(row.endpoint_name).to.be.ok;
});

// IMPORTANT: Don't loop back to this request, or Runner will never advance iterations
const isLastIteration = (pm.info.iteration === pm.info.iterationCount - 1);

if (isLastIteration) {
  postman.setNextRequest('Bulk endpoint creation');
} else {
  postman.setNextRequest(null);
}
```

> **Info**
>
> This script uses `postman.setNextRequest()` for maximum compatibility.
> Some Postman environments don't expose `pm.execution.setNextRequest()`.

#### Configure the bulk request

Create (or open) your bulk request.

Name the request to match the `setNextRequest` value defined in the collector script.

> **Warning**
>
> The name must match the value used in the collector script.
> For example, the collector script in this guide defines `postman.setNextRequest('Bulk endpoint creation')`, meaning the request name must be `Bulk endpoint creation`.

Set:

* **Method**: `POST`
* **URL**: `https://cdn.emnify.net/api/v2/endpoint/multi`

In **Headers**, set:

* Key: `Content-Type` | Value: `application/json`
* Key: `Authorization` | Value: `Bearer TOKEN` (replace `TOKEN` with your [`auth_token`](/developers/auth/application-tokens))

In **Body**:

1. Select **raw**
2. Set the format to **JSON**
3. Paste the following into the body:

```json
{{bulkBody}}
```

Open the **Pre-request Script** tab and paste the following script:

```javascript
const shared = JSON.parse(pm.collectionVariables.get('bulkShared') || '{}');
const endpoints = JSON.parse(pm.collectionVariables.get('bulkEndpoints') || '[]');

if (!endpoints.length) {
  throw new Error('No endpoints were collected from the CSV. Run "Bulk CSV — Collect rows" using Runner with a CSV data file.');
}

pm.variables.set('bulkBody', JSON.stringify({ ...shared, endpoints }));
```

> **Tip**
>
> This step is optional, but recommended.

Open the **Tests** tab and paste the following cleanup script:

```javascript
pm.test('Bulk request body contains endpoints', function () {
  pm.expect(pm.request.body.raw).to.include('"endpoints"');
});

// Clean up so reruns don't append old data
pm.collectionVariables.unset('bulkShared');
pm.collectionVariables.unset('bulkEndpoints');
pm.variables.unset('bulkBody');

// Stop after sending the bulk request
postman.setNextRequest(null);
```

#### Run the workflow in Runner

Open **Runner** in Postman.

Select the collection or folder that contains both requests:

1. `Bulk CSV — Collect rows`
2. `Bulk endpoint creation`

> **Warning**
>
> The order matters.
> The collector request must run first.

Under **Data**, upload your CSV file.

* Postman runs one iteration per CSV row.
* Each iteration populates `pm.iterationData` with the row's values.

Click **Start Run** to execute the requests.

The Runner executes each CSV row through the collector request, building an array of endpoints.
On the final row, it triggers the bulk request which sends all endpoints in a single API call.

> **Success**
>
> The script builds the bulk request automatically from your CSV data.

### Create more than 2,000 endpoints

If you need to create more than 2,000 endpoints:

Divide your endpoint data into batches of 2,000 or fewer.

> **Tip**
>
> For CSV workflows, split your CSV file into multiple files of 2,000 rows or fewer before processing.

Execute the first bulk request and wait for the `201 CREATED` response.

Update your request body with the next batch of endpoints.

Execute subsequent bulk requests sequentially, waiting for each to complete before starting the next.