# TrustTrade Device Valuation API

- **OpenAPI Version:** `3.1.0`
- **API Version:** `2.0.0`

Real-time Apple device valuations for K-12 IT asset management. Price any Apple Silicon Mac or iPad by SKU, Apple model identifier, or raw MDM payload.

## Authentication

All endpoints except `/health` require authentication. The API uses two auth methods:

- **API Key** (for device valuation endpoints) — pass via `X-API-Key` or `Authorization: Bearer`
- **Session Token** (for account management) — JWT from `/auth/login`, pass via `Authorization: Bearer`

## Credits

Device lookups consume credits from your account balance (1,000 free on registration).

| Endpoint              | Cost                                       |
| --------------------- | ------------------------------------------ |
| `GET /devices/{id}`   | 1 credit                                   |
| `POST /devices/batch` | `ceil(uniqueDevicesResolved / 10)` credits |

## Rate Limits

Sliding 60-second window per API key: **10 requests/min** (free tier). Keys with `allowed_origins` also enforce **60 requests/min per client IP**.

Response headers on every authenticated request:

- `X-RateLimit-Limit` — requests allowed per window
- `X-RateLimit-Remaining` — requests remaining
- `X-RateLimit-Reset` — Unix timestamp when window resets

## Servers

- **URL:** `https://api.trusttrade.com/v1`
  - **Description:** Production

## Operations

### Health check

- **Method:** `GET`
- **Path:** `/health`
- **Tags:** Health

Returns API health status. No authentication required.

#### Responses

##### Status: 200 API is healthy

###### Content-Type: application/json

- **`status` (required)**

  `string`

- **`timestamp` (required)**

  `string`, format: `date-time`

- **`version` (required)**

  `string`

**Example:**

```json
{
  "status": "",
  "version": "",
  "timestamp": ""
}
```

### Single device lookup

- **Method:** `GET`
- **Path:** `/devices/{id}`
- **Tags:** Devices

Look up a single device by identifier. Accepts SKU format, Apple model identifier, or MDM model identifier. All lookups are case-insensitive. Costs 1 credit.

#### Responses

##### Status: 200 Device valuation

###### Content-Type: application/json

- **`confidence` (required)**

  `string`, possible values: `"high", "medium", "low"`

- **`currency` (required)**

  `string`, default: `"USD"`

- **`currentValuation` (required)**

  `object`

  - **`excellent` (required)**

    `number` — Best-case value (USD)

  - **`fair` (required)**

    `number` — Conservative estimate (USD)

  - **`good` (required)**

    `number` — Mid-market value (USD)

- **`deviceId` (required)**

  `string`

- **`displayName` (required)**

  `string`

- **`validUntil` (required)**

  `string`, format: `date-time` — Pricing data freshness (24-hour cache)

- **`depreciation`**

  `object`

  - **`confidence` (required)**

    `string`, possible values: `"high", "medium", "low"`

  - **`projection` (required)**

    `object`

    - **`excellent` (required)**

      `number`

    - **`fair` (required)**

      `number`

    - **`good` (required)**

      `number`

    - **`months` (required)**

      `integer`

  - **`refreshSignal` (required)**

    `string`, possible values: `"hold", "considerRefreshing", "refreshNow"` — - \`hold\` — device retains strong value - \`considerRefreshing\` — approaching optimal trade-in window - \`refreshNow\` — past optimal trade-in window

  - **`trend` (required)**

    `string`, possible values: `"stable", "increasing", "decreasing"`

- **`msrp`**

  `number` — Original retail price (USD)

- **`residualPct`**

  `number` — Percentage of MSRP retained (good / msrp x 100)

- **`valueTier`**

  `string`, possible values: `"Peak", "Strong", "Moderate", "Low"`

**Example:**

```json
{
  "deviceId": "",
  "displayName": "",
  "currentValuation": {
    "fair": 1,
    "good": 1,
    "excellent": 1
  },
  "msrp": 1,
  "residualPct": 1,
  "valueTier": "Peak",
  "depreciation": {
    "trend": "stable",
    "projection": {
      "months": 1,
      "fair": 1,
      "good": 1,
      "excellent": 1
    },
    "refreshSignal": "hold",
    "confidence": "high"
  },
  "currency": "USD",
  "confidence": "high",
  "validUntil": ""
}
```

##### Status: 401 Missing or invalid authentication

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code

  - **`message` (required)**

    `string` — Human-readable description

  - **`details`**

    `object` — Additional error context (e.g. validation issues)

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "details": {}
  }
}
```

##### Status: 402 No credits remaining

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code

  - **`message` (required)**

    `string` — Human-readable description

  - **`details`**

    `object` — Additional error context (e.g. validation issues)

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "details": {}
  }
}
```

##### Status: 403 Origin header missing or not in allowed list

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code

  - **`message` (required)**

    `string` — Human-readable description

  - **`details`**

    `object` — Additional error context (e.g. validation issues)

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "details": {}
  }
}
```

##### Status: 404 Device not found

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code

  - **`message` (required)**

    `string` — Human-readable description

  - **`details`**

    `object` — Additional error context (e.g. validation issues)

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "details": {}
  }
}
```

##### Status: 429 Rate limit exceeded

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code

  - **`message` (required)**

    `string` — Human-readable description

  - **`details`**

    `object` — Additional error context (e.g. validation issues)

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "details": {}
  }
}
```

##### Status: 503 Pricing data temporarily unavailable

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code

  - **`message` (required)**

    `string` — Human-readable description

  - **`details`**

    `object` — Additional error context (e.g. validation issues)

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "details": {}
  }
}
```

### Batch device valuation

- **Method:** `POST`
- **Path:** `/devices/batch`
- **Tags:** Devices

Value multiple devices in one request. Supports three input formats per item:

- **String**: device ID with quantity 1
- **Object with id**: device ID with explicit quantity
- **MDM payload**: raw MDM device data with auto-normalization

Server deduplicates by normalized device ID and sums quantities. Costs `ceil(uniqueDevicesResolved / 10)` credits.

#### Request Body

##### Content-Type: application/json

- **`devices` (required)**

  `array`

  **Items:**

  **One of:**

  `string` — Device ID (quantity = 1)

  - **`id` (required)**

    `string`

  - **`qty`**

    `integer`, default: `1`

  * **`deviceModelIdentifier` (required)**

    `string` — Apple model identifier (e.g. \`mac14,2\`)

  * **`stats` (required)**

    `object`

    - **`memoryTotalGB` (required)**

      `number` — Reported RAM in GB (e.g. 8.5 normalizes to 8GB)

    - **`storageTotalGB` (required)**

      `number` — Reported storage in GB (e.g. 243.8 normalizes to 256GB)

  * **`cpuModelName`**

    `string`

  * **`deviceModelName`**

    `string`

  * **`qty`**

    `integer`, default: `1`

**Example:**

```json
{
  "devices": [
    ""
  ]
}
```

#### Responses

##### Status: 200 Batch valuation results

###### Content-Type: application/json

- **`currency` (required)**

  `string`, default: `"USD"`

- **`results` (required)**

  `array`

  **Items:**

  - **`currentValuation` (required)**

    `object`

    - **`excellent` (required)**

      `number` — Best-case value (USD)

    - **`fair` (required)**

      `number` — Conservative estimate (USD)

    - **`good` (required)**

      `number` — Mid-market value (USD)

  - **`deviceId` (required)**

    `string`

  - **`displayName` (required)**

    `string`

  - **`quantity` (required)**

    `integer`

  - **`depreciation`**

    `object`

    - **`confidence` (required)**

      `string`, possible values: `"high", "medium", "low"`

    - **`projection` (required)**

      `object`

      - **`excellent` (required)**

        `number`

      - **`fair` (required)**

        `number`

      - **`good` (required)**

        `number`

      - **`months` (required)**

        `integer`

    - **`refreshSignal` (required)**

      `string`, possible values: `"hold", "considerRefreshing", "refreshNow"` — - \`hold\` — device retains strong value - \`considerRefreshing\` — approaching optimal trade-in window - \`refreshNow\` — past optimal trade-in window

    - **`trend` (required)**

      `string`, possible values: `"stable", "increasing", "decreasing"`

  - **`msrp`**

    `number`

  - **`residualPct`**

    `number`

  - **`valueTier`**

    `string`, possible values: `"Peak", "Strong", "Moderate", "Low"`

- **`summary` (required)**

  `object`

  - **`confidence` (required)**

    `string`, possible values: `"high", "medium", "low"`

  - **`itemsReceived` (required)**

    `integer`

  - **`totalCurrentValue` (required)**

    `number` — Sum of good-condition values across all units

  - **`totalUnits` (required)**

    `integer`

  - **`uniqueDevicesResolved` (required)**

    `integer`

  - **`projectedValue`**

    `object`

    - **`months`**

      `integer`

    - **`percentChange`**

      `number`

    - **`total`**

      `number`

  - **`refreshBreakdown`**

    `object`

    - **`considerRefreshing`**

      `integer`

    - **`hold`**

      `integer`

    - **`refreshNow`**

      `integer`

- **`validUntil` (required)**

  `string`, format: `date-time`

- **`unmatched`**

  `array`

  **Items:**

  - **`input` (required)**

    `string` — The original identifier that could not be resolved

  - **`reason` (required)**

    `string`, possible values: `"not_found", "invalid_identifier", "no_pricing", "unsupported_model", "virtual_machine", "unknown_model"`

  - **`suggestions`**

    `array`

    **Items:**

    `string`

**Example:**

```json
{
  "results": [
    {
      "deviceId": "",
      "displayName": "",
      "quantity": 1,
      "currentValuation": {
        "fair": 1,
        "good": 1,
        "excellent": 1
      },
      "msrp": 1,
      "residualPct": 1,
      "valueTier": "Peak",
      "depreciation": {
        "trend": "stable",
        "projection": {
          "months": 1,
          "fair": 1,
          "good": 1,
          "excellent": 1
        },
        "refreshSignal": "hold",
        "confidence": "high"
      }
    }
  ],
  "unmatched": [
    {
      "input": "",
      "reason": "not_found",
      "suggestions": [
        ""
      ]
    }
  ],
  "summary": {
    "itemsReceived": 1,
    "uniqueDevicesResolved": 1,
    "totalUnits": 1,
    "totalCurrentValue": 1,
    "projectedValue": {
      "months": 1,
      "total": 1,
      "percentChange": 1
    },
    "refreshBreakdown": {
      "hold": 1,
      "considerRefreshing": 1,
      "refreshNow": 1
    },
    "confidence": "high"
  },
  "currency": "USD",
  "validUntil": ""
}
```

##### Status: 400 Malformed request body

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code

  - **`message` (required)**

    `string` — Human-readable description

  - **`details`**

    `object` — Additional error context (e.g. validation issues)

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "details": {}
  }
}
```

##### Status: 401 Missing or invalid authentication

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code

  - **`message` (required)**

    `string` — Human-readable description

  - **`details`**

    `object` — Additional error context (e.g. validation issues)

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "details": {}
  }
}
```

##### Status: 402 No credits remaining

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code

  - **`message` (required)**

    `string` — Human-readable description

  - **`details`**

    `object` — Additional error context (e.g. validation issues)

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "details": {}
  }
}
```

##### Status: 403 Origin header missing or not in allowed list

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code

  - **`message` (required)**

    `string` — Human-readable description

  - **`details`**

    `object` — Additional error context (e.g. validation issues)

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "details": {}
  }
}
```

##### Status: 422 Request body failed schema validation

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code

  - **`message` (required)**

    `string` — Human-readable description

  - **`details`**

    `object` — Additional error context (e.g. validation issues)

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "details": {}
  }
}
```

##### Status: 429 Rate limit exceeded

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code

  - **`message` (required)**

    `string` — Human-readable description

  - **`details`**

    `object` — Additional error context (e.g. validation issues)

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "details": {}
  }
}
```

##### Status: 503 Pricing data temporarily unavailable

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code

  - **`message` (required)**

    `string` — Human-readable description

  - **`details`**

    `object` — Additional error context (e.g. validation issues)

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "details": {}
  }
}
```

### Register a developer account

- **Method:** `POST`
- **Path:** `/auth/register`
- **Tags:** Auth

Create a new developer account. A verification email is sent automatically. You must verify your email before logging in. New accounts receive 1,000 free credits.

#### Request Body

##### Content-Type: application/json

- **`email` (required)**

  `string`, format: `email`

- **`password` (required)**

  `string`

- **`company_name`**

  `string`

- **`use_case`**

  `string`

**Example:**

```json
{
  "email": "",
  "password": "",
  "company_name": "",
  "use_case": ""
}
```

#### Responses

##### Status: 201 Account created

###### Content-Type: application/json

- **`developer_id` (required)**

  `string`, format: `uuid`

- **`message` (required)**

  `string`

**Example:**

```json
{
  "message": "",
  "developer_id": ""
}
```

##### Status: 409 Email already registered

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code

  - **`message` (required)**

    `string` — Human-readable description

  - **`details`**

    `object` — Additional error context (e.g. validation issues)

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "details": {}
  }
}
```

##### Status: 422 Request body failed schema validation

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code

  - **`message` (required)**

    `string` — Human-readable description

  - **`details`**

    `object` — Additional error context (e.g. validation issues)

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "details": {}
  }
}
```

### Log in

- **Method:** `POST`
- **Path:** `/auth/login`
- **Tags:** Auth

Sign in with email and password. Returns a session token for account management endpoints. Email must be verified first.

#### Request Body

##### Content-Type: application/json

- **`email` (required)**

  `string`, format: `email`

- **`password` (required)**

  `string`

**Example:**

```json
{
  "email": "",
  "password": ""
}
```

#### Responses

##### Status: 200 Login successful

###### Content-Type: application/json

- **`access_token` (required)**

  `string` — JWT session token

- **`expires_in` (required)**

  `integer` — Token lifetime in seconds

- **`refresh_token` (required)**

  `string`

**Example:**

```json
{
  "access_token": "",
  "refresh_token": "",
  "expires_in": 1
}
```

##### Status: 401 Invalid credentials

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code

  - **`message` (required)**

    `string` — Human-readable description

  - **`details`**

    `object` — Additional error context (e.g. validation issues)

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "details": {}
  }
}
```

##### Status: 403 Email not verified

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code

  - **`message` (required)**

    `string` — Human-readable description

  - **`details`**

    `object` — Additional error context (e.g. validation issues)

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "details": {}
  }
}
```

### Refresh access token

- **Method:** `POST`
- **Path:** `/auth/refresh`
- **Tags:** Auth

Exchange a refresh token for a new access token.

#### Request Body

##### Content-Type: application/json

- **`refresh_token` (required)**

  `string`

**Example:**

```json
{
  "refresh_token": ""
}
```

#### Responses

##### Status: 200 Token refreshed

###### Content-Type: application/json

- **`access_token` (required)**

  `string` — JWT session token

- **`expires_in` (required)**

  `integer` — Token lifetime in seconds

- **`refresh_token` (required)**

  `string`

**Example:**

```json
{
  "access_token": "",
  "refresh_token": "",
  "expires_in": 1
}
```

##### Status: 401 Invalid or expired refresh token

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code

  - **`message` (required)**

    `string` — Human-readable description

  - **`details`**

    `object` — Additional error context (e.g. validation issues)

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "details": {}
  }
}
```

### Request password reset

- **Method:** `POST`
- **Path:** `/auth/forgot-password`
- **Tags:** Auth

Send a password reset email. Always returns success to prevent email enumeration.

#### Request Body

##### Content-Type: application/json

- **`email` (required)**

  `string`, format: `email`

**Example:**

```json
{
  "email": ""
}
```

#### Responses

##### Status: 200 Reset email sent (if account exists)

###### Content-Type: application/json

- **`message`**

  `string`

**Example:**

```json
{
  "message": ""
}
```

### Get developer profile

- **Method:** `GET`
- **Path:** `/account`
- **Tags:** Account

Returns your developer profile including credits remaining.

#### Responses

##### Status: 200 Developer profile

###### Content-Type: application/json

- **`created_at` (required)**

  `string`, format: `date-time`

- **`credits_remaining` (required)**

  `integer`

- **`email` (required)**

  `string`, format: `email`

- **`id` (required)**

  `string`, format: `uuid`

- **`company_name`**

  `string`

- **`use_case`**

  `string`

**Example:**

```json
{
  "id": "",
  "email": "",
  "company_name": "",
  "use_case": "",
  "credits_remaining": 1,
  "created_at": ""
}
```

##### Status: 401 Missing or invalid authentication

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code

  - **`message` (required)**

    `string` — Human-readable description

  - **`details`**

    `object` — Additional error context (e.g. validation issues)

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "details": {}
  }
}
```

### List API keys

- **Method:** `GET`
- **Path:** `/account/keys`
- **Tags:** Account

List all API keys for your account.

#### Responses

##### Status: 200 List of API keys

###### Content-Type: application/json

- **`keys` (required)**

  `array`

  **Items:**

  - **`active` (required)**

    `boolean`

  - **`created_at` (required)**

    `string`, format: `date-time`

  - **`id` (required)**

    `string`, format: `uuid`

  - **`key_prefix` (required)**

    `string` — First 8 characters of the key (for identification)

  - **`allowed_origins`**

    `array`

    **Items:**

    `string`

  - **`label`**

    `string`

  - **`last_used_at`**

    `string`, format: `date-time`

**Example:**

```json
{
  "keys": [
    {
      "id": "",
      "key_prefix": "",
      "allowed_origins": [
        ""
      ],
      "label": "",
      "active": true,
      "created_at": "",
      "last_used_at": ""
    }
  ]
}
```

##### Status: 401 Missing or invalid authentication

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code

  - **`message` (required)**

    `string` — Human-readable description

  - **`details`**

    `object` — Additional error context (e.g. validation issues)

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "details": {}
  }
}
```

### Create an API key

- **Method:** `POST`
- **Path:** `/account/keys`
- **Tags:** Account

Create a new API key. The plaintext key is returned **only once** in the response. Store it securely — it cannot be retrieved again.

Optionally set `allowed_origins` to restrict the key to specific domains (for browser/client-side use).

#### Request Body

##### Content-Type: application/json

- **`allowed_origins`**

  `array` — Exact origins for client-side use (e.g. \`https\://example.com\`). Omit for server-side keys.

  **Items:**

  `string`

- **`label`**

  `string`

**Example:**

```json
{
  "allowed_origins": [
    ""
  ],
  "label": ""
}
```

#### Responses

##### Status: 201 API key created

###### Content-Type: application/json

- **`active` (required)**

  `boolean`

- **`created_at` (required)**

  `string`, format: `date-time`

- **`id` (required)**

  `string`, format: `uuid`

- **`key` (required)**

  `string` — The plaintext API key. \*\*Shown only once — save it immediately.\*\*

- **`key_prefix` (required)**

  `string`

- **`allowed_origins`**

  `array`

  **Items:**

  `string`

- **`label`**

  `string`

**Example:**

```json
{
  "key": "",
  "id": "",
  "key_prefix": "",
  "allowed_origins": [
    ""
  ],
  "label": "",
  "active": true,
  "created_at": ""
}
```

##### Status: 401 Missing or invalid authentication

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code

  - **`message` (required)**

    `string` — Human-readable description

  - **`details`**

    `object` — Additional error context (e.g. validation issues)

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "details": {}
  }
}
```

##### Status: 422 Request body failed schema validation

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code

  - **`message` (required)**

    `string` — Human-readable description

  - **`details`**

    `object` — Additional error context (e.g. validation issues)

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "details": {}
  }
}
```

### Update an API key

- **Method:** `POST`
- **Path:** `/account/keys/{id}`
- **Tags:** Account

Update a key's origin restrictions or label. Set `allowed_origins` to `null` to remove origin restrictions.

#### Request Body

##### Content-Type: application/json

- **`allowed_origins`**

  `array` — Set to \`null\` to remove origin restrictions.

  **Items:**

  `string`

- **`label`**

  `string`

**Example:**

```json
{
  "allowed_origins": [
    ""
  ],
  "label": ""
}
```

#### Responses

##### Status: 200 Key updated

###### Content-Type: application/json

- **`active` (required)**

  `boolean`

- **`created_at` (required)**

  `string`, format: `date-time`

- **`id` (required)**

  `string`, format: `uuid`

- **`key_prefix` (required)**

  `string` — First 8 characters of the key (for identification)

- **`allowed_origins`**

  `array`

  **Items:**

  `string`

- **`label`**

  `string`

- **`last_used_at`**

  `string`, format: `date-time`

**Example:**

```json
{
  "id": "",
  "key_prefix": "",
  "allowed_origins": [
    ""
  ],
  "label": "",
  "active": true,
  "created_at": "",
  "last_used_at": ""
}
```

##### Status: 401 Missing or invalid authentication

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code

  - **`message` (required)**

    `string` — Human-readable description

  - **`details`**

    `object` — Additional error context (e.g. validation issues)

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "details": {}
  }
}
```

##### Status: 404 Key not found

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code

  - **`message` (required)**

    `string` — Human-readable description

  - **`details`**

    `object` — Additional error context (e.g. validation issues)

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "details": {}
  }
}
```

##### Status: 422 Request body failed schema validation

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code

  - **`message` (required)**

    `string` — Human-readable description

  - **`details`**

    `object` — Additional error context (e.g. validation issues)

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "details": {}
  }
}
```

### Deactivate an API key

- **Method:** `DELETE`
- **Path:** `/account/keys/{id}`
- **Tags:** Account

Soft-deletes a key by setting it to inactive. The key can no longer be used for API requests.

#### Responses

##### Status: 200 Key deactivated

###### Content-Type: application/json

- **`deleted`**

  `boolean`

**Example:**

```json
{
  "deleted": true
}
```

##### Status: 401 Missing or invalid authentication

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code

  - **`message` (required)**

    `string` — Human-readable description

  - **`details`**

    `object` — Additional error context (e.g. validation issues)

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "details": {}
  }
}
```

##### Status: 404 Key not found

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code

  - **`message` (required)**

    `string` — Human-readable description

  - **`details`**

    `object` — Additional error context (e.g. validation issues)

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "details": {}
  }
}
```

### Usage summary

- **Method:** `GET`
- **Path:** `/account/usage`
- **Tags:** Account

Returns usage statistics for the last 30 days including total credits used and per-endpoint breakdown.

#### Responses

##### Status: 200 Usage summary

###### Content-Type: application/json

- **`by_endpoint` (required)**

  `array`

  **Items:**

  - **`credits` (required)**

    `integer`

  - **`endpoint` (required)**

    `string`

  - **`requests` (required)**

    `integer`

- **`period_days` (required)**

  `integer`

- **`total_credits_used` (required)**

  `integer`

- **`total_requests` (required)**

  `integer`

**Example:**

```json
{
  "total_credits_used": 1,
  "total_requests": 1,
  "period_days": 1,
  "by_endpoint": [
    {
      "endpoint": "",
      "requests": 1,
      "credits": 1
    }
  ]
}
```

##### Status: 401 Missing or invalid authentication

###### Content-Type: application/json

- **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code

  - **`message` (required)**

    `string` — Human-readable description

  - **`details`**

    `object` — Additional error context (e.g. validation issues)

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "details": {}
  }
}
```

## Schemas

### HealthResponse

- **Type:**`object`

* **`status` (required)**

  `string`

* **`timestamp` (required)**

  `string`, format: `date-time`

* **`version` (required)**

  `string`

**Example:**

```json
{
  "status": "",
  "version": "",
  "timestamp": ""
}
```

### Valuation

- **Type:**`object`

* **`excellent` (required)**

  `number` — Best-case value (USD)

* **`fair` (required)**

  `number` — Conservative estimate (USD)

* **`good` (required)**

  `number` — Mid-market value (USD)

**Example:**

```json
{
  "fair": 1,
  "good": 1,
  "excellent": 1
}
```

### Depreciation

- **Type:**`object`

* **`confidence` (required)**

  `string`, possible values: `"high", "medium", "low"`

* **`projection` (required)**

  `object`

  - **`excellent` (required)**

    `number`

  - **`fair` (required)**

    `number`

  - **`good` (required)**

    `number`

  - **`months` (required)**

    `integer`

* **`refreshSignal` (required)**

  `string`, possible values: `"hold", "considerRefreshing", "refreshNow"` — - \`hold\` — device retains strong value - \`considerRefreshing\` — approaching optimal trade-in window - \`refreshNow\` — past optimal trade-in window

* **`trend` (required)**

  `string`, possible values: `"stable", "increasing", "decreasing"`

**Example:**

```json
{
  "trend": "stable",
  "projection": {
    "months": 1,
    "fair": 1,
    "good": 1,
    "excellent": 1
  },
  "refreshSignal": "hold",
  "confidence": "high"
}
```

### DeviceResponse

- **Type:**`object`

* **`confidence` (required)**

  `string`, possible values: `"high", "medium", "low"`

* **`currency` (required)**

  `string`, default: `"USD"`

* **`currentValuation` (required)**

  `object`

  - **`excellent` (required)**

    `number` — Best-case value (USD)

  - **`fair` (required)**

    `number` — Conservative estimate (USD)

  - **`good` (required)**

    `number` — Mid-market value (USD)

* **`deviceId` (required)**

  `string`

* **`displayName` (required)**

  `string`

* **`validUntil` (required)**

  `string`, format: `date-time` — Pricing data freshness (24-hour cache)

* **`depreciation`**

  `object`

  - **`confidence` (required)**

    `string`, possible values: `"high", "medium", "low"`

  - **`projection` (required)**

    `object`

    - **`excellent` (required)**

      `number`

    - **`fair` (required)**

      `number`

    - **`good` (required)**

      `number`

    - **`months` (required)**

      `integer`

  - **`refreshSignal` (required)**

    `string`, possible values: `"hold", "considerRefreshing", "refreshNow"` — - \`hold\` — device retains strong value - \`considerRefreshing\` — approaching optimal trade-in window - \`refreshNow\` — past optimal trade-in window

  - **`trend` (required)**

    `string`, possible values: `"stable", "increasing", "decreasing"`

* **`msrp`**

  `number` — Original retail price (USD)

* **`residualPct`**

  `number` — Percentage of MSRP retained (good / msrp x 100)

* **`valueTier`**

  `string`, possible values: `"Peak", "Strong", "Moderate", "Low"`

**Example:**

```json
{
  "deviceId": "",
  "displayName": "",
  "currentValuation": {
    "fair": 1,
    "good": 1,
    "excellent": 1
  },
  "msrp": 1,
  "residualPct": 1,
  "valueTier": "Peak",
  "depreciation": {
    "trend": "stable",
    "projection": {
      "months": 1,
      "fair": 1,
      "good": 1,
      "excellent": 1
    },
    "refreshSignal": "hold",
    "confidence": "high"
  },
  "currency": "USD",
  "confidence": "high",
  "validUntil": ""
}
```

### BatchDeviceResponse

- **Type:**`object`

* **`currentValuation` (required)**

  `object`

  - **`excellent` (required)**

    `number` — Best-case value (USD)

  - **`fair` (required)**

    `number` — Conservative estimate (USD)

  - **`good` (required)**

    `number` — Mid-market value (USD)

* **`deviceId` (required)**

  `string`

* **`displayName` (required)**

  `string`

* **`quantity` (required)**

  `integer`

* **`depreciation`**

  `object`

  - **`confidence` (required)**

    `string`, possible values: `"high", "medium", "low"`

  - **`projection` (required)**

    `object`

    - **`excellent` (required)**

      `number`

    - **`fair` (required)**

      `number`

    - **`good` (required)**

      `number`

    - **`months` (required)**

      `integer`

  - **`refreshSignal` (required)**

    `string`, possible values: `"hold", "considerRefreshing", "refreshNow"` — - \`hold\` — device retains strong value - \`considerRefreshing\` — approaching optimal trade-in window - \`refreshNow\` — past optimal trade-in window

  - **`trend` (required)**

    `string`, possible values: `"stable", "increasing", "decreasing"`

* **`msrp`**

  `number`

* **`residualPct`**

  `number`

* **`valueTier`**

  `string`, possible values: `"Peak", "Strong", "Moderate", "Low"`

**Example:**

```json
{
  "deviceId": "",
  "displayName": "",
  "quantity": 1,
  "currentValuation": {
    "fair": 1,
    "good": 1,
    "excellent": 1
  },
  "msrp": 1,
  "residualPct": 1,
  "valueTier": "Peak",
  "depreciation": {
    "trend": "stable",
    "projection": {
      "months": 1,
      "fair": 1,
      "good": 1,
      "excellent": 1
    },
    "refreshSignal": "hold",
    "confidence": "high"
  }
}
```

### UnmatchedDevice

- **Type:**`object`

* **`input` (required)**

  `string` — The original identifier that could not be resolved

* **`reason` (required)**

  `string`, possible values: `"not_found", "invalid_identifier", "no_pricing", "unsupported_model", "virtual_machine", "unknown_model"`

* **`suggestions`**

  `array`

  **Items:**

  `string`

**Example:**

```json
{
  "input": "",
  "reason": "not_found",
  "suggestions": [
    ""
  ]
}
```

### BatchRequest

- **Type:**`object`

* **`devices` (required)**

  `array`

  **Items:**

  **One of:**

  `string` — Device ID (quantity = 1)

  - **`id` (required)**

    `string`

  - **`qty`**

    `integer`, default: `1`

  * **`deviceModelIdentifier` (required)**

    `string` — Apple model identifier (e.g. \`mac14,2\`)

  * **`stats` (required)**

    `object`

    - **`memoryTotalGB` (required)**

      `number` — Reported RAM in GB (e.g. 8.5 normalizes to 8GB)

    - **`storageTotalGB` (required)**

      `number` — Reported storage in GB (e.g. 243.8 normalizes to 256GB)

  * **`cpuModelName`**

    `string`

  * **`deviceModelName`**

    `string`

  * **`qty`**

    `integer`, default: `1`

**Example:**

```json
{
  "devices": [
    ""
  ]
}
```

### MdmPayload

- **Type:**`object`

Raw MDM device data. Storage and RAM are auto-normalized to marketing tiers.

- **`deviceModelIdentifier` (required)**

  `string` — Apple model identifier (e.g. \`mac14,2\`)

- **`stats` (required)**

  `object`

  - **`memoryTotalGB` (required)**

    `number` — Reported RAM in GB (e.g. 8.5 normalizes to 8GB)

  - **`storageTotalGB` (required)**

    `number` — Reported storage in GB (e.g. 243.8 normalizes to 256GB)

- **`cpuModelName`**

  `string`

- **`deviceModelName`**

  `string`

- **`qty`**

  `integer`, default: `1`

**Example:**

```json
{
  "deviceModelIdentifier": "",
  "deviceModelName": "",
  "cpuModelName": "",
  "stats": {
    "memoryTotalGB": 1,
    "storageTotalGB": 1
  },
  "qty": 1
}
```

### BatchResponse

- **Type:**`object`

* **`currency` (required)**

  `string`, default: `"USD"`

* **`results` (required)**

  `array`

  **Items:**

  - **`currentValuation` (required)**

    `object`

    - **`excellent` (required)**

      `number` — Best-case value (USD)

    - **`fair` (required)**

      `number` — Conservative estimate (USD)

    - **`good` (required)**

      `number` — Mid-market value (USD)

  - **`deviceId` (required)**

    `string`

  - **`displayName` (required)**

    `string`

  - **`quantity` (required)**

    `integer`

  - **`depreciation`**

    `object`

    - **`confidence` (required)**

      `string`, possible values: `"high", "medium", "low"`

    - **`projection` (required)**

      `object`

      - **`excellent` (required)**

        `number`

      - **`fair` (required)**

        `number`

      - **`good` (required)**

        `number`

      - **`months` (required)**

        `integer`

    - **`refreshSignal` (required)**

      `string`, possible values: `"hold", "considerRefreshing", "refreshNow"` — - \`hold\` — device retains strong value - \`considerRefreshing\` — approaching optimal trade-in window - \`refreshNow\` — past optimal trade-in window

    - **`trend` (required)**

      `string`, possible values: `"stable", "increasing", "decreasing"`

  - **`msrp`**

    `number`

  - **`residualPct`**

    `number`

  - **`valueTier`**

    `string`, possible values: `"Peak", "Strong", "Moderate", "Low"`

* **`summary` (required)**

  `object`

  - **`confidence` (required)**

    `string`, possible values: `"high", "medium", "low"`

  - **`itemsReceived` (required)**

    `integer`

  - **`totalCurrentValue` (required)**

    `number` — Sum of good-condition values across all units

  - **`totalUnits` (required)**

    `integer`

  - **`uniqueDevicesResolved` (required)**

    `integer`

  - **`projectedValue`**

    `object`

    - **`months`**

      `integer`

    - **`percentChange`**

      `number`

    - **`total`**

      `number`

  - **`refreshBreakdown`**

    `object`

    - **`considerRefreshing`**

      `integer`

    - **`hold`**

      `integer`

    - **`refreshNow`**

      `integer`

* **`validUntil` (required)**

  `string`, format: `date-time`

* **`unmatched`**

  `array`

  **Items:**

  - **`input` (required)**

    `string` — The original identifier that could not be resolved

  - **`reason` (required)**

    `string`, possible values: `"not_found", "invalid_identifier", "no_pricing", "unsupported_model", "virtual_machine", "unknown_model"`

  - **`suggestions`**

    `array`

    **Items:**

    `string`

**Example:**

```json
{
  "results": [
    {
      "deviceId": "",
      "displayName": "",
      "quantity": 1,
      "currentValuation": {
        "fair": 1,
        "good": 1,
        "excellent": 1
      },
      "msrp": 1,
      "residualPct": 1,
      "valueTier": "Peak",
      "depreciation": {
        "trend": "stable",
        "projection": {
          "months": 1,
          "fair": 1,
          "good": 1,
          "excellent": 1
        },
        "refreshSignal": "hold",
        "confidence": "high"
      }
    }
  ],
  "unmatched": [
    {
      "input": "",
      "reason": "not_found",
      "suggestions": [
        ""
      ]
    }
  ],
  "summary": {
    "itemsReceived": 1,
    "uniqueDevicesResolved": 1,
    "totalUnits": 1,
    "totalCurrentValue": 1,
    "projectedValue": {
      "months": 1,
      "total": 1,
      "percentChange": 1
    },
    "refreshBreakdown": {
      "hold": 1,
      "considerRefreshing": 1,
      "refreshNow": 1
    },
    "confidence": "high"
  },
  "currency": "USD",
  "validUntil": ""
}
```

### BatchSummary

- **Type:**`object`

* **`confidence` (required)**

  `string`, possible values: `"high", "medium", "low"`

* **`itemsReceived` (required)**

  `integer`

* **`totalCurrentValue` (required)**

  `number` — Sum of good-condition values across all units

* **`totalUnits` (required)**

  `integer`

* **`uniqueDevicesResolved` (required)**

  `integer`

* **`projectedValue`**

  `object`

  - **`months`**

    `integer`

  - **`percentChange`**

    `number`

  - **`total`**

    `number`

* **`refreshBreakdown`**

  `object`

  - **`considerRefreshing`**

    `integer`

  - **`hold`**

    `integer`

  - **`refreshNow`**

    `integer`

**Example:**

```json
{
  "itemsReceived": 1,
  "uniqueDevicesResolved": 1,
  "totalUnits": 1,
  "totalCurrentValue": 1,
  "projectedValue": {
    "months": 1,
    "total": 1,
    "percentChange": 1
  },
  "refreshBreakdown": {
    "hold": 1,
    "considerRefreshing": 1,
    "refreshNow": 1
  },
  "confidence": "high"
}
```

### RegisterRequest

- **Type:**`object`

* **`email` (required)**

  `string`, format: `email`

* **`password` (required)**

  `string`

* **`company_name`**

  `string`

* **`use_case`**

  `string`

**Example:**

```json
{
  "email": "",
  "password": "",
  "company_name": "",
  "use_case": ""
}
```

### LoginRequest

- **Type:**`object`

* **`email` (required)**

  `string`, format: `email`

* **`password` (required)**

  `string`

**Example:**

```json
{
  "email": "",
  "password": ""
}
```

### AuthTokenResponse

- **Type:**`object`

* **`access_token` (required)**

  `string` — JWT session token

* **`expires_in` (required)**

  `integer` — Token lifetime in seconds

* **`refresh_token` (required)**

  `string`

**Example:**

```json
{
  "access_token": "",
  "refresh_token": "",
  "expires_in": 1
}
```

### DeveloperProfile

- **Type:**`object`

* **`created_at` (required)**

  `string`, format: `date-time`

* **`credits_remaining` (required)**

  `integer`

* **`email` (required)**

  `string`, format: `email`

* **`id` (required)**

  `string`, format: `uuid`

* **`company_name`**

  `string`

* **`use_case`**

  `string`

**Example:**

```json
{
  "id": "",
  "email": "",
  "company_name": "",
  "use_case": "",
  "credits_remaining": 1,
  "created_at": ""
}
```

### ApiKeyMeta

- **Type:**`object`

* **`active` (required)**

  `boolean`

* **`created_at` (required)**

  `string`, format: `date-time`

* **`id` (required)**

  `string`, format: `uuid`

* **`key_prefix` (required)**

  `string` — First 8 characters of the key (for identification)

* **`allowed_origins`**

  `array`

  **Items:**

  `string`

* **`label`**

  `string`

* **`last_used_at`**

  `string`, format: `date-time`

**Example:**

```json
{
  "id": "",
  "key_prefix": "",
  "allowed_origins": [
    ""
  ],
  "label": "",
  "active": true,
  "created_at": "",
  "last_used_at": ""
}
```

### CreateKeyRequest

- **Type:**`object`

* **`allowed_origins`**

  `array` — Exact origins for client-side use (e.g. \`https\://example.com\`). Omit for server-side keys.

  **Items:**

  `string`

* **`label`**

  `string`

**Example:**

```json
{
  "allowed_origins": [
    ""
  ],
  "label": ""
}
```

### CreatedApiKey

- **Type:**`object`

* **`active` (required)**

  `boolean`

* **`created_at` (required)**

  `string`, format: `date-time`

* **`id` (required)**

  `string`, format: `uuid`

* **`key` (required)**

  `string` — The plaintext API key. \*\*Shown only once — save it immediately.\*\*

* **`key_prefix` (required)**

  `string`

* **`allowed_origins`**

  `array`

  **Items:**

  `string`

* **`label`**

  `string`

**Example:**

```json
{
  "key": "",
  "id": "",
  "key_prefix": "",
  "allowed_origins": [
    ""
  ],
  "label": "",
  "active": true,
  "created_at": ""
}
```

### UpdateKeyRequest

- **Type:**`object`

* **`allowed_origins`**

  `array` — Set to \`null\` to remove origin restrictions.

  **Items:**

  `string`

* **`label`**

  `string`

**Example:**

```json
{
  "allowed_origins": [
    ""
  ],
  "label": ""
}
```

### UsageResponse

- **Type:**`object`

* **`by_endpoint` (required)**

  `array`

  **Items:**

  - **`credits` (required)**

    `integer`

  - **`endpoint` (required)**

    `string`

  - **`requests` (required)**

    `integer`

* **`period_days` (required)**

  `integer`

* **`total_credits_used` (required)**

  `integer`

* **`total_requests` (required)**

  `integer`

**Example:**

```json
{
  "total_credits_used": 1,
  "total_requests": 1,
  "period_days": 1,
  "by_endpoint": [
    {
      "endpoint": "",
      "requests": 1,
      "credits": 1
    }
  ]
}
```

### ErrorResponse

- **Type:**`object`

* **`error` (required)**

  `object`

  - **`code` (required)**

    `string` — Machine-readable error code

  - **`message` (required)**

    `string` — Human-readable description

  - **`details`**

    `object` — Additional error context (e.g. validation issues)

**Example:**

```json
{
  "error": {
    "code": "",
    "message": "",
    "details": {}
  }
}
```
