Get started
Authentication
Sign in once for a bearer token, send it with every request, and sign in again when it expires.
The API authenticates users, not applications: your integration signs in with the email and password of a HoundSat user and gets a bearer token. Every request then acts as that user, with that user's role and organization, exactly as if they were using the dashboard.
Use an integration user
Give each integration its own user rather than a person's account, so a teammate leaving or changing their password never breaks it:
- In the dashboard (or with Invite a user), invite an address your team controls, such as
integrations@yourcompany.com. - Pick the lowest role that does the job: Staff to read devices, usage and messages; Admin to also import, activate and manage.
- Accept the invite, set a long random password, and keep it in your secrets manager.
Sign in
Send the email and password to POST /api/auth/sign_in. The answer holds the token and the user it belongs to.
curl -X POST https://api.houndsat.com/api/auth/sign_in \
-H "Content-Type: application/json" \
-d '{"email": "integrations@acme.example", "password": "…"}'{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…",
"user": {
"id": "b5e1f3a9-7d2c-4e08-96b4-0c3a8f6d2e71",
"email": "integrations@acme.example",
"name": "Fleet sync",
"role": "admin",
"invite_status": "active",
"organization_id": "a7d35c90-2e14-4f6b-8c03-5b9e1d4a2f67",
"organization_level": "reseller"
}
}A wrong password, an unknown email, a deactivated user and a suspended organization all answer the same 401 invalid_credentials, so the answer never reveals which accounts exist.
Send the token
Put the token in the Authorization header of every request:
curl https://api.houndsat.com/api/json/devices \
-H "Authorization: Bearer $HOUNDSAT_TOKEN"Keep the token on your servers. Anyone holding it can act as the integration user until it expires or is revoked.
Token lifetime
A token is valid for 14 days. It stops working earlier when:
- you sign out with it (
POST /api/auth/sign_out); - the user's password is reset, or the user is deactivated;
- the user's organization, or its reseller, is suspended.
Cache the token and reuse it, and sign in again before it expires: every 7 days is a good rhythm.
HTTP/1.1 401 Unauthorized
content-type: application/json
{"error": "unauthenticated", "message": "Your session has ended or is invalid. Sign in again to continue."}Check a token
GET /api/me returns the user behind a token, their organization and what they are allowed to do. It's a cheap way to check a token at start-up and to learn your organization's id.
{
"user": { "id": "b5e1f3a9-…", "role": "admin", "organization_level": "reseller", … },
"organization": {
"id": "a7d35c90-2e14-4f6b-8c03-5b9e1d4a2f67",
"name": "Acme Connect",
"level": "reseller",
"parent_id": "…",
"status": "active"
},
"permissions": {
"devices.import": true,
"devices.manage": true,
"devices.assign": true,
"organizations.create_child": true,
"users.invite": true,
"messages.retry": true,
…
},
…
}Roles and scope
Every user has one role in one organization:
| Role | Can |
|---|---|
| Owner | Everything an Admin can, plus pay invoices and delete the organization. One per organization. |
| Admin | Manage users, devices, plans, invoices and webhook endpoints, and retry failed deliveries. |
| Staff | Read devices, usage, messages and users. Never sees prices, costs or invoices, and can't change anything. |
A user sees their own organization and everything below it: a reseller user sees all of the reseller's customers, a customer user only their own organization. Records outside that scope answer 404, as if they didn't exist. Each endpoint in the API reference lists who may call it.