igloo
Docs / iglooworks / API Reference / Access

Access API Reference

API endpoints for managing access.

AlgoPIN

Create a Daily AlgoPIN

POSThttps://api.igloohome.co/works/devices/{id}/algopin/daily

See POST /devices/{id}/algopin/permanent. Identical shape, different scope. endDate is required for this PIN type (forbidden for permanent/onetime), and variance range is 1–3 (not 1–10).

Path Parameters

Parameter Type Required
id string Yes

Body Parameters

Content-Type:application/json
  • accessName string required
  • departmentId string
    Required unless the account has a single department.
  • startDate string required
    Format YYYY-MM-DDTHH:00:00+hh:mm. Must be now or after.
  • endDate string
    Format YYYY-MM-DDTHH:00:00+hh:mm. Required for daily/hourly, forbidden for onetime/permanent. Must be after startDate. Hourly: at most 672 hours after startDate.
  • variance integer required
    Daily/hourly: 1–3. Onetime/permanent: 1–10. Values 6–10 require newer lock firmware (some older locks support them after a firmware update); otherwise use 1–5.

Request Example

curl -X POST "https://api.igloohome.co/works/devices/{id}/algopin/daily" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "accessName": "value",
    "departmentId": "value",
    "endDate": "value",
    "startDate": "value",
    "variance": "value"
  }'
const res = await fetch("https://api.igloohome.co/works/devices/{id}/algopin/daily", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "accessName": "value",
    "departmentId": "value",
    "endDate": "value",
    "startDate": "value",
    "variance": "value"
  })
});

const data = await res.json();
console.log(data);
import requests

url = "https://api.igloohome.co/works/devices/{id}/algopin/daily"
headers = {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Accept": "application/json"
}
payload = {
    "accessName": "value",
    "departmentId": "value",
    "endDate": "value",
    "startDate": "value",
    "variance": "value"
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
)

func main() {
	url := "https://api.igloohome.co/works/devices/{id}/algopin/daily"
	payload := []byte(`{
		"accessName": "value",
		"departmentId": "value",
		"endDate": "value",
		"startDate": "value",
		"variance": "value"
	}`)

	req, _ := http.NewRequest("POST", url, bytes.NewBuffer(payload))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer YOUR_ACCESS_TOKEN")
	req.Header.Set("Accept", "application/json")

	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()

	body, _ := io.ReadAll(res.Body)
	fmt.Println(string(body))
}
<?php
$curl = curl_init();

curl_setopt_array($curl, [
    CURLOPT_URL => "https://api.igloohome.co/works/devices/{id}/algopin/daily",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer YOUR_ACCESS_TOKEN",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS => json_encode([
        "accessName" => "value",
        "departmentId" => "value",
        "endDate" => "value",
        "startDate" => "value",
        "variance" => "value"
    ])
]);

$response = curl_exec($curl);
curl_close($curl);

echo $response;
val client = OkHttpClient()

val mediaType = "application/json".toMediaType()
val body = """
    {
        "accessName": "value",
        "departmentId": "value",
        "endDate": "value",
        "startDate": "value",
        "variance": "value"
    }
""".trimIndent().toRequestBody(mediaType)

val request = Request.Builder()
    .url("https://api.igloohome.co/works/devices/{id}/algopin/daily")
    .method("POST", body)
    .addHeader("Authorization", "Bearer YOUR_ACCESS_TOKEN")
    .addHeader("Accept", "application/json")
    .addHeader("Content-Type", "application/json")
    .build()

val response = client.newCall(request).execute()
println(response.body?.string())
import Foundation

var request = URLRequest(url: URL(string: "https://api.igloohome.co/works/devices/{id}/algopin/daily")!)
request.httpMethod = "POST"
request.setValue("Bearer YOUR_ACCESS_TOKEN", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let payload: [String: Any] = [
    "accessName": "value",
    "departmentId": "value",
    "endDate": "value",
    "startDate": "value",
    "variance": "value"
]
request.httpBody = try? JSONSerialization.data(withJSONObject: payload)

let task = URLSession.shared.dataTask(with: request) { data, response, error in
    if let data = data {
        print(String(data: data, encoding: .utf8) ?? "")
    }
}
task.resume()

Responses

200400401403409415

OK. If a matching PIN already exists for this lock, type, and window with the same 'variance', the API returns the same success response without creating a new PIN. This idempotent behavior is not an error.

Example response — 402-account-suspended:

{
  "error": "account.payment.is.suspended"
}

Example response — 402-trial-ended:

{
  "error": "30 days iglooworks API trial has ended"
}

Create an Hourly AlgoPIN

POSThttps://api.igloohome.co/works/devices/{id}/algopin/hourly

See POST /devices/{id}/algopin/permanent. Identical shape, different scope. endDate is required for this PIN type (forbidden for permanent/onetime), and variance range is 1–3 (not 1–10).

Path Parameters

Parameter Type Required
id string Yes

Body Parameters

Content-Type:application/json
  • accessName string required
  • departmentId string
    Required unless the account has a single department.
  • startDate string required
    Format YYYY-MM-DDTHH:00:00+hh:mm. Must be now or after.
  • endDate string
    Format YYYY-MM-DDTHH:00:00+hh:mm. Required for daily/hourly, forbidden for onetime/permanent. Must be after startDate. Hourly: at most 672 hours after startDate.
  • variance integer required
    Daily/hourly: 1–3. Onetime/permanent: 1–10. Values 6–10 require newer lock firmware (some older locks support them after a firmware update); otherwise use 1–5.

Request Example

curl -X POST "https://api.igloohome.co/works/devices/{id}/algopin/hourly" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "accessName": "value",
    "departmentId": "value",
    "endDate": "value",
    "startDate": "value",
    "variance": "value"
  }'
const res = await fetch("https://api.igloohome.co/works/devices/{id}/algopin/hourly", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "accessName": "value",
    "departmentId": "value",
    "endDate": "value",
    "startDate": "value",
    "variance": "value"
  })
});

const data = await res.json();
console.log(data);
import requests

url = "https://api.igloohome.co/works/devices/{id}/algopin/hourly"
headers = {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Accept": "application/json"
}
payload = {
    "accessName": "value",
    "departmentId": "value",
    "endDate": "value",
    "startDate": "value",
    "variance": "value"
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
)

func main() {
	url := "https://api.igloohome.co/works/devices/{id}/algopin/hourly"
	payload := []byte(`{
		"accessName": "value",
		"departmentId": "value",
		"endDate": "value",
		"startDate": "value",
		"variance": "value"
	}`)

	req, _ := http.NewRequest("POST", url, bytes.NewBuffer(payload))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer YOUR_ACCESS_TOKEN")
	req.Header.Set("Accept", "application/json")

	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()

	body, _ := io.ReadAll(res.Body)
	fmt.Println(string(body))
}
<?php
$curl = curl_init();

curl_setopt_array($curl, [
    CURLOPT_URL => "https://api.igloohome.co/works/devices/{id}/algopin/hourly",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer YOUR_ACCESS_TOKEN",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS => json_encode([
        "accessName" => "value",
        "departmentId" => "value",
        "endDate" => "value",
        "startDate" => "value",
        "variance" => "value"
    ])
]);

$response = curl_exec($curl);
curl_close($curl);

echo $response;
val client = OkHttpClient()

val mediaType = "application/json".toMediaType()
val body = """
    {
        "accessName": "value",
        "departmentId": "value",
        "endDate": "value",
        "startDate": "value",
        "variance": "value"
    }
""".trimIndent().toRequestBody(mediaType)

val request = Request.Builder()
    .url("https://api.igloohome.co/works/devices/{id}/algopin/hourly")
    .method("POST", body)
    .addHeader("Authorization", "Bearer YOUR_ACCESS_TOKEN")
    .addHeader("Accept", "application/json")
    .addHeader("Content-Type", "application/json")
    .build()

val response = client.newCall(request).execute()
println(response.body?.string())
import Foundation

var request = URLRequest(url: URL(string: "https://api.igloohome.co/works/devices/{id}/algopin/hourly")!)
request.httpMethod = "POST"
request.setValue("Bearer YOUR_ACCESS_TOKEN", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let payload: [String: Any] = [
    "accessName": "value",
    "departmentId": "value",
    "endDate": "value",
    "startDate": "value",
    "variance": "value"
]
request.httpBody = try? JSONSerialization.data(withJSONObject: payload)

let task = URLSession.shared.dataTask(with: request) { data, response, error in
    if let data = data {
        print(String(data: data, encoding: .utf8) ?? "")
    }
}
task.resume()

Responses

200400401403409415

OK. If a matching PIN already exists for this lock, type, and window with the same 'variance', the API returns the same success response without creating a new PIN. This idempotent behavior is not an error.

Example response — 402-account-suspended:

{
  "error": "account.payment.is.suspended"
}

Example response — 402-trial-ended:

{
  "error": "30 days iglooworks API trial has ended"
}

Create a One-Time AlgoPIN

POSThttps://api.igloohome.co/works/devices/{id}/algopin/onetime

See POST /devices/{id}/algopin/permanent. Identical shape, different scope.

Path Parameters

Parameter Type Required
id string Yes

Body Parameters

Content-Type:application/json
  • accessName string required
  • departmentId string
    Required unless the account has a single department.
  • startDate string required
    Format YYYY-MM-DDTHH:00:00+hh:mm. Must be now or after.
  • endDate string
    Format YYYY-MM-DDTHH:00:00+hh:mm. Required for daily/hourly, forbidden for onetime/permanent. Must be after startDate. Hourly: at most 672 hours after startDate.
  • variance integer required
    Daily/hourly: 1–3. Onetime/permanent: 1–10. Values 6–10 require newer lock firmware (some older locks support them after a firmware update); otherwise use 1–5.

Request Example

curl -X POST "https://api.igloohome.co/works/devices/{id}/algopin/onetime" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "accessName": "value",
    "departmentId": "value",
    "endDate": "value",
    "startDate": "value",
    "variance": "value"
  }'
const res = await fetch("https://api.igloohome.co/works/devices/{id}/algopin/onetime", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "accessName": "value",
    "departmentId": "value",
    "endDate": "value",
    "startDate": "value",
    "variance": "value"
  })
});

const data = await res.json();
console.log(data);
import requests

url = "https://api.igloohome.co/works/devices/{id}/algopin/onetime"
headers = {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Accept": "application/json"
}
payload = {
    "accessName": "value",
    "departmentId": "value",
    "endDate": "value",
    "startDate": "value",
    "variance": "value"
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
)

func main() {
	url := "https://api.igloohome.co/works/devices/{id}/algopin/onetime"
	payload := []byte(`{
		"accessName": "value",
		"departmentId": "value",
		"endDate": "value",
		"startDate": "value",
		"variance": "value"
	}`)

	req, _ := http.NewRequest("POST", url, bytes.NewBuffer(payload))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer YOUR_ACCESS_TOKEN")
	req.Header.Set("Accept", "application/json")

	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()

	body, _ := io.ReadAll(res.Body)
	fmt.Println(string(body))
}
<?php
$curl = curl_init();

curl_setopt_array($curl, [
    CURLOPT_URL => "https://api.igloohome.co/works/devices/{id}/algopin/onetime",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer YOUR_ACCESS_TOKEN",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS => json_encode([
        "accessName" => "value",
        "departmentId" => "value",
        "endDate" => "value",
        "startDate" => "value",
        "variance" => "value"
    ])
]);

$response = curl_exec($curl);
curl_close($curl);

echo $response;
val client = OkHttpClient()

val mediaType = "application/json".toMediaType()
val body = """
    {
        "accessName": "value",
        "departmentId": "value",
        "endDate": "value",
        "startDate": "value",
        "variance": "value"
    }
""".trimIndent().toRequestBody(mediaType)

val request = Request.Builder()
    .url("https://api.igloohome.co/works/devices/{id}/algopin/onetime")
    .method("POST", body)
    .addHeader("Authorization", "Bearer YOUR_ACCESS_TOKEN")
    .addHeader("Accept", "application/json")
    .addHeader("Content-Type", "application/json")
    .build()

val response = client.newCall(request).execute()
println(response.body?.string())
import Foundation

var request = URLRequest(url: URL(string: "https://api.igloohome.co/works/devices/{id}/algopin/onetime")!)
request.httpMethod = "POST"
request.setValue("Bearer YOUR_ACCESS_TOKEN", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let payload: [String: Any] = [
    "accessName": "value",
    "departmentId": "value",
    "endDate": "value",
    "startDate": "value",
    "variance": "value"
]
request.httpBody = try? JSONSerialization.data(withJSONObject: payload)

let task = URLSession.shared.dataTask(with: request) { data, response, error in
    if let data = data {
        print(String(data: data, encoding: .utf8) ?? "")
    }
}
task.resume()

Responses

200400401403409415

OK. If a matching PIN already exists for this lock, type, and window with the same 'variance', the API returns the same success response without creating a new PIN. This idempotent behavior is not an error.

Example response — 402-account-suspended:

{
  "error": "account.payment.is.suspended"
}

Example response — 402-trial-ended:

{
  "error": "30 days iglooworks API trial has ended"
}

Create a Passage AlgoPIN

POSThttps://api.igloohome.co/works/devices/{id}/algopin/passage

Allows unlock with AlgoPIN and keeps the lock unlocked for the duration given in the request body. Supports newer devices with the latest firmware only.

Path Parameters

Parameter Type Required
id string Yes

Body Parameters

Content-Type:application/json
  • variance integer required
    • Allowed values: 1
  • startDate string<date-time> required
    Date and time when the permission starts. Must be in format YYYY-MM-DDTHH:00:00+hh:mm (hour resolution only). The PIN is valid from startDate for durationHours hours.
    • Example: 2022-01-01T12:00:00+08:00
  • durationHours integer required
    Must be between 1 and 12 hours
  • accessName string required
    Name or short description of the access
    • Example: Maintenance guy
  • departmentId string
    Required unless the account has a single department.

Request Example

curl -X POST "https://api.igloohome.co/works/devices/{id}/algopin/passage" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "accessName": "value",
    "departmentId": "value",
    "durationHours": "value",
    "startDate": "value",
    "variance": "value"
  }'
const res = await fetch("https://api.igloohome.co/works/devices/{id}/algopin/passage", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "accessName": "value",
    "departmentId": "value",
    "durationHours": "value",
    "startDate": "value",
    "variance": "value"
  })
});

const data = await res.json();
console.log(data);
import requests

url = "https://api.igloohome.co/works/devices/{id}/algopin/passage"
headers = {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Accept": "application/json"
}
payload = {
    "accessName": "value",
    "departmentId": "value",
    "durationHours": "value",
    "startDate": "value",
    "variance": "value"
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
)

func main() {
	url := "https://api.igloohome.co/works/devices/{id}/algopin/passage"
	payload := []byte(`{
		"accessName": "value",
		"departmentId": "value",
		"durationHours": "value",
		"startDate": "value",
		"variance": "value"
	}`)

	req, _ := http.NewRequest("POST", url, bytes.NewBuffer(payload))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer YOUR_ACCESS_TOKEN")
	req.Header.Set("Accept", "application/json")

	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()

	body, _ := io.ReadAll(res.Body)
	fmt.Println(string(body))
}
<?php
$curl = curl_init();

curl_setopt_array($curl, [
    CURLOPT_URL => "https://api.igloohome.co/works/devices/{id}/algopin/passage",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer YOUR_ACCESS_TOKEN",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS => json_encode([
        "accessName" => "value",
        "departmentId" => "value",
        "durationHours" => "value",
        "startDate" => "value",
        "variance" => "value"
    ])
]);

$response = curl_exec($curl);
curl_close($curl);

echo $response;
val client = OkHttpClient()

val mediaType = "application/json".toMediaType()
val body = """
    {
        "accessName": "value",
        "departmentId": "value",
        "durationHours": "value",
        "startDate": "value",
        "variance": "value"
    }
""".trimIndent().toRequestBody(mediaType)

val request = Request.Builder()
    .url("https://api.igloohome.co/works/devices/{id}/algopin/passage")
    .method("POST", body)
    .addHeader("Authorization", "Bearer YOUR_ACCESS_TOKEN")
    .addHeader("Accept", "application/json")
    .addHeader("Content-Type", "application/json")
    .build()

val response = client.newCall(request).execute()
println(response.body?.string())
import Foundation

var request = URLRequest(url: URL(string: "https://api.igloohome.co/works/devices/{id}/algopin/passage")!)
request.httpMethod = "POST"
request.setValue("Bearer YOUR_ACCESS_TOKEN", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let payload: [String: Any] = [
    "accessName": "value",
    "departmentId": "value",
    "durationHours": "value",
    "startDate": "value",
    "variance": "value"
]
request.httpBody = try? JSONSerialization.data(withJSONObject: payload)

let task = URLSession.shared.dataTask(with: request) { data, response, error in
    if let data = data {
        print(String(data: data, encoding: .utf8) ?? "")
    }
}
task.resume()

Responses

200400401403409415

OK. If a matching PIN already exists for this lock, type, and window with the same 'variance', the API returns the same success response without creating a new PIN. This idempotent behavior is not an error.

Example response — 402-account-suspended:

{
  "error": "account.payment.is.suspended"
}

Example response — 402-trial-ended:

{
  "error": "30 days iglooworks API trial has ended"
}

Create a Permanent AlgoPIN

POSThttps://api.igloohome.co/works/devices/{id}/algopin/permanent

Request and response shape match the other AlgoPIN endpoints (onetime/daily/hourly). Requires the algopin-permanent scope. A different AlgoPIN scope (e.g. algopin-daily) is not sufficient and returns a 403.

Path Parameters

Parameter Type Required
id string Yes

Body Parameters

Content-Type:application/json
  • accessName string required
  • departmentId string
    Required unless the account has a single department.
  • startDate string required
    Format YYYY-MM-DDTHH:00:00+hh:mm. Must be now or after.
  • endDate string
    Format YYYY-MM-DDTHH:00:00+hh:mm. Required for daily/hourly, forbidden for onetime/permanent. Must be after startDate. Hourly: at most 672 hours after startDate.
  • variance integer required
    Daily/hourly: 1–3. Onetime/permanent: 1–10. Values 6–10 require newer lock firmware (some older locks support them after a firmware update); otherwise use 1–5.

Request Example

curl -X POST "https://api.igloohome.co/works/devices/{id}/algopin/permanent" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "accessName": "value",
    "departmentId": "value",
    "endDate": "value",
    "startDate": "value",
    "variance": "value"
  }'
const res = await fetch("https://api.igloohome.co/works/devices/{id}/algopin/permanent", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "accessName": "value",
    "departmentId": "value",
    "endDate": "value",
    "startDate": "value",
    "variance": "value"
  })
});

const data = await res.json();
console.log(data);
import requests

url = "https://api.igloohome.co/works/devices/{id}/algopin/permanent"
headers = {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Accept": "application/json"
}
payload = {
    "accessName": "value",
    "departmentId": "value",
    "endDate": "value",
    "startDate": "value",
    "variance": "value"
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
)

func main() {
	url := "https://api.igloohome.co/works/devices/{id}/algopin/permanent"
	payload := []byte(`{
		"accessName": "value",
		"departmentId": "value",
		"endDate": "value",
		"startDate": "value",
		"variance": "value"
	}`)

	req, _ := http.NewRequest("POST", url, bytes.NewBuffer(payload))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer YOUR_ACCESS_TOKEN")
	req.Header.Set("Accept", "application/json")

	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()

	body, _ := io.ReadAll(res.Body)
	fmt.Println(string(body))
}
<?php
$curl = curl_init();

curl_setopt_array($curl, [
    CURLOPT_URL => "https://api.igloohome.co/works/devices/{id}/algopin/permanent",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer YOUR_ACCESS_TOKEN",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS => json_encode([
        "accessName" => "value",
        "departmentId" => "value",
        "endDate" => "value",
        "startDate" => "value",
        "variance" => "value"
    ])
]);

$response = curl_exec($curl);
curl_close($curl);

echo $response;
val client = OkHttpClient()

val mediaType = "application/json".toMediaType()
val body = """
    {
        "accessName": "value",
        "departmentId": "value",
        "endDate": "value",
        "startDate": "value",
        "variance": "value"
    }
""".trimIndent().toRequestBody(mediaType)

val request = Request.Builder()
    .url("https://api.igloohome.co/works/devices/{id}/algopin/permanent")
    .method("POST", body)
    .addHeader("Authorization", "Bearer YOUR_ACCESS_TOKEN")
    .addHeader("Accept", "application/json")
    .addHeader("Content-Type", "application/json")
    .build()

val response = client.newCall(request).execute()
println(response.body?.string())
import Foundation

var request = URLRequest(url: URL(string: "https://api.igloohome.co/works/devices/{id}/algopin/permanent")!)
request.httpMethod = "POST"
request.setValue("Bearer YOUR_ACCESS_TOKEN", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let payload: [String: Any] = [
    "accessName": "value",
    "departmentId": "value",
    "endDate": "value",
    "startDate": "value",
    "variance": "value"
]
request.httpBody = try? JSONSerialization.data(withJSONObject: payload)

let task = URLSession.shared.dataTask(with: request) { data, response, error in
    if let data = data {
        print(String(data: data, encoding: .utf8) ?? "")
    }
}
task.resume()

Responses

200400401403409415

OK. If a matching PIN already exists for this lock, type, and window with the same 'variance', the API returns the same success response without creating a new PIN. This idempotent behavior is not an error.

Example response — 402-account-suspended:

{
  "error": "account.payment.is.suspended"
}

Example response — 402-trial-ended:

{
  "error": "30 days iglooworks API trial has ended"
}

eKey

Grant eKey Access

POSThttps://api.igloohome.co/works/devices/{id}/access/grant

Creates an eKey access record for the recipient and logs it in device activity and access history. All error responses on this endpoint use a {message, code} body shape. See the 404 response below for the specific not-found causes.

Path Parameters

Parameter Type Required
id string Yes

Body Parameters

Content-Type:application/json
  • recipientId string required
  • startDateTime string<date-time> required
    Must include an explicit timezone offset ('Z' or '+08:00').
  • endDateTime string<date-time> required
    Must be after startDateTime and after the current time. Same explicit-timezone-offset requirement.
  • permissions array of string required
    Narrower allow-list than POST /ekey's 56-value list, even though both mint an eKey.
  • departmentRef string
  • lang string

Request Example

curl -X POST "https://api.igloohome.co/works/devices/{id}/access/grant" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "departmentRef": "value",
    "endDateTime": "value",
    "lang": "value",
    "permissions": "value",
    "recipientId": "value",
    "startDateTime": "value"
  }'
const res = await fetch("https://api.igloohome.co/works/devices/{id}/access/grant", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "departmentRef": "value",
    "endDateTime": "value",
    "lang": "value",
    "permissions": "value",
    "recipientId": "value",
    "startDateTime": "value"
  })
});

const data = await res.json();
console.log(data);
import requests

url = "https://api.igloohome.co/works/devices/{id}/access/grant"
headers = {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Accept": "application/json"
}
payload = {
    "departmentRef": "value",
    "endDateTime": "value",
    "lang": "value",
    "permissions": "value",
    "recipientId": "value",
    "startDateTime": "value"
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
)

func main() {
	url := "https://api.igloohome.co/works/devices/{id}/access/grant"
	payload := []byte(`{
		"departmentRef": "value",
		"endDateTime": "value",
		"lang": "value",
		"permissions": "value",
		"recipientId": "value",
		"startDateTime": "value"
	}`)

	req, _ := http.NewRequest("POST", url, bytes.NewBuffer(payload))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer YOUR_ACCESS_TOKEN")
	req.Header.Set("Accept", "application/json")

	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()

	body, _ := io.ReadAll(res.Body)
	fmt.Println(string(body))
}
<?php
$curl = curl_init();

curl_setopt_array($curl, [
    CURLOPT_URL => "https://api.igloohome.co/works/devices/{id}/access/grant",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer YOUR_ACCESS_TOKEN",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS => json_encode([
        "departmentRef" => "value",
        "endDateTime" => "value",
        "lang" => "value",
        "permissions" => "value",
        "recipientId" => "value",
        "startDateTime" => "value"
    ])
]);

$response = curl_exec($curl);
curl_close($curl);

echo $response;
val client = OkHttpClient()

val mediaType = "application/json".toMediaType()
val body = """
    {
        "departmentRef": "value",
        "endDateTime": "value",
        "lang": "value",
        "permissions": "value",
        "recipientId": "value",
        "startDateTime": "value"
    }
""".trimIndent().toRequestBody(mediaType)

val request = Request.Builder()
    .url("https://api.igloohome.co/works/devices/{id}/access/grant")
    .method("POST", body)
    .addHeader("Authorization", "Bearer YOUR_ACCESS_TOKEN")
    .addHeader("Accept", "application/json")
    .addHeader("Content-Type", "application/json")
    .build()

val response = client.newCall(request).execute()
println(response.body?.string())
import Foundation

var request = URLRequest(url: URL(string: "https://api.igloohome.co/works/devices/{id}/access/grant")!)
request.httpMethod = "POST"
request.setValue("Bearer YOUR_ACCESS_TOKEN", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let payload: [String: Any] = [
    "departmentRef": "value",
    "endDateTime": "value",
    "lang": "value",
    "permissions": "value",
    "recipientId": "value",
    "startDateTime": "value"
]
request.httpBody = try? JSONSerialization.data(withJSONObject: payload)

let task = URLSession.shared.dataTask(with: request) { data, response, error in
    if let data = data {
        print(String(data: data, encoding: .utf8) ?? "")
    }
}
task.resume()

Responses

201400401403404409415422500

Created. If activity logging fails after the API saves the access record, the API still returns 201, but with a different response body (no 'code' field) containing an error message.

Example response — 402-account-suspended:

{
  "error": "account.payment.is.suspended"
}

Example response — 402-trial-ended:

{
  "error": "30 days iglooworks API trial has ended"
}

Revoke eKey Access

POSThttps://api.igloohome.co/works/devices/{id}/access/revoke

Revokes all matching access records for this recipient and permanently deletes their associated key material. You cannot undo this action.

Path Parameters

Parameter Type Required
id string Yes

Body Parameters

Content-Type:application/json
  • recipientId string required

Request Example

curl -X POST "https://api.igloohome.co/works/devices/{id}/access/revoke" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "recipientId": "value"
  }'
const res = await fetch("https://api.igloohome.co/works/devices/{id}/access/revoke", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "recipientId": "value"
  })
});

const data = await res.json();
console.log(data);
import requests

url = "https://api.igloohome.co/works/devices/{id}/access/revoke"
headers = {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Accept": "application/json"
}
payload = {
    "recipientId": "value"
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
)

func main() {
	url := "https://api.igloohome.co/works/devices/{id}/access/revoke"
	payload := []byte(`{
		"recipientId": "value"
	}`)

	req, _ := http.NewRequest("POST", url, bytes.NewBuffer(payload))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer YOUR_ACCESS_TOKEN")
	req.Header.Set("Accept", "application/json")

	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()

	body, _ := io.ReadAll(res.Body)
	fmt.Println(string(body))
}
<?php
$curl = curl_init();

curl_setopt_array($curl, [
    CURLOPT_URL => "https://api.igloohome.co/works/devices/{id}/access/revoke",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer YOUR_ACCESS_TOKEN",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS => json_encode([
        "recipientId" => "value"
    ])
]);

$response = curl_exec($curl);
curl_close($curl);

echo $response;
val client = OkHttpClient()

val mediaType = "application/json".toMediaType()
val body = """
    {
        "recipientId": "value"
    }
""".trimIndent().toRequestBody(mediaType)

val request = Request.Builder()
    .url("https://api.igloohome.co/works/devices/{id}/access/revoke")
    .method("POST", body)
    .addHeader("Authorization", "Bearer YOUR_ACCESS_TOKEN")
    .addHeader("Accept", "application/json")
    .addHeader("Content-Type", "application/json")
    .build()

val response = client.newCall(request).execute()
println(response.body?.string())
import Foundation

var request = URLRequest(url: URL(string: "https://api.igloohome.co/works/devices/{id}/access/revoke")!)
request.httpMethod = "POST"
request.setValue("Bearer YOUR_ACCESS_TOKEN", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let payload: [String: Any] = [
    "recipientId": "value"
]
request.httpBody = try? JSONSerialization.data(withJSONObject: payload)

let task = URLSession.shared.dataTask(with: request) { data, response, error in
    if let data = data {
        print(String(data: data, encoding: .utf8) ?? "")
    }
}
task.resume()

Responses

200400401403404415500

OK.

Example response — 402-account-suspended:

{
  "error": "account.payment.is.suspended"
}

Example response — 402-trial-ended:

{
  "error": "30 days iglooworks API trial has ended"
}

Generate eKey

POSThttps://api.igloohome.co/works/devices/{id}/ekey

Returns an eKey without creating an access record. To create a tracked access record, use Grant eKey Access. Error responses are plain text, not JSON. Only a successful response returns a JSON body.

Path Parameters

Parameter Type Required
id string Yes

Body Parameters

Content-Type:application/json
  • startDate string required
    Format YYYY-MM-DDTHH:mm:00Z (minute resolution).
  • endDate string required
    Must be after startDate. Same format.
  • permissions array of string required
    Each must be a valid permission type (56 supported values).

Request Example

curl -X POST "https://api.igloohome.co/works/devices/{id}/ekey" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "endDate": "value",
    "permissions": "value",
    "startDate": "value"
  }'
const res = await fetch("https://api.igloohome.co/works/devices/{id}/ekey", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "endDate": "value",
    "permissions": "value",
    "startDate": "value"
  })
});

const data = await res.json();
console.log(data);
import requests

url = "https://api.igloohome.co/works/devices/{id}/ekey"
headers = {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Accept": "application/json"
}
payload = {
    "endDate": "value",
    "permissions": "value",
    "startDate": "value"
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())
package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
)

func main() {
	url := "https://api.igloohome.co/works/devices/{id}/ekey"
	payload := []byte(`{
		"endDate": "value",
		"permissions": "value",
		"startDate": "value"
	}`)

	req, _ := http.NewRequest("POST", url, bytes.NewBuffer(payload))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer YOUR_ACCESS_TOKEN")
	req.Header.Set("Accept", "application/json")

	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()

	body, _ := io.ReadAll(res.Body)
	fmt.Println(string(body))
}
<?php
$curl = curl_init();

curl_setopt_array($curl, [
    CURLOPT_URL => "https://api.igloohome.co/works/devices/{id}/ekey",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer YOUR_ACCESS_TOKEN",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS => json_encode([
        "endDate" => "value",
        "permissions" => "value",
        "startDate" => "value"
    ])
]);

$response = curl_exec($curl);
curl_close($curl);

echo $response;
val client = OkHttpClient()

val mediaType = "application/json".toMediaType()
val body = """
    {
        "endDate": "value",
        "permissions": "value",
        "startDate": "value"
    }
""".trimIndent().toRequestBody(mediaType)

val request = Request.Builder()
    .url("https://api.igloohome.co/works/devices/{id}/ekey")
    .method("POST", body)
    .addHeader("Authorization", "Bearer YOUR_ACCESS_TOKEN")
    .addHeader("Accept", "application/json")
    .addHeader("Content-Type", "application/json")
    .build()

val response = client.newCall(request).execute()
println(response.body?.string())
import Foundation

var request = URLRequest(url: URL(string: "https://api.igloohome.co/works/devices/{id}/ekey")!)
request.httpMethod = "POST"
request.setValue("Bearer YOUR_ACCESS_TOKEN", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let payload: [String: Any] = [
    "endDate": "value",
    "permissions": "value",
    "startDate": "value"
]
request.httpBody = try? JSONSerialization.data(withJSONObject: payload)

let task = URLSession.shared.dataTask(with: request) { data, response, error in
    if let data = data {
        print(String(data: data, encoding: .utf8) ?? "")
    }
}
task.resume()

Responses

200400401403409415500

OK.

Example response — 402-account-suspended:

{
  "error": "account.payment.is.suspended"
}

Example response — 402-trial-ended:

{
  "error": "30 days iglooworks API trial has ended"
}

Access Records

List Device Access

GEThttps://api.igloohome.co/works/devices/{id}/access

A malformed query parameter returns a 400, even if authentication is missing or invalid.

Path Parameters

Parameter Type Required
id string Yes

Query Parameters

  • accessType string
    Comma-separated list from pin,ekey,nfc,fingerprint. Invalid entries → 400 {error: "valid 'accessType' - pin,ekey,nfc,fingerprint"}.
  • limit integer
    • Constraints: >= 1, <= 300
    • Default: 100
  • cursor string
  • sort string
    • Default: desc
    • Allowed values: asc, desc

Request Example

curl -X GET "https://api.igloohome.co/works/devices/{id}/access?accessType=value&limit=value&cursor=value&sort=value" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Accept: application/json"
const res = await fetch("https://api.igloohome.co/works/devices/{id}/access?accessType=value&limit=value&cursor=value&sort=value", {
  method: "GET",
  headers: {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Accept": "application/json"
  }
});

const data = await res.json();
console.log(data);
import requests

url = "https://api.igloohome.co/works/devices/{id}/access"
headers = {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Accept": "application/json"
}
params = {
    "accessType": "value",
    "limit": "value",
    "cursor": "value",
    "sort": "value"
}
response = requests.get(url, headers=headers, params=params)
print(response.json())
package main

import (
	"fmt"
	"io"
	"net/http"
)

func main() {
	url := "https://api.igloohome.co/works/devices/{id}/access?accessType=value&limit=value&cursor=value&sort=value"
	req, _ := http.NewRequest("GET", url, nil)
	req.Header.Set("Authorization", "Bearer YOUR_ACCESS_TOKEN")
	req.Header.Set("Accept", "application/json")

	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()

	body, _ := io.ReadAll(res.Body)
	fmt.Println(string(body))
}
<?php
$curl = curl_init();

curl_setopt_array($curl, [
    CURLOPT_URL => "https://api.igloohome.co/works/devices/{id}/access?accessType=value&limit=value&cursor=value&sort=value",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "GET",
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer YOUR_ACCESS_TOKEN",
        "Accept: application/json"
    ]
]);

$response = curl_exec($curl);
curl_close($curl);

echo $response;
val client = OkHttpClient()

val request = Request.Builder()
    .url("https://api.igloohome.co/works/devices/{id}/access?accessType=value&limit=value&cursor=value&sort=value")
    .method("GET", null)
    .addHeader("Authorization", "Bearer YOUR_ACCESS_TOKEN")
    .addHeader("Accept", "application/json")
    .build()

val response = client.newCall(request).execute()
println(response.body?.string())
import Foundation

var request = URLRequest(url: URL(string: "https://api.igloohome.co/works/devices/{id}/access?accessType=value&limit=value&cursor=value&sort=value")!)
request.httpMethod = "GET"
request.setValue("Bearer YOUR_ACCESS_TOKEN", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Accept")

let task = URLSession.shared.dataTask(with: request) { data, response, error in
    if let data = data {
        print(String(data: data, encoding: .utf8) ?? "")
    }
}
task.resume()

Responses

200400401403404409

OK.

Example response — 402-account-suspended:

{
  "error": "account.payment.is.suspended"
}

Example response — 402-trial-ended:

{
  "error": "30 days iglooworks API trial has ended"
}