Skip to content
Docs

Guide

Manage devices

Import SIMs, assign them to customers, activate them in bulk, confirm the provider's answer and handle refusals.

A device is one SIM card, identified by its ICCID (19 or 20 digits) and IMSI (15 digits). You can also store its modem's IMEI and an external_id of your own, such as a vehicle or asset number, to find it later.

The device lifecycle

inventoryactivesuspendedterminated
Each change goes through pending while the network provider confirms it. Suspended devices can be activated again; terminated is final.
ActionFromTo
Activateinventory, suspendedactive
Suspendactivesuspended
Deactivateactive, suspendedterminated (final)
Deleteinventory only(removed)

A pending device refuses every other change until the provider answers.

Import SIMs

Import up to 5,000 SIMs at a time from CSV text with the header iccid,imsi,imei,external_id.imei and external_id are optional, and the columns can come in any order.

sims.csv
iccid,imsi,imei,external_id
8999001234000020718,901880000010001,356938035643809,trailer-207
8999001234000011428,901880000010002,,trailer-114
8999001234000003185,901880000010003,,reefer-031
Request
curl -X POST https://api.houndsat.com/api/json/devices/import \
  -H "Authorization: Bearer $HOUNDSAT_TOKEN" \
  -H "Content-Type: application/vnd.api+json" \
  -d "$(jq -n --rawfile csv sims.csv '{data: {csv: $csv}}')"
Response200 OK
{
  "created": [
    { "row": 2, "id": "5f0c2b7e-8d41-4a96-b3e2-91c7d0a4e6f8", "iccid": "8999001234000020718" },
    { "row": 4, "id": "0b6d4e2a-1c9f-4a3b-8e5d-7f2c0a9b6d13", "iccid": "8999001234000003185" }
  ],
  "skipped": [
    { "row": 3, "iccid": "8999001234000011428", "reason": "already imported" }
  ],
  "errors": []
}

Every valid row is imported; rows whose ICCID or IMSI already exists are skipped, so re-running an import is safe; invalid rows are listed in errors with their row number (the header is row 1). Add "customer_id" next to "csv" to import straight into one of your customers. For a single SIM, use Add a device.

Assign to customers

Imported SIMs sit in your inventory until you assign them. Assign one, or up to 500 with Reassign devices in bulk; "customer_id": null returns a device to your inventory.

Request
curl -X PATCH https://api.houndsat.com/api/json/devices/5f0c2b7e-8d41-4a96-b3e2-91c7d0a4e6f8/assign \
  -H "Authorization: Bearer $HOUNDSAT_TOKEN" \
  -H "Content-Type: application/vnd.api+json" \
  -d '{
    "data": {
      "type": "device",
      "id": "5f0c2b7e-8d41-4a96-b3e2-91c7d0a4e6f8",
      "attributes": {"customer_id": "c41e9a03-6b2f-4d8e-a571-0f3b9c2d7e14"}
    }
  }'

Activate and confirm

Activate up to 500 devices per request:

Request
curl -X POST https://api.houndsat.com/api/json/devices/bulk/activate \
  -H "Authorization: Bearer $HOUNDSAT_TOKEN" \
  -H "Content-Type: application/vnd.api+json" \
  -d '{"data": {"ids": ["5f0c2b7e-8d41-4a96-b3e2-91c7d0a4e6f8", "0b6d4e2a-1c9f-4a3b-8e5d-7f2c0a9b6d13"]}}'

Each accepted device answers "status": "ok" in the results and moves to pending at once. HoundSat then asks the network provider and settles the device when it answers, usually within seconds. To see the outcome, read the devices again, or list those still pending:

Still pending
curl -g "https://api.houndsat.com/api/json/devices?filter[status]=pending&fields[device]=iccid,status,pending_operation" \
  -H "Authorization: Bearer $HOUNDSAT_TOKEN"

When the provider refuses

A refused or failed change puts the device back in its previous status and records why, with a message you can show as is:

A refused activation
{
  "status": "inventory",
  "last_failed_operation": "activate",
  "last_error_code": "provider_rejected",
  "last_error_message": "Activation failed: the provider rejected the request. Check the ICCID and try again.",
  "last_error_at": "2026-10-12T14:03:24Z",
  …
}
last_error_codeMeaning
provider_rejectedThe provider refused the change. Check the ICCID and try again.
provider_timeoutNo answer in time. The change may still happen: read the device later before retrying.
provider_rate_limitedThe provider is limiting requests. Try again in a few minutes.
provider_account_disabledThe SIM's provider account is disabled. Contact HoundSat support.
provider_not_configuredThe SIM's network isn't connected yet. Contact HoundSat support.
provider_errorAny other provider error.

The error fields clear when the next change starts. Separately, provider_status_mismatch turns true when an hourly check finds the provider reporting a different state than status.

Suspend and deactivate

Suspend pauses an active SIM; activate it again to resume. Deactivate ends it for good: the device becomes terminated and can't be activated again. Both work one device at a time (PATCH /api/json/devices/{id}/suspend) or in bulk, and go through pending like activation.

If two changes hit the same device at once, the second answers 409 stale_record. Read the device again and decide.

Find devices

last_seen_at is when the device last sent a message, and usage_this_month_bytes its data use so far this month. Both filter and sort:

Useful queries
# Never heard from
curl -g "https://api.houndsat.com/api/json/devices?filter[status]=active&filter[last_seen_at][is_nil]=true" -H "Authorization: Bearer $HOUNDSAT_TOKEN"

# Heaviest users this month
curl -g "https://api.houndsat.com/api/json/devices?sort=-usage_this_month_bytes&page[limit]=10" -H "Authorization: Bearer $HOUNDSAT_TOKEN"

# Your inventory: not assigned to a customer
curl -g "https://api.houndsat.com/api/json/devices?filter[customer_id][is_nil]=true" -H "Authorization: Bearer $HOUNDSAT_TOKEN"

# By ICCID, IMSI or external ID prefix
curl -g "https://api.houndsat.com/api/json/devices?search=trailer-2" -H "Authorization: Bearer $HOUNDSAT_TOKEN"