
# Utils tools

Six in-process crypto/encoding primitives on Node's built-in [`crypto`](https://nodejs.org/api/crypto.html) and [`jose`](https://github.com/panva/jose) — the same open-source libraries you could run yourself. Every op is a `POST https://api.relaystation.ai/v1/utils/<op>`. These return a small **JSON object** (a hash, a list of UUIDs, a verification result) — there is no file output.

## Inputs

`hash`, `hmac`, and `base64` take bytes; the rest take a string. The byte-taking ops accept **either** an inline `data` string **or** a `file` input source — `{ "inline": "<base64>" }` (≤ 4 MB) or `{ "inputKey": "..." }` (from `POST /v1/cputools/upload-url`, ≤ 50 MB) — exactly one. Secret inputs (the `hmac` key, the `jwt-verify` key) ride only in the request body and are **never logged** and never echoed in an error.

## Billing

`hash`, `hmac`, `base64` bill **per MB of input** (min 1 MiB) at `cputools.price.utils.<op>.per_mb_micros` (launch default $0.0002 / MB). `uuid`, `jwt-decode`, `jwt-verify` are **flat** at `cputools.price.utils.<op>.flat_micros` (launch default $0.0001 / call). The live `402` challenge is authoritative.

| Op | Billed on | Rate |
|---|---|---|
| `hash` | input MB | $0.0002 / MB |
| `hmac` | input MB | $0.0002 / MB |
| `base64` | input MB | $0.0002 / MB |
| `uuid` | per call | $0.0001 flat |
| `jwt-decode` | per call | $0.0001 flat |
| `jwt-verify` | per call | $0.0001 flat |

## hash

Hash bytes with `sha256`, `sha512`, `sha1`, or `md5`. Returns `{ algo, hash: <hex> }`. (`sha1`/`md5` are offered for legacy checksum compatibility.)

```json
POST /v1/utils/hash
{ "data": "hello", "algo": "sha256" }
```

## hmac

Keyed HMAC over the same algorithms. Returns `{ algo, hmac: <hex> }`. The `key` is never logged.

```json
POST /v1/utils/hmac
{ "data": "hello", "key": "<secret>", "algo": "sha256" }
```

## uuid

Generate v4 UUIDs. `count` defaults to 1 and is capped at `cputools.utils.uuid.max_count` (default 1000). Returns `{ uuids: [...] }`.

```json
POST /v1/utils/uuid
{ "count": 5 }
```

## jwt-decode

Decode a JWT's header + payload **without verifying the signature** (jose). Returns `{ header, payload }`. A malformed token → `422 JWT_MALFORMED`.

```json
POST /v1/utils/jwt-decode
{ "token": "<jwt>" }
```

## jwt-verify

Verify a JWT signature, **pinned to the declared `alg`** — this blocks the alg-confusion / `alg:none` downgrade (`none` is not an accepted algorithm). `alg` is one of `HS256/384/512`, `RS256/384/512`, `ES256/384`. A valid-shape token that fails verification is a **paid answer** (`200 { valid: false, reason }`) — you paid to learn validity; only an unparseable token (`422 JWT_MALFORMED`) or an unimportable key (`422 JWT_KEY_INVALID`) is an error. The `key` is never logged.

```json
POST /v1/utils/jwt-verify
{ "token": "<jwt>", "key": "<secret-or-PEM>", "alg": "HS256" }
```

## base64

Encode or decode a string. Returns `{ data: <result> }`.

```json
POST /v1/utils/base64
{ "data": "hello", "mode": "encode" }
```

## Sample

```bash
curl -X POST https://api.relaystation.ai/v1/utils/hash \
  -H 'X-Payment: <base64 EIP-3009 auth>' \
  -H 'Idempotency-Key: hash-manifest-20260609' \
  -H 'Content-Type: application/json' \
  -d '{"data":"hello","algo":"sha256"}'
```

## Errors

- `402 PAYMENT_REQUIRED` — no valid payment.
- `422 JWT_MALFORMED` — the token isn't a well-formed JWT (jwt-decode / jwt-verify).
- `422 JWT_KEY_INVALID` — the jwt-verify key couldn't be imported for the declared `alg` (the key bytes are never echoed).
- `422 COUNT_TOO_LARGE` — `uuid` count over the cap. Rejected **before** any charge.
- `400 VALIDATION_ERROR` — the body failed schema validation (e.g. neither/both of `data`/`file`, or `alg: "none"`).

## Next

[PDF tools](/docs/pdf-tools) · [CSV tools](/docs/csv-tools) · [Image tools](/docs/image-tools) · [Generate tools](/docs/generate-tools) · [Archive tools](/docs/archive-tools) · [Pricing](/pricing) · [API reference](/api-reference)
