API: products and profiles
General contract in How the API works. Everything is bound to the key's account,
which need not send clientId or accountId when creating (they are ignored if they point elsewhere).
Products
POST /products
GET /products
GET /products/:id
PATCH /products/:id
PATCH /products/:id/deactivate
PATCH /products/:id/activate
DELETE /products/:id
Creating a product — 201
| Field | Type | Required | Notes |
|---|---|---|---|
businessLine | 'vending' | 'eas' | yes | must be enabled on the account |
name | string | yes | min. 2 |
type | string | yes | key of the product_types selector (GET /selectors/product_types) |
cost | integer | yes | minor units, ≥ 0 |
code | string | no | informational, unique per account among live products |
description | string | no | — |
currency | string | no | if sent, must match the account's |
attributes | object | yes | shape depends on the line (below) |
attributes for EAS:
{ "returnPolicy": { "isReturnable": true, "restrictDelivery": false } }
attributes for vending:
{ "taxRate": 19, "listPrice": 3000, "suggestedPrice": 3000 }
Full example:
curl -X POST https://api.inssacs.com/products \
-H 'x-api-key: ics_…' -H 'content-type: application/json' \
-d '{
"businessLine": "eas",
"name": "Casco de seguridad",
"type": "epp",
"code": "EPP-CAS",
"cost": 38000,
"attributes": { "returnPolicy": { "isReturnable": true, "restrictDelivery": true } }
}'
Editing — 200
PATCH /products/:id accepts name, code, description, cost, type, easAttributes and
vendingAttributes (all optional). Business line and account cannot change.
Listing
Query: businessLine, isActive, search (name, code or type), code, page, pageSize (max
1000). Response { items, total, page, pageSize }.
Removal
deactivate / activate answer 204. DELETE answers 204 and removes the product from every
device planogram and from the EAS profiles that include it; historical deliveries are kept.
Errors: 404 products.not_found, 409 products.code_exists,
400 products.attributes_mismatch, 400 products.currency_mismatch,
403 products.not_visible_to_scope.
Profiles
POST /profiles
GET /profiles
GET /profiles/:id
PATCH /profiles/:id
PATCH /profiles/:id/deactivate
PATCH /profiles/:id/activate
DELETE /profiles/:id
A profile belongs to the account and to one line; where it works is defined by allowedDevices.
Concept in Codes and profiles.
Creating a profile — 201
| Field | Type | Required | Notes |
|---|---|---|---|
accountId | string | yes | the key's account |
businessLine | 'vending' | 'eas' | yes | — |
name | string | yes | min. 2, unique per account |
period | object | yes | see below |
policy | object | yes | shape depends on the line |
allowedDevices | string[] | no | device ids, up to 5000. Empty = dispenses nowhere |
consumptionSchedule | object | null | no | allowed days |
period — preset or specific dates:
{ "type": "preset", "value": "monthly" }
{ "type": "custom", "dates": ["2026-09-01T00:00:00.000Z", "2026-09-15T00:00:00.000Z"] }
Values for value: daily, weekly, biweekly, monthly, quarterly, semiannual, annual.
policy for vending (amounts in minor units):
{ "defaultReloadValue": 50000, "maxBalance": 200000, "cumulative": false }
policy for EAS (at least one product; quantity: null = unlimited):
{
"products": [
{ "productId": "665f…d0", "quantity": 1, "minutesBetweenDeliveries": 43200 },
{ "productId": "665f…d1", "quantity": null, "minutesBetweenDeliveries": 720 }
]
}
consumptionSchedule — its presence is what restricts; an empty object blocks every day:
{
"weekdays": [1, 2, 3, 4, 5],
"includeDates": ["2026-12-24T00:00:00.000Z"],
"excludeDates": ["2026-12-25T00:00:00.000Z"]
}
weekdays runs 0 (Sunday) to 6 (Saturday).
Example:
curl -X POST https://api.inssacs.com/profiles \
-H 'x-api-key: ics_…' -H 'content-type: application/json' \
-d '{
"accountId": "665f0f1c2e8a4b0012a3b4c6",
"businessLine": "vending",
"name": "Subsidio Operarios",
"period": { "type": "preset", "value": "monthly" },
"policy": { "defaultReloadValue": 50000, "maxBalance": 100000, "cumulative": true },
"allowedDevices": ["665f…d1", "665f…d2"]
}'
Editing — 200
PATCH /profiles/:id accepts name, period, consumptionSchedule, allowedDevices, easPolicy
and vendingPolicy. allowedDevices is replaced wholesale: send the final list, not a delta.
Listing
Query: businessLine, isActive, search (name), page, pageSize.
Removal
deactivate / activate → 204. DELETE → 204, but 409 profiles.in_use if the profile has codes
assigned: reassign them first.
Own errors: 404 profiles.not_found, 409 profiles.name_exists,
400 profiles.device_not_in_account, 400 profiles.duplicate_device,
400 profiles.device_business_line_mismatch, 400 profiles.product_not_visible_to_account,
400 profiles.invalid_consumption_schedule, 403 profiles.actor_scope_not_allowed.