# Quickstart

Four steps from nothing to your first review request. You need a Citypicked account and a terminal.

Source: https://citypicked.com/en/developers/quickstart

## 1. Make an API key

1. In the app, open **Settings > Sending > API** ([go there](https://app.citypicked.com/settings/api)). Owners and managers can do this.
2. Name the key and pick **Read and send requests** if it should send.
3. Copy the key right away. It is shown only once.

Keep it in a variable for the next steps. The examples show a placeholder.

```bash
export CITYPICKED_API_KEY=cp_live_xxxxxxxx
```

> Sending requests through the API is part of the Pro and Business plans. Reading works on every plan.

## 2. Make your first call

`GET /v1/me` shows the account, the key and whether it can send. Every working key gets 200 here.

curl:

```bash
curl "https://api.citypicked.com/v1/me" \
  -H "Authorization: Bearer cp_live_xxxxxxxx"
```

JavaScript:

```js
const res = await fetch("https://api.citypicked.com/v1/me", {
  headers: {
    Authorization: "Bearer cp_live_xxxxxxxx",
  },
});
const data = await res.json();
console.log(res.status, data);
```

Python:

```python
import requests

res = requests.get(
    "https://api.citypicked.com/v1/me",
    headers={"Authorization": "Bearer cp_live_xxxxxxxx"},
)
print(res.status_code, res.json())
```

Answer

```json
{
  "account": {
    "id": "0b7c8f4e-5a1d-4c2e-9f3a-6d8e2b1c4a70",
    "name": "Sunnyside Salon",
    "plan": "pro",
    "language": "en",
    "time_zone": "America/New_York"
  },
  "key": {
    "name": "Booking system",
    "scopes": [
      "read",
      "send"
    ]
  },
  "can_send": true,
  "credits": {
    "balance": 180
  }
}
```

## 3. Send one review request

`POST /v1/requests` sends to up to 100 customers at once. `consent: true` confirms the customers agreed to hear from you. With an `Idempotency-Key`, the same call within 24 hours goes out only once.

curl:

```bash
curl -X POST "https://api.citypicked.com/v1/requests" \
  -H "Authorization: Bearer cp_live_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: booking-1042" \
  -d '{
  "location_id": "5b1d0c7e-2f4a-4c3e-9a51-7d2e8f1b6a40",
  "channel": "email",
  "consent": true,
  "contacts": [
    {
      "name": "Emma Clark",
      "email": "emma@example.com"
    }
  ]
}'
```

JavaScript:

```js
const res = await fetch("https://api.citypicked.com/v1/requests", {
  method: "POST",
  headers: {
    Authorization: "Bearer cp_live_xxxxxxxx",
    "Content-Type": "application/json",
    "Idempotency-Key": "booking-1042",
  },
  body: JSON.stringify({
    "location_id": "5b1d0c7e-2f4a-4c3e-9a51-7d2e8f1b6a40",
    "channel": "email",
    "consent": true,
    "contacts": [
      {
        "name": "Emma Clark",
        "email": "emma@example.com"
      }
    ]
  }),
});
const data = await res.json();
console.log(res.status, data);
```

Python:

```python
import requests

res = requests.post(
    "https://api.citypicked.com/v1/requests",
    headers={"Authorization": "Bearer cp_live_xxxxxxxx", "Idempotency-Key": "booking-1042"},
    json={
        "location_id": "5b1d0c7e-2f4a-4c3e-9a51-7d2e8f1b6a40",
        "channel": "email",
        "consent": True,
        "contacts": [
            {
                "name": "Emma Clark",
                "email": "emma@example.com",
            },
        ],
    },
)
print(res.status_code, res.json())
```

Answer

```json
{
  "results": [
    {
      "index": 0,
      "outcome": "created",
      "request_id": "c3f1a9e2-7b4d-4e8a-b6c2-1f9d3e5a7b20"
    }
  ],
  "created": 1
}
```

- `created` means the request is on its way
- `duplicate` means this customer was asked recently. The window is 30 days unless the account changed it in the app
- `opted_out`, `invalid`, `no_credits` and `consent_method_missing` say why nothing went out

> For SMS, use `"channel": "sms"` and a number like `+1 201 555 0123`. SMS to US and Canadian numbers also need `consent_method` and go out from the business's own number once the carriers have checked its business details.

## 4. Read the result

Use the `request_id` from the answer to check where it stands. `status` moves from `sent` through `delivered` and `clicked` to `rated`, and `rating` shows the stars.

curl:

```bash
curl "https://api.citypicked.com/v1/requests/c3f1a9e2-7b4d-4e8a-b6c2-1f9d3e5a7b20" \
  -H "Authorization: Bearer cp_live_xxxxxxxx"
```

JavaScript:

```js
const res = await fetch("https://api.citypicked.com/v1/requests/c3f1a9e2-7b4d-4e8a-b6c2-1f9d3e5a7b20", {
  headers: {
    Authorization: "Bearer cp_live_xxxxxxxx",
  },
});
const data = await res.json();
console.log(res.status, data);
```

Python:

```python
import requests

res = requests.get(
    "https://api.citypicked.com/v1/requests/c3f1a9e2-7b4d-4e8a-b6c2-1f9d3e5a7b20",
    headers={"Authorization": "Bearer cp_live_xxxxxxxx"},
)
print(res.status_code, res.json())
```

Answer

```json
{
  "id": "c3f1a9e2-7b4d-4e8a-b6c2-1f9d3e5a7b20",
  "location_id": "5b1d0c7e-2f4a-4c3e-9a51-7d2e8f1b6a40",
  "channel": "email",
  "source": "api",
  "status": "rated",
  "contact": {
    "name": "Emma C.",
    "email": "em***@example.com",
    "phone": null
  },
  "rating": 5,
  "created_at": "2026-11-08T09:30:00Z",
  "sent_at": "2026-11-08T09:30:04Z",
  "clicked_at": "2026-11-08T10:12:40Z",
  "rated_at": "2026-11-08T10:13:05Z"
}
```

Instead of asking again, you can have it sent to you. With [webhooks](https://citypicked.com/en/developers/webhooks) every rating and every piece of feedback arrives at your URL right away.
