> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rafter.so/llms.txt
> Use this file to discover all available pages before exploring further.

# Create Site

> Register a site for live-application security monitoring and kick off its first scan

## POST /api/static/sites

Register a new [Site](/guides/sites) for live-application monitoring and trigger its first scan. Sites are distinct from repository scans (`/api/static/scan`) — instead of scanning source code, Sites continuously monitor a live domain for exposed backends, DNS misconfiguration, SEO issues, and accessibility problems.

Requires an API key with the `read-and-scan` scope.

### Request

**Headers:**

* `x-api-key` (required): Your Rafter security API key, scope `read-and-scan`
* `Content-Type: application/json`

**Body:**

```json theme={null}
{
  "url": "https://example.com"
}
```

**Fields:**

| Field | Type   | Required | Description                    |
| ----- | ------ | -------- | ------------------------------ |
| `url` | string | Yes      | The URL of the site to monitor |

### Example Request

```bash theme={null}
curl -X POST \
  -H "Content-Type: application/json" \
  -H "x-api-key: RFabc-your-api-key-here" \
  -d '{"url": "https://example.com"}' \
  https://rafter.so/api/static/sites
```

### Response

**Success (200 OK — new site):**

```json theme={null}
{
  "site": {
    "id": "b1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "user_id": "u_abc123",
    "registrable_domain": "example.com",
    "preferred_base_url": "https://example.com",
    "scope_type": "domain",
    "scope_value": "example.com",
    "is_archived": false,
    "github_repos": [],
    "created_at": "2026-07-24T00:00:00.000+00:00",
    "updated_at": "2026-07-24T00:00:00.000+00:00"
  },
  "run": {
    "id": "r_1a2b3c4d",
    "project_id": "b1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "user_id": "u_abc123",
    "status": "running",
    "started_at": "2026-07-24T00:00:00.000+00:00",
    "finished_at": null,
    "progress_total": 0,
    "progress_done": 0,
    "created_at": "2026-07-24T00:00:00.000+00:00",
    "updated_at": "2026-07-24T00:00:00.000+00:00"
  },
  "created": true
}
```

<Note>
  If the site was created but its initial scan failed to start, the response includes a `scan_error` string alongside `"created": true` and `"run": null`.
</Note>

**Success (200 OK — site already existed):**

```json theme={null}
{
  "site": {
    "id": "b1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "is_archived": false
  },
  "run": null,
  "created": false
}
```

**Error (400 Bad Request — missing, invalid, or blocked URL):**

```json theme={null}
{
  "error": "Invalid or blocked URL."
}
```

**Error (401 Unauthorized):**

```json theme={null}
{
  "error": "Invalid or inactive API key."
}
```

**Error (403 Forbidden — wrong scope):**

```json theme={null}
{
  "error": "API key does not have read-and-scan scope."
}
```

**Error (403 Forbidden — plan or site limit reached):**

```json theme={null}
{
  "error": "You have reached your site limit for this billing period."
}
```

**Error (429 Too Many Requests):**

```json theme={null}
{
  "error": "Rate limit exceeded",
  "message": "Too many requests. Please try again later.",
  "retryAfter": 30
}
```

**Error (500 Internal Server Error):**

```json theme={null}
{
  "error": "An unexpected error occurred."
}
```

### Response Fields

| Field                     | Type           | Description                                                                                                                                                                                   |
| ------------------------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `site.id`                 | string         | Unique identifier for the site (project id)                                                                                                                                                   |
| `site.user_id`            | string         | Owning user's id (omitted when `created` is `false`)                                                                                                                                          |
| `site.registrable_domain` | string         | The site's registrable domain                                                                                                                                                                 |
| `site.preferred_base_url` | string         | The canonical base URL used for scanning                                                                                                                                                      |
| `site.scope_type`         | string         | How the site's scan scope is defined                                                                                                                                                          |
| `site.scope_value`        | string         | The value for `scope_type`                                                                                                                                                                    |
| `site.is_archived`        | boolean        | Whether the site has been archived                                                                                                                                                            |
| `site.github_repos`       | array          | Linked GitHub repos for this site (empty until configured)                                                                                                                                    |
| `site.created_at`         | string         | ISO 8601 timestamp when the site was created                                                                                                                                                  |
| `site.updated_at`         | string         | ISO 8601 timestamp when the site was last updated                                                                                                                                             |
| `run`                     | object \| null | The first scan run that was kicked off, or `null` if the site already existed or the scan failed to start                                                                                     |
| `run.status`              | string         | The run's status. The initial run created here starts as `running` (its steps are enqueued synchronously); it can also be `queued`, `succeeded`, or `failed` at other points in its lifecycle |
| `run.updated_at`          | string         | ISO 8601 timestamp when the run was last updated                                                                                                                                              |
| `created`                 | boolean        | `true` if this call created a new site, `false` if the site already existed                                                                                                                   |
| `scan_error`              | string         | Present only when `created` is `true` but the initial scan failed to start                                                                                                                    |

## Rate Limiting

The API implements rate limiting to ensure fair usage:

* **Rate Limit**: 100 requests per minute per IP address
* **Quota**: Based on your subscription plan

### Examples

#### JavaScript

```javascript theme={null}
const response = await fetch('https://rafter.so/api/static/sites', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': 'RFabc-your-api-key-here'
  },
  body: JSON.stringify({ url: 'https://example.com' })
});

const data = await response.json();
console.log(`Site ID: ${data.site.id}`);
```

#### Python

```python theme={null}
import requests

response = requests.post(
    'https://rafter.so/api/static/sites',
    headers={
        'Content-Type': 'application/json',
        'x-api-key': 'RFabc-your-api-key-here'
    },
    json={'url': 'https://example.com'}
)

data = response.json()
print(f"Site ID: {data['site']['id']}")
```

### Next Steps

After creating a site, you can:

1. **Check status and findings** using the site id with the [Get Site endpoint](/api-reference/endpoint/static/sites/get)
2. **Trigger a re-scan** later with the [Scan Site endpoint](/api-reference/endpoint/static/sites/scan)
3. **List all your sites** with the [List Sites endpoint](/api-reference/endpoint/static/sites/list)
