# Check your workspace from code: Koltrix API health, domains and usage

> Four read-only Koltrix API calls tell a script which workspace a key belongs to, whether it can send, if domains are ready and how close you are to limits.

- Published: 2026-10-25
- Author: Koltrix Team
- Category: Email API
- Source: https://koltrix.com/blog/check-your-koltrix-workspace-from-code-health-domains-and-usage

Most email problems in an application show up late. A domain record gets removed during a DNS cleanup, a workspace slips into read-only mode after a payment issue, or a monthly send limit is reached on the busiest day. Your code only finds out when a customer asks why the receipt never came.

The Koltrix REST API has a few small read-only calls that let your own code ask these questions first. This post walks through each one, what it returns, and a simple routine that turns them into a health check you can run on a schedule.

## What you can ask

All of these live under `https://api.koltrix.com/api/v2` and use the same API key as sending. Send it as a bearer token: `Authorization: Bearer kx_…`.

| Call | What it tells you | Scope needed |
|---|---|---|
| `GET /me` | Which workspace the key belongs to, its plan and whether it can send | Any valid key |
| `GET /domains` | For each sending domain, whether MX, SPF, DKIM and DMARC are confirmed | `read` |
| `GET /usage` | How much of the plan is used: storage, sends, AI actions, mailboxes, seats | `read` |
| `GET /templates` | The workspace's saved templates, and `GET /templates/:id` for one | `read` |

None of them change anything. The full field list is in the [API reference](https://docs.koltrix.com/authentication) and the key and scope rules are on the same page.

## Call one: who am I?

`GET /me` is the cheapest check there is, and it works with any valid key.

```bash
curl https://api.koltrix.com/api/v2/me \
  -H "Authorization: Bearer $KOLTRIX_API_KEY"
```

```json
{
  "tenant": "acme",
  "permissions": ["read", "send"],
  "id": "0d3f6a52-91c4-4b7e-8e2a-6f1b3c9d4a10",
  "name": "Acme",
  "plan": "growth",
  "read_only_reason": ""
}
```

Three fields matter most:

- **`tenant`** is the workspace's short name. A key belongs to exactly one workspace, so this answers the question "did I paste the staging key into production?" before you send anything.
- **`permissions`** lists the key's scopes. If your health check needs `read` and the key only has `send`, you find out here with a clear message rather than a confusing 403 later.
- **`read_only_reason`** is empty when the workspace can send. If it holds a value, the workspace cannot send right now, and the text says why. Treat anything non-empty as an alert, because every send will fail until someone fixes the plan.

If you run more than one workspace, make one key in each. The `tenant` in the response tells you which is which. The same one-workspace rule applies to AI assistants, as described in [two workspaces in Claude](/blog/two-workspaces-in-claude-one-koltrix-connector-for-each).

## Call two: are my domains ready?

`GET /domains` lists the workspace's sending domains.

```json
{
  "data": [
    {
      "domain": "acme.com",
      "ready": true,
      "mx": true,
      "spf": true,
      "dkim": true,
      "dmarc": true,
      "last_checked_at": "2026-10-22T08:00:00Z"
    }
  ]
}
```

`ready` is true when the domain can send and receive. The four booleans show which record is missing when it is not. A check that loops through `data` and alerts on any `ready: false` catches the most common silent failure: someone edited DNS and a record disappeared.

Two habits make this more useful:

1. **Alert on the specific record.** "acme.com: dkim missing" is something a person can fix in a minute. "A domain is not ready" is not.
2. **Look at `last_checked_at`.** If it is old, the status may be stale. Treat a very old timestamp as a warning on its own.

When a record is missing, the background in [domain verification flows](/blog/domain-verification-flows-checking-dns-and-explaining-failures) explains how to word the message so the right person can act on it.

## Call three: how close am I to the limits?

`GET /usage` shows how much of the plan the workspace has used.

```json
{
  "plan": "growth",
  "trial": false,
  "storage": { "used": 1288490188, "limit": 53687091200, "percent": 2 },
  "api_sends_monthly": { "used": 3120, "limit": 50000, "window": "month", "percent": 6 },
  "mailboxes": { "used": 4, "limit": 10, "percent": 40 },
  "seats": { "used": 3, "limit": 5, "percent": 60 }
}
```

Each figure has `used`, `limit` and `percent`, and the sending figures also have a `window` (a day or a month). Two details to handle in code:

- **A `limit` of `-1` means unlimited.** Check for it before you divide, or you will report nonsense percentages.
- **`trial` tells you the workspace is still on a trial.** A trial workspace is the one most likely to hit a wall, so it deserves a lower alert threshold.

A reasonable rule is a warning at 80 percent and an alert at 95 percent, using the `percent` field the API already gives you. Warn early enough that a person can add capacity or clean up before it matters. For what to do when a send is refused by a limit, see [handling 429 errors](/blog/email-api-rate-limits-429).

## Call four: are my templates there?

`GET /templates` returns the saved templates, with `name`, `category`, `subject`, `body_html`, `body_text` and timestamps, and `GET /templates/:id` returns one. This is useful in two places:

- **A deploy check.** If your application expects a template named "Pricing question" and it is missing, you want to know before a customer replies.
- **A backup.** The response contains the full text, so a nightly job can save it to your own storage.

Pass a malformed id to `/templates/:id` and you get a 404, not a server error, so a bad id from a stale config is easy to recognize.

## Putting it together: a small health check

Here is a shell sketch that combines the first three calls. It prints one line per problem and exits non-zero when something needs attention, so a scheduler or a monitoring tool can act on it.

```bash
#!/usr/bin/env bash
set -u
api=https://api.koltrix.com/api/v2
auth="Authorization: Bearer $KOLTRIX_API_KEY"
bad=0

me=$(curl -sf -H "$auth" "$api/me") || { echo "me: request failed"; exit 2; }
[ -n "$(echo "$me" | jq -r .read_only_reason)" ] && { echo "workspace is read-only: $(echo "$me" | jq -r .read_only_reason)"; bad=1; }

curl -sf -H "$auth" "$api/domains" | jq -r '.data[] | select(.ready|not) | "domain not ready: \(.domain)"' | grep . && bad=1

curl -sf -H "$auth" "$api/usage" | jq -r 'to_entries[] | select(.value|type=="object" and .percent != null) | select(.value.limit != -1 and .value.percent >= 90) | "usage \(.key) at \(.value.percent)%"' | grep . && bad=1

exit $bad
```

Run it every hour from a scheduler, and send the output to wherever your team already looks. Keep the key in a secret store, and give it only the scopes it needs. A key for this job needs `read` and nothing more, which is the principle behind [API key security](/blog/email-api-key-security).

## What this does not do

It is worth being clear about the limits of these calls.

- **They do not send mail.** Sending is a separate call with the `send` scope, and it should always carry an idempotency key, as covered in [idempotency keys for email sends](/blog/idempotency-keys-email-sends).
- **They do not prove a message arrived.** A ready domain means your records are in place, not that a particular message reached an inbox. For delivery of one message, read the message log and its events.
- **They show the workspace, not other workspaces.** One key sees one workspace.

## A short checklist

1. Make a key with only the `read` scope for monitoring.
2. Call `/me` first, and check `tenant`, `permissions` and `read_only_reason`.
3. Loop through `/domains` and alert on the exact record that is missing.
4. Read `/usage`, handle a `limit` of `-1`, and warn before 100 percent.
5. Check that the templates your code depends on still exist.
6. Run the check on a schedule and send failures to a place people read.
7. Keep the key in a secret store and rotate it if it leaks.

## Key takeaways

A few read-only calls give your own code the same view a person gets in the Koltrix settings: who the key is, whether the workspace can send, whether each domain is ready and how much of the plan is left. Check them on a schedule, alert on the specific problem and give the monitoring key only the `read` scope. You will hear about a lost DNS record or a nearly full limit from your own script, not from a customer.
