# Your first request

> Create an API key, connect your browser, and list the tabs on example.com with a short curl example.

Let's list the tabs open on `example.com` in your browser. You'll connect the browser,
run one command, and get a JSON response.

You'll need an Apigami account. [Sign up](https://app.apigami.com/register) with your email:
there's no password, you sign in with a code sent to that address. Keep Chrome open throughout
this guide.

## 1. Create an app and its API key

In the [dashboard](https://app.apigami.com), confirm your email address when asked, then choose
**Create your first app**. Under **API keys**, choose **New API key** and copy the key. It's shown
only once.

Save it in your terminal for the examples below. Keep it on your server, out of your frontend code.

```sh
export APIGAMI_API_KEY='YOUR_API_KEY'
```

## 2. Connect your browser

Open the app's install link from the dashboard, in the Chrome you want to use. Sign in with the
same account, install Apigami if the page asks, and choose **Continue**. When an Apigami window
opens showing your email, choose **Allow** to attach this browser to your account.

On the app's **Browsers** page, under **Connected users**, copy your user reference:

```sh
export APIGAMI_USER_REF='YOUR_USER_REF'
```

Open [example.com](https://example.com) in a tab of that browser. This example uses a public page,
so you don't need to sign in to another site.

## 3. List your tabs

Run this in your terminal:

```bash title="Request"
curl https://api.eu.apigami.com/call \
  -H "Authorization: Bearer $APIGAMI_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"user_ref\": \"$APIGAMI_USER_REF\",
    \"op\": \"tabs.list\",
    \"params\": { \"domain\": \"example.com\" }
  }"
```

An approval window opens in your browser. Allow `example.com` and the request completes.
You only need to approve the site once for this app.

Your response will look like this, with your own tab ID:

```json title="Response"
{
  "result": {
    "tabs": [
      {
        "id": 1042,
        "url": "https://example.com/",
        "title": "Example Domain",
        "active": true
      }
    ]
  }
}
```

An empty `tabs` list means there isn't an open tab on that site. Open one and run the command again.

<details>
<summary>Didn't get a result?</summary>

| Response | What to do |
|---|---|
| `extension offline` | Keep the connected browser open and check that Apigami is running there. |
| `unknown user_ref` | Copy the reference again from **Connected users**, with the key of the same app. |
| `extension outdated` | Update Apigami in that browser: Chrome installs the update on its own, and restarting Chrome applies it sooner. |
| `not paired` | Open this app's install link and finish the connection step. |
| `consent requested` | Answer the approval window, then run the command again. |
| `no grant` | Access was declined. Change the site's approval from Apigami's menu in your browser before trying again. |
| `bad client credentials` | Check that you copied the API key correctly and haven't revoked it. |

See [Troubleshooting](/docs/errors/) for other responses.

</details>

## Try it from your code

The same request in server-side JavaScript:

```js title="JavaScript"
const response = await fetch('https://api.eu.apigami.com/call', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.APIGAMI_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    user_ref: process.env.APIGAMI_USER_REF,
    op: 'tabs.list',
    params: { domain: 'example.com' },
  }),
})

const data = await response.json()
if (!response.ok) throw new Error(data.error)
console.log(data.result.tabs)
```

For `request.fetch` in your server code, [request gzip](/docs/operations/#gzip-and-binary-responses)
with outer headers `Accept: application/octet-stream` and `Accept-Encoding: gzip`, plus
`params.responseType: "binary"`. All three are required, even for text or JSON from the site.
Use `curl --compressed` or a client with gzip decoding enabled. This returns the site's raw body
and its status in `X-Apigami-Status`; the `tabs.list` example above keeps its JSON envelope.

Next, [connect your users](/docs/connect/) to your app or [read the page's text](/docs/operations/#tabsread--read-a-tab-by-selector).