# Your first call

> Get an OAuth token and make a successful list_businesses call against the Caramel API in about 5 minutes.

This walkthrough ends with a working `list_businesses` response in your terminal. It takes about 5 minutes if you have your client ID ready.

## Before you begin

- A Caramel account at [caramelme.com](https://caramelme.com).
- An OAuth client ID. If your redirect URI is `http://localhost:3000/callback` or another `localhost` URL, you can self-register in step 2 — no manual setup needed. Otherwise, email `aymen@reactmotion.com` with your app name, redirect URIs, and requested scopes.
- `curl` installed locally.

## Step 1 — Confirm the endpoints

```bash
curl -s https://app.caramelme.com/.well-known/oauth-authorization-server | \
  python3 -m json.tool
```

You should see a JSON document with `authorization_endpoint`, `token_endpoint`, and `registration_endpoint`. If this call fails, check your network connection before continuing.

## Step 2 — Get a client ID

**Skip this step** if you already have a client ID issued manually.

Register a client for `http://localhost:3000/callback`:

```bash
curl -s -X POST https://api.caramelme.com/functions/v1/mcp-oauth/register \
  -H "Content-Type: application/json" \
  -d '{
    "client_name":                "my-first-app",
    "redirect_uris":              ["http://localhost:3000/callback"],
    "grant_types":                ["authorization_code", "refresh_token"],
    "response_types":             ["code"],
    "token_endpoint_auth_method": "none"
  }'
```

Copy the `client_id` from the response:

```json
{
  "client_id":    "my-first-app",
  "redirect_uris": ["http://localhost:3000/callback"]
}
```

```bash
export CLIENT_ID="my-first-app"
export REDIRECT_URI="http://localhost:3000/callback"
```

## Step 3 — Generate a PKCE pair

Run this Node.js snippet to get a verifier and challenge. Keep both — you'll need them in the next two steps.

```js
// save as pkce.mjs, run with: node pkce.mjs
import crypto from 'node:crypto';

const verifier  = crypto.randomBytes(32).toString('base64url');
const challenge = crypto.createHash('sha256').update(verifier).digest('base64url');

console.log('VERIFIER: ', verifier);
console.log('CHALLENGE:', challenge);
```

```bash
node pkce.mjs
# VERIFIER:  5rq1oKGcE9...
# CHALLENGE: X3Lx8pMkT0...

export VERIFIER="5rq1oKGcE9..."
export CHALLENGE="X3Lx8pMkT0..."
```

Alternatively, in Python:

```py
# save as pkce.py, run with: python3 pkce.py
import secrets, hashlib, base64

verifier  = base64.urlsafe_b64encode(secrets.token_bytes(32)).rstrip(b'=').decode()
challenge = base64.urlsafe_b64encode(
    hashlib.sha256(verifier.encode()).digest()
).rstrip(b'=').decode()

print('VERIFIER: ', verifier)
print('CHALLENGE:', challenge)
```

## Step 4 — Authorize (get a code)

Open this URL in a browser. Replace the placeholder values with your own:

```
https://api.caramelme.com/functions/v1/mcp-oauth
  ?response_type=code
  &client_id=YOUR_CLIENT_ID
  &redirect_uri=http://localhost:3000/callback
  &code_challenge=YOUR_CHALLENGE
  &code_challenge_method=S256
  &state=any-random-string
  &scope=meta:read
```

Or build it in the terminal:

```bash
STATE=$(openssl rand -hex 16)
echo "Open this URL in your browser:"
echo "https://api.caramelme.com/functions/v1/mcp-oauth?response_type=code&client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&code_challenge=${CHALLENGE}&code_challenge_method=S256&state=${STATE}&scope=meta%3Aread"
```

Enter your Caramel email address. Caramel sends a magic-link email. Click the link.

The browser redirects to `http://localhost:3000/callback?code=AUTH_CODE&state=…`. Nothing runs at that URL yet — that's fine. Copy the `code` parameter from the browser's address bar.

```bash
export AUTH_CODE="the-code-from-the-url"
```

## Step 5 — Exchange the code for a token

```bash
curl -s -X POST https://api.caramelme.com/functions/v1/mcp-oauth \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "code=${AUTH_CODE}" \
  -d "redirect_uri=${REDIRECT_URI}" \
  -d "client_id=${CLIENT_ID}" \
  -d "code_verifier=${VERIFIER}" | python3 -m json.tool
```

You get back:

```json
{
  "access_token":  "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "rt_8f3e21c4b7d94a1f8e2c6b5d4a3f2e1d",
  "expires_in":    3600,
  "token_type":    "Bearer",
  "scope":         "meta:read"
}
```

```bash
export TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
```

> **Note** The authorization code is single-use. If you get `400 invalid_grant`, start again at step 4 — the code either expired (codes are short-lived) or was already exchanged.

## Step 6 — Call `list_businesses`

```bash
curl -s -X POST https://app.caramelme.com/api/functions/caramel-mcp \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method":  "tools/call",
    "id":      1,
    "params":  { "name": "caramel.v1.business.list", "arguments": {} }
  }' | python3 -m json.tool
```

You should see the businesses your account has access to:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\"businesses\":[{\"id\":\"bus_01h7m9k0aabcdefghj1234567\",\"name\":\"Brewmaster Café\",\"tier\":\"growth\",\"role\":\"owner\"}]}"
      }
    ]
  }
}
```

Parse the `result.content[0].text` field — it's a JSON string that contains the actual payload.

```bash
export BUSINESS_ID="bus_01h7m9k0aabcdefghj1234567"
```

That's it. You now have a working token and a business ID. Every other tool call follows the same shape — change the `name` and `arguments` fields.

## Troubleshooting

| Symptom | Likely cause | Fix |
|---|---|---|
| `400 invalid_grant` on code exchange | Code expired or already used | Repeat step 4 to get a fresh code |
| `400 invalid_grant` on refresh | Refresh token rotated out | Re-run the full authorize flow |
| `401 unauthorized` on tool call | Access token expired | Run the refresh call; see [Authentication](authentication) |
| `403 scope_required` | Token scope too narrow | Re-authorize with the required scope |
| Empty `businesses` array | No businesses linked to this account | Sign into [caramelme.com](https://caramelme.com) and confirm at least one business exists |
| `-32001` JSON-RPC error | Token expired mid-session | Refresh the access token and retry the call |

## Next steps

- [Quickstart](quickstart) — the same flow as a one-page reference card.
- [Authentication](authentication) — refresh rotation, scope table, error codes, and edge cases.
- [Reference](../reference/index) — every tool in the catalog.
