# Quickstart

This guide will get you all set up and ready to use the ScreenshotBuddy API. We'll cover how our API works, how to authenticate with it, and how to make your first API request.

> Before you can make requests to the ScreenshotBuddy API, you will need to grab your API key from your dashboard. You find it under [Settings, API tokens](https://screenshotbuddy.io/settings/api-tokens).

Every option a request accepts is listed on two pages: [Taking screenshots](https://screenshotbuddy.io/documentation/taking-screenshots.md) for images and [Creating PDFs](https://screenshotbuddy.io/documentation/creating-pdfs.md) for documents. The [OpenAPI document](https://api.screenshotbuddy.io/v1/openapi.json) is the complete reference, generated from the same definitions the API validates against.

If you are an agent rather than a person, [/llms.txt](https://screenshotbuddy.io/llms.txt) indexes this documentation for machine readers, and every page of it is also served as markdown at its own URL with `.md` on the end.

## Making your first API request

After obtaining your API key, you can make your first API request. Below, we'll show you how you can take a screenshot of a website using the API.

The API is served from a host of its own, `api.screenshotbuddy.io`, rather than from the site you are reading this on. Every path below is relative to that base URL, and it is the only host you ever send a token to.

Endpoint: `GET https://api.screenshotbuddy.io/v1/snap`

Replace `{token}` with your API key. The response body is the image itself, so write it straight to a file instead of parsing it as JSON.

```bash
curl "https://api.screenshotbuddy.io/v1/snap?url=https%3A%2F%2Fexample.com" \
  -H "Authorization: Bearer {token}" \
  --output screenshot.png
```

```javascript
import { writeFile } from 'node:fs/promises';

const response = await fetch('https://api.screenshotbuddy.io/v1/snap?url=https%3A%2F%2Fexample.com', {
    headers: { Authorization: 'Bearer {token}' },
});

if (!response.ok) {
    throw new Error(`Request failed with status ${response.status}`);
}

await writeFile('screenshot.png', Buffer.from(await response.arrayBuffer()));
```

```python
import requests

response = requests.get(
    'https://api.screenshotbuddy.io/v1/snap',
    params={'url': 'https://example.com'},
    headers={'Authorization': 'Bearer {token}'},
)
response.raise_for_status()

with open('screenshot.png', 'wb') as file:
    file.write(response.content)
```

```php
<?php

$endpoint = 'https://api.screenshotbuddy.io/v1/snap?url=' . urlencode('https://example.com');

$curl = curl_init($endpoint);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, ['Authorization: Bearer {token}']);

$response = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);

if ($status !== 200) {
    exit('Request failed with status ' . $status);
}

file_put_contents('screenshot.png', $response);
```

```php
$response = Http::withToken(config('services.screenshotbuddy.token'))
    ->get('https://api.screenshotbuddy.io/v1/snap', [
        'url' => 'https://example.com',
    ])
    ->throw();

Storage::put('screenshot.png', $response->body());
```

The Laravel example uses `->throw()` so a failed request raises a `RequestException`. Prefer `$response->failed()` if you would rather handle the error yourself.

## Rate limits

Every account can ask for up to 20 renders per minute by default. Higher plans and custom arrangements can have higher limits. Repeats we answer out of your cache are counted apart from that, against a flat 300 per minute, so a burst of captures you already hold does not eat into the renders you were saving. A conditional request we can answer `304` out of that cache counts against neither; one we had to render before we could answer it counts as the render it was.

Every response to a request that carried your token includes an `X-RateLimit-Limit` header with the size of the budget that answer was counted against, and an `X-RateLimit-Remaining` header with what is left of it. A signed URL is answered without them, because its answer goes to whoever you handed the URL to rather than to you.

If you go over a limit, the API returns HTTP status `429` together with a `Retry-After` header telling you how many seconds to wait before trying again.

To see where you stand before you send anything, ask `/usage`: it reports your credits, your plan and both of your per-minute limits, under a limit of its own.

The [rate limits](https://screenshotbuddy.io/documentation/rate-limits.md) page covers this in full, including the separate limit the playground runs under.

If you are rendering slow pages, or a whole list of them at once, submit them as a [batch](https://screenshotbuddy.io/documentation/batch-renders.md) instead and collect the results afterwards, rather than holding a request open and pacing the calls yourself.
