# Raw API (No SDK)

TherosAI's REST API works with any HTTP client. No SDK is required. This page covers the essentials for provisioning vaults, enforcing spending policy, and settling payments from any language or framework.

***

## Base URL

```
https://api.therosai.com/v1
```

***

## Authentication

Pass your API key as a Bearer token in every request:

```
Authorization: Bearer <your-api-key>
```

***

## Content type

All request bodies use `application/json`. All responses are `application/json`.

***

## Minimal integration example

The following example — using plain `curl` — provisions a vault, funds it from the organisation reserve, and sends a payment.

### Step 1: Create a spending policy

```bash
curl -X POST https://api.therosai.com/v1/policies \
  -H "Authorization: Bearer $THEROS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Standard Policy",
    "maxPerTx": "10.00",
    "maxPerDay": "100.00",
    "velocityCap": 50
  }'
```

Note the `policy_id` from the response.

### Step 2: Provision a vault

```bash
curl -X POST https://api.therosai.com/v1/wallets \
  -H "Authorization: Bearer $THEROS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agentId": "my-agent-001",
    "label": "My Agent",
    "policyId": "pol_..."
  }'
```

Note the `wallet_id` and `solana_address` from the response — this is your agent's on-chain vault address.

### Step 3: Fund the vault

```bash
curl -X POST https://api.therosai.com/v1/wallets/wal_.../fund \
  -H "Authorization: Bearer $THEROS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "amount": "50.00", "currency": "USDC" }'
```

### Step 4: Send a payment

```bash
curl -X POST https://api.therosai.com/v1/payments \
  -H "Authorization: Bearer $THEROS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "walletId": "wal_...",
    "to": "api.perplexity.ai",
    "amount": "2.50",
    "currency": "USDC",
    "memo": "Query batch #1"
  }'
```

***

## Idempotency

For any state-changing request (payments, funding, wallet creation), pass a unique `idempotencyKey` in the request body to safely retry on failure:

```json
{
  "walletId": "wal_...",
  "to": "api.perplexity.ai",
  "amount": "2.50",
  "currency": "USDC",
  "idempotencyKey": "my-unique-key-001"
}
```

If a request with the same key has already succeeded, the original response is returned instead of re-processing.

***

## Pagination

List endpoints return a cursor-paginated response:

```json
{
  "data": [ /* items */ ],
  "has_more": true,
  "next_cursor": "cursor_abc123"
}
```

Fetch the next page by passing `cursor=cursor_abc123` as a query parameter.

***

## Webhook verification (raw implementation)

Compute HMAC-SHA256 of the raw request body using your webhook signing secret and compare to the `Theros-Signature` header:

```python
import hmac
import hashlib

def verify_signature(raw_body: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode("utf-8"),
        raw_body,
        hashlib.sha256,
    ).hexdigest()
    return hmac.compare_digest(expected, signature)
```

```go
func verifySignature(rawBody []byte, signature, secret string) bool {
    mac := hmac.New(sha256.New, []byte(secret))
    mac.Write(rawBody)
    expected := hex.EncodeToString(mac.Sum(nil))
    return hmac.Equal([]byte(expected), []byte(signature))
}
```

```rust
use hmac::{Hmac, Mac};
use sha2::Sha256;

fn verify_signature(raw_body: &[u8], signature: &str, secret: &str) -> bool {
    let mut mac = Hmac::<Sha256>::new_from_slice(secret.as_bytes()).unwrap();
    mac.update(raw_body);
    let result = hex::encode(mac.finalize().into_bytes());
    result == signature
}
```

***

## Error format

All errors follow a consistent JSON structure:

```json
{
  "error": {
    "code": "policy_violation",
    "message": "Transaction blocked by spending policy.",
    "docs": "https://docs.therosai.com/api-reference/errors#policy_violation",
    "request_id": "req_7f3b2a1c"
  }
}
```

→ See [Errors](/api-reference/errors.md) for the full error code catalogue.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.therosai.com/integrations/raw-api.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
