# Add an asset

`POST /app/assets`

Adds a domain, subdomain, IP address or bucket to a project and checks that it answers. Nothing is scanned until its ownership is proven (see Verify ownership). Past the plan's included assets the answer asks for a paid slot, which an API key or OAuth app cannot buy: add that asset in the dashboard.

Scope: `assets:write`.

## Request body

- `projectId` (integer, required)
- `name` (string | null)
- `type` (string, required)
- `value` (string, required)
- `bucketProvider` (string | null)
- `acceptExtraCharge` (boolean)

## Example

```bash
curl -X POST "https://api.fortwatch.ai/app/assets" \
  -H "Authorization: Bearer $FORTWATCH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "projectId": 42,
  "name": "Production",
  "type": "string",
  "value": "app.example.com",
  "bucketProvider": "string",
  "acceptExtraCharge": true
}'
```

## Response 201

Created.

- `id` (number, required)
- `projectId` (number, required)
- `name` (string | null, required)
- `type` (string, required)
- `value` (string, required)
- `status` (string, required)
- `canonicalUrl` (string | null, required)
- `resolvedIp` (string | null, required)
- `cdnProvider` (string | null, required)
- `bucketProvider` (string | null, required)
- `lastCheckedAt` (string (date-time) | null, required)
- `failReason` (string | null, required)
- `skippedRedirectHost` (string | null, required)
- `disabledScannerTypes` (string[], required)
- `portScanMode` (string, required)
- `nucleiMinSeverity` (string, required)
- `ownershipVerifiedAt` (string (date-time) | null, required)
- `ownershipToken` (string, required)
- `ownershipMethod` (string | null, required)
- `createdAt` (string (date-time), required)
- `updatedAt` (string (date-time), required)
- `project` (object, required)
  - `id` (number, required)
  - `name` (string, required)
  - `color` (string, required)

```json
{
  "id": 42,
  "projectId": 42,
  "name": "Production",
  "type": "string",
  "value": "app.example.com",
  "status": "string",
  "canonicalUrl": "string",
  "resolvedIp": "string",
  "cdnProvider": "string",
  "bucketProvider": "string",
  "lastCheckedAt": "2026-10-16T12:00:00.000Z",
  "failReason": "string",
  "skippedRedirectHost": "string",
  "disabledScannerTypes": [
    "string"
  ],
  "portScanMode": "string",
  "nucleiMinSeverity": "string",
  "ownershipVerifiedAt": "2026-10-16T12:00:00.000Z",
  "ownershipToken": "string",
  "ownershipMethod": "string",
  "createdAt": "2026-10-16T12:00:00.000Z",
  "updatedAt": "2026-10-16T12:00:00.000Z",
  "project": {
    "id": 42,
    "name": "Production",
    "color": "string"
  }
}
```

## Errors

- 400: The request is not valid: a field is missing or has the wrong shape (the message names it).
- 401: No valid credentials: the API key or access token is missing, revoked or expired (INVALID_API_KEY, INVALID_TOKEN).
- 403: Not allowed: the key or token lacks this scope (SCOPE_REQUIRED), the route is dashboard-only (SESSION_REQUIRED), or a plan limit applies.
- 429: Too many requests (RATE_LIMITED): wait the seconds Retry-After gives.
