> Searlo API Docs — Account & Utilities
> Source: https://searlo.tech/docs#account
> Full docs: https://searlo.tech/docs/full.md

# Account & Utilities

Your balance, and what this API serves right now. **All free (0 credits)**; each needs your API key, like every other call.

### Endpoints

```
GET /credits/balance
GET /credit/balance
GET /search/capabilities
GET /search/countries
GET /search/states
```

### Credit Balance

`GET /credits/balance` returns the credits available to your account, and nothing else about it. It works with an API key (`x-api-key`, or `Authorization: Bearer sk_...`) and with a dashboard login. It is free, and like any call it counts against your request limits.

```json
{
  "success": true,
  "credits": {
    "available": 2500,
    "reserved": 6,
    "expiresAt": "2027-09-01T10:00:00.000Z",
    "expiringCredits": 2500
  }
}
```

| Field | Description |
|-------|-------------|
| `available` | Credits you can spend now. It is the balance `GET /user/profile` shows (0 while the account is on hold) |
| `reserved` | Present when known: how much of `available` requests still in flight, or awaiting settlement, already hold |
| `expiresAt` / `expiringCredits` | Present when some credits expire: when the next ones do, and how many expire then |

The answer is never cached (`Cache-Control: no-store`).

`GET /credit/balance` is the fuller view: the same balance with a low-balance flag and the expiry of each grant.

```json
{
  "statusCode": 200,
  "data": {
    "balance": 2500,
    "available": 2500,
    "isLowBalance": false,
    "lastUpdated": "2026-09-29T08:12:03.000Z",
    "expiry": {
      "policyApplies": true,
      "durationDays": 365,
      "totalExpiringAmount": 2500,
      "nonExpiringAmount": 0,
      "nextExpiryAt": "2027-09-01T10:00:00.000Z",
      "daysUntilNextExpiry": 336,
      "nextExpiryAmount": 2500,
      "breakdown": [
        { "sourceType": "purchase", "amount": 2500, "grantedAt": "2026-09-01T10:00:00.000Z", "expiresAt": "2027-09-01T10:00:00.000Z", "daysRemaining": 336, "status": "active" }
      ]
    }
  },
  "message": "Credit balance retrieved successfully",
  "success": true
}
```

| Field | Description |
|-------|-------------|
| `available` | Credits you can spend now (`balance` is the same number) |
| `isLowBalance` | Below the low-balance threshold (100 credits by default) |
| `expiry.nextExpiryAt` / `nextExpiryAmount` | When credits next expire, and how many expire then |
| `expiry.breakdown` | Each purchase or grant still holding credits, soonest expiry first |

Every metered response also carries `X-Credits-Deducted` and `X-Credits-Remaining`, so a client rarely needs to poll this.

### Capabilities

`GET /search/capabilities` lists every endpoint this deployment serves, what it costs, whether it is switched on, and how it has done over the last two hours. Read it instead of hard-coding which endpoints are available: a switched-off endpoint answers `403` `FEATURE_NOT_AVAILABLE` (not charged), and this tells you before you pay the round trip.

```json
{
  "success": true,
  "generatedAt": "2026-09-29T17:20:00.000Z",
  "capabilities": [
    {
      "id": "serp/html",
      "method": "GET",
      "path": "/serp/html",
      "credits": 2,
      "creditsNote": "per page; 8 with js=true (rendered, AI Overview opened out)",
      "group": "google",
      "enabled": true,
      "state": "live",
      "health": { "window": "2h", "ok": 412, "fail": 6, "successRate": 0.99 }
    },
    {
      "id": "backlinks",
      "method": "GET",
      "path": "/backlinks",
      "credits": 0,
      "group": "backlinks",
      "enabled": false,
      "reason": "No backlink provider is bound to this deployment. The endpoints answer 501 rather than returning synthesised link data.",
      "state": "off",
      "health": { "window": "2h", "ok": 0, "fail": 0, "successRate": null }
    }
  ],
  "states": { "live": "serving", "degraded": "on, but most recent calls failed", "off": "switched off here" }
}
```

`state` is `off` when the endpoint is switched off (`reason` says why), `degraded` when at least 3 calls in the window and fewer than half of them succeeded, and `live` otherwise. `successRate` is a fraction (0–1), `null` with no calls in the window. The response may be cached for 30 seconds.

### Countries and States

`GET /search/countries` lists the countries the AI answer endpoints accept as `gl`. The search endpoints accept any two-letter `gl`, applied as the results country.

```json
{
  "success": true,
  "engine": "all",
  "countries": [
    { "code": "US", "name": "United States", "states": true, "exit": true },
    { "code": "GB", "name": "United Kingdom", "states": false, "exit": true }
  ]
}
```

`GET /search/states` lists the US states with Google's name and `uule` token for each. **State- and city-level location is not available yet** ([Location](#full-serp)): the response says `targeting: false`, and a state passed as `location` or `uule` returns `400` `CITY_LOCATION_UNAVAILABLE`. Only `country=US` is available; any other country returns `400`.

```json
{
  "success": true,
  "country": "US",
  "exitPinning": false,
  "targeting": false,
  "message": "State- and city-level location is not available yet: a state passed as location returns 400 CITY_LOCATION_UNAVAILABLE. Country (gl) and language (hl) are applied.",
  "states": [
    { "code": "TX", "name": "Texas", "location": "Texas,United States", "uule": "w+CAIQICIT..." }
  ]
}
```

`exitPinning: false`: results are not localized to the state.

## Code Examples

### cURL

```bash
curl "https://api.searlo.tech/api/v1/credits/balance" \
  -H "x-api-key: sk_your_api_key"

curl "https://api.searlo.tech/api/v1/credit/balance" \
  -H "x-api-key: sk_your_api_key"

curl "https://api.searlo.tech/api/v1/search/capabilities" \
  -H "x-api-key: sk_your_api_key"
```

### JavaScript

```javascript
const headers = { "x-api-key": process.env.SEARLO_API_KEY };
const res = await fetch("https://api.searlo.tech/api/v1/search/capabilities", { headers });
const { capabilities } = await res.json();

// Only call what is on here right now
const live = new Set(capabilities.filter(c => c.state !== "off").map(c => c.path));
console.log(live.has("/serp/html"));
```

### Python

```python
import os
import requests

HEADERS = {"x-api-key": os.environ["SEARLO_API_KEY"]}
balance = requests.get("https://api.searlo.tech/api/v1/credits/balance", headers=HEADERS).json()
print(balance["credits"]["available"], balance["credits"].get("expiresAt"))
```


---
*From https://searlo.tech/docs — see full docs at https://searlo.tech/docs/full.md*