# OrbitFlare Customer API - Agent Instructions

> Machine-readable instructions for AI agents and CLI tools to authenticate and interact with the OrbitFlare Customer API.

## Quick Reference

| Field | Value |
|-------|-------|
| Base URL | `https://orbitflare.com/api/customer/v2` |
| Auth Methods | Bearer token (Sanctum) OR `X-ORBIT-KEY` header |
| Response Format | JSON `{ success, message, data }` |
| API Docs | `https://docs.orbitflare.com/api-documentation/welcome` |
| OpenAPI Spec | `https://orbitflare.com/openapi/customer-api.json` |

## Authentication Methods

### Method 1: API Key (Simplest for Agents)

If you already have an OrbitFlare API key, pass it via header:

```bash
curl -H "X-ORBIT-KEY: your-api-key" \
  https://orbitflare.com/api/customer/v2/auth/me
```

API keys can be created in the [OrbitFlare Dashboard](https://orbitflare.com/dashboard/settings/api-keys).

### Method 2: Wallet Signature (Programmatic, No Browser)

Authenticate with a Solana keypair. Ideal for agents with wallet access.

#### Step 1: Request Challenge

```bash
curl -X POST https://orbitflare.com/api/customer/v2/auth/wallet/challenge \
  -H "Content-Type: application/json" \
  -d '{"wallet_address": "YourSolanaPublicKey..."}'
```

**Response:**
```json
{
  "success": true,
  "data": {
    "challenge_id": "<opaque id>",
    "challenge": "OrbitFlare authentication for orbitflare.com\nWallet: <wallet>\nNonce: <nonce>\nIssued at: <timestamp>",
    "expires_in": 300
  }
}
```

#### Step 2: Sign Challenge & Verify

Sign the exact challenge string (including its line breaks) with your Solana keypair (Ed25519), then submit it with the `challenge_id`:

```bash
curl -X POST https://orbitflare.com/api/customer/v2/auth/wallet/verify \
  -H "Content-Type: application/json" \
  -d '{
    "wallet_address": "YourSolanaPublicKey...",
    "challenge_id": "<challenge_id from step 1>",
    "signature": "<base64-or-base58-encoded-signature>"
  }'
```

If the account has two-factor authentication enabled, the response is `401` with `"error": "two_factor_required"`. Send the same request again with `"code"`: the current 6-digit code from the authenticator app, or a backup code. The challenge stays valid for that retry.

**Success Response:**
```json
{
  "success": true,
  "data": {
    "token_type": "Bearer",
    "access_token": "orbit_1|abc123...",
    "expires_in": 2592000,
    "user": {
      "id": 1,
      "name": "Agent User",
      "email": "agent@example.com",
      "wallet_address": "YourSolanaPublicKey...",
      "balance": 0.00
    }
  }
}
```

#### Step 3: Use Bearer Token

```bash
curl -H "Authorization: Bearer orbit_1|abc123..." \
  https://orbitflare.com/api/customer/v2/licenses
```

### Method 3: Wallet Registration (New Account)

Create a new OrbitFlare account from a Solana keypair.

#### Prerequisites

- A Solana keypair
- A valid email address

#### Flow

1. Request challenge (same as Method 2, Step 1)
2. Sign the challenge with your keypair
3. Register:

```bash
curl -X POST https://orbitflare.com/api/customer/v2/auth/wallet/register \
  -H "Content-Type: application/json" \
  -d '{
    "wallet_address": "YourSolanaPublicKey...",
    "signature": "<signature>",
    "name": "My Agent",
    "email": "agent@example.com"
  }'
```

**Success Response:**
```json
{
  "success": true,
  "message": "Account created successfully.",
  "data": {
    "token_type": "Bearer",
    "access_token": "orbit_1|abc123...",
    "expires_in": 2592000,
    "user": { "id": 1, "name": "My Agent", "email": "agent@example.com" },
    "api_key": {
      "name": "Default CLI Key",
      "key": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
    }
  }
}
```

The `api_key.key` value is your `X-ORBIT-KEY` for future requests.

### Method 4: Device Authorization Flow (Browser Required)

For interactive CLI sessions where the user has a browser.

#### Step 1: Request Device Code

```bash
curl -X POST https://orbitflare.com/api/customer/v2/auth/device/code
```

**Response:**
```json
{
  "success": true,
  "data": {
    "device_code": "abc123...",
    "user_code": "ABCD-1234",
    "verification_uri": "https://orbitflare.com/device",
    "expires_in": 900,
    "interval": 5
  }
}
```

#### Step 2: Display to User

Tell the user to open `verification_uri` and enter `user_code`.

#### Step 3: Poll for Token

```bash
curl -X POST https://orbitflare.com/api/customer/v2/auth/device/token \
  -H "Content-Type: application/json" \
  -d '{"device_code": "abc123..."}'
```

Poll every 5 seconds. Responses:

- `428` + `authorization_pending` - Keep polling
- `429` + `slow_down` - Increase interval
- `410` + `expired_token` - Code expired, start over
- `200` + token data - Success

## API Endpoints

### Health Check

```
GET /api/customer/v2/ping
```

### Profile & Balance

```
GET  /api/customer/v2/auth/me      # Current user info
GET  /api/customer/v2/profile      # Detailed profile
PUT  /api/customer/v2/profile      # Update profile {name, payment_wallet_address}
GET  /api/customer/v2/balance      # Account balance
```

### Licenses

```
GET    /api/customer/v2/licenses                              # List all licenses
GET    /api/customer/v2/licenses/{license}                    # License details
POST   /api/customer/v2/licenses/{license}/reset-key          # Reset/reshuffle key
POST   /api/customer/v2/licenses/{license}/regenerate-key     # Regenerate key
POST   /api/customer/v2/licenses/{license}/toggle-auth-mode   # Toggle IP whitelist / API key mode
POST   /api/customer/v2/licenses/{license}/toggle-auto-renewal
GET    /api/customer/v2/licenses/{license}/locations           # Allowed locations
GET    /api/customer/v2/licenses/{license}/ips                 # Whitelisted IPs
POST   /api/customer/v2/licenses/{license}/ips                 # Add IP {ip_address, location_id}
DELETE /api/customer/v2/licenses/{license}/ips                 # Remove IP {ip_address, location_id}
POST   /api/customer/v2/licenses/{license}/domains             # Add domain {domain}
DELETE /api/customer/v2/licenses/{license}/domains             # Remove domain {domain}
POST   /api/customer/v2/licenses/{license}/devnet-domains      # Add devnet domain {domain}
DELETE /api/customer/v2/licenses/{license}/devnet-domains      # Remove devnet domain {domain}
```

### API Keys

```
GET    /api/customer/v2/api-keys                    # List keys (masked)
POST   /api/customer/v2/api-keys                    # Create key {name} → returns full key
GET    /api/customer/v2/api-keys/{id}               # Key details (masked)
PUT    /api/customer/v2/api-keys/{id}               # Update {name?, enabled?}
DELETE /api/customer/v2/api-keys/{id}               # Delete key
POST   /api/customer/v2/api-keys/{id}/regenerate    # Regenerate → returns new full key
POST   /api/customer/v2/api-keys/{id}/ips           # Add IP {ip}
DELETE /api/customer/v2/api-keys/{id}/ips           # Remove IP {ip}
```

### Invoices

```
GET    /api/customer/v2/invoices                              # Paginated list (?per_page=15)
GET    /api/customer/v2/invoices/{reference}                  # Invoice detail (by reference)
POST   /api/customer/v2/invoices/{reference}/pay-with-balance # Pay with account balance
```

## Error Handling

All errors return JSON:

```json
{
  "success": false,
  "message": "Human-readable error description",
  "error": "error_code"
}
```

### HTTP Status Codes

| Code | Meaning |
|------|---------|
| 200 | Success |
| 201 | Created (new resource) |
| 400 | Bad request / validation error |
| 401 | Unauthorized (missing or invalid auth) |
| 403 | Forbidden (no permission) |
| 404 | Not found |
| 409 | Conflict (duplicate) |
| 410 | Gone (expired) |
| 422 | Validation errors |
| 428 | Precondition required (device auth pending) |
| 429 | Rate limited |

### Auth Error Codes

| Error Code | Meaning | Action |
|------------|---------|--------|
| `authorization_pending` | Device not yet authorized | Keep polling |
| `slow_down` | Polling too fast | Increase interval |
| `expired_token` | Device code expired | Request new code |
| `invalid_device_code` | Device code not found | Check code |
| `wallet_not_linked` | No account for wallet | Use /wallet/register |
| `two_factor_required` | Account has 2FA enabled | Resend /wallet/verify with `code` |
| `two_factor_invalid` | Wrong 2FA code | Request a new challenge and retry |
| `two_factor_locked` | Too many wrong 2FA codes | Wait 15 minutes |
| `email_unverified` | Account email not verified | Verify the email from the dashboard |

## Agent Implementation Pseudocode

```
1. CHECK if API key exists in config
   - If yes: use X-ORBIT-KEY header for all requests
   - If no: continue to step 2

2. CHECK if Solana keypair available
   - If yes: use Wallet Signature flow
     a. POST /auth/wallet/challenge {wallet_address}
     b. Sign challenge with keypair
     c. POST /auth/wallet/verify {wallet_address, challenge_id, signature}
        If 401 two_factor_required: ask for the 2FA code, resend with {code}
     d. If 404 (wallet_not_linked): POST /auth/wallet/register (with challenge_id)
     e. Store access_token and api_key in config
   - If no: use Device Authorization flow
     a. POST /auth/device/code
     b. Display verification_uri and user_code to user
     c. Poll POST /auth/device/token every 5s
     d. On success: store access_token in config

3. USE stored credentials for all subsequent requests
   - Prefer X-ORBIT-KEY for long-lived automation
   - Use Bearer token for interactive CLI sessions

4. ON 401 response: re-authenticate (token may have expired)
```

## Rate Limits

- Auth endpoints: 10 requests per minute
- Authenticated endpoints: Standard API rate limits apply
- Device code polling: Minimum 5-second interval enforced

## Signature Verification Details

OrbitFlare uses Ed25519 signature verification for wallet auth:

- **Public key**: Base58-decoded Solana wallet address (32 bytes)
- **Message**: The exact challenge string returned by `/auth/wallet/challenge`
- **Signature**: 64-byte Ed25519 signature, encoded as base64 or base58
- **Verification**: `sodium_crypto_sign_verify_detached(signature, message, publicKey)`

## Support

- Documentation: https://docs.orbitflare.com
- Discord: https://discord.gg/orbitflare
- Email: support@orbitflare.com
