# auth.md

You are an agent. SocialTap (`socialtap.dev`) gives you an API key for your user in one step of theirs: you register, show them a link, they approve in their browser, and you collect the key. It works whether or not they have an account, and you don't need their email address.

SocialTap is the social media scraper API for developers and AI agents. Send a public link, a handle or a search and get live data back in one schema. Failed requests are free.

- **Resource:** `https://socialtap.dev`. The API takes the key in the `x-api-key` header, or as `Authorization: Bearer <key>`.
- **Authorization server:** `https://socialtap.dev`
- **Pricing:** https://socialtap.dev/pricing/ (100 free credits on a new account, no card)
- **Contact:** support@socialtap.dev

What you do next with the key is in the [agent quickstart](https://socialtap.dev/docs/agent-quickstart/).

## Discover

The metadata below is the authority if this page ever disagrees with it.

```http
GET https://socialtap.dev/.well-known/oauth-protected-resource
GET https://socialtap.dev/.well-known/oauth-authorization-server
```

A 401 names the protected resource's metadata in `WWW-Authenticate` (`resource_metadata`): the API's is the first above, the MCP server's `https://socialtap.dev/.well-known/oauth-protected-resource/mcp` (RFC 9728 §3.1: the resource's path after the well-known one). A key that was sent and refused adds `error="invalid_token"`.

## Pick a method

Register with `service_auth`, the only type. An MCP client that speaks OAuth needs none of this: add `https://socialtap.dev/mcp` and it signs your user in by itself (authorization code with PKCE, dynamic client registration; see the metadata).

## Register

```http
POST https://socialtap.dev/agent/identity
Content-Type: application/json

{
  "type": "service_auth",
  "client_name": "Claude Code",
  "api_key_name": "Acme app (local)"
}
```

Every field is optional:

- `client_name`: what you are. Your user sees it when they decide.
- `api_key_name`: the key's label, at most 60 characters: name the project, so nobody deletes the key by mistake.
- `login_hint`: your user's email address, if you know it, to fill in on their sign-in page. Don't ask for it just for this. Nothing is sent to it.

The answer (201):

```json
{
  "claim_token": "clm_…",
  "claim": {
    "user_code": "WDJB-MJHT",
    "verification_uri": "https://socialtap.dev/agent/connect/",
    "verification_uri_complete": "https://socialtap.dev/agent/connect/#code=WDJBMJHT",
    "expires_in": 900,
    "interval": 5
  },
  "api_key_name": "Acme app (local)",
  "scopes": [
    "endpoints",
    "jobs",
    "account:read"
  ]
}
```

Keep `claim_token` in memory: don't write it down or show it.

Errors: `400 invalid_request` or `400 unsupported_identity_type`: fix the body. `429 rate_limit_exceeded`: stop and tell your user; don't retry in a loop.

## Claim ceremony

Send your user this now, with the real values, before your first poll. We never email it: if it doesn't come from you, it doesn't reach them.

```markdown
**Approve SocialTap access**

Open this link, sign in or create an account, and approve:

{verification_uri_complete}

The code on the page should be {user_code}. It expires in 15 minutes.
```

They see who is asking, the code to compare, and what the key can do, and they approve or refuse. Never approve it yourself, in a browser you control or any other way: the person is the point.

## Exchange the claim

Poll every `interval` seconds:

```http
POST https://socialtap.dev/oauth2/token
Content-Type: application/x-www-form-urlencoded

grant_type=urn:workos:agent-auth:grant-type:claim
&claim_token=clm_…
```

| Answer | What it means |
| --- | --- |
| `authorization_pending` | They haven't decided yet: keep polling |
| `slow_down` | You polled too soon: wait longer |
| `access_denied` | They refused: stop, and don't ask again unless they say so |
| `expired_token` | 15 minutes passed: start again only if they agree |
| `invalid_grant` | It was collected already, or can't be collected any more: stop and say so |

On success (200), once only:

```json
{
  "access_token": "st_live_…",
  "token_type": "Bearer",
  "scope": "endpoints jobs account:read",
  "account_id": "acct_…",
  "key_id": "key_…"
}
```

`access_token` is a live API key that lasts until it is revoked, so there is no `expires_in` and no refresh token. Save it straight to a file git ignores or to a secret manager, as `SOCIALTAP_API_KEY`, without printing it: only the link and the code belong in the conversation.

## Use the access token

```http
GET https://socialtap.dev/v1/tiktok/profile?…
x-api-key: <access_token>
```

Its scopes: `endpoints` (Call data endpoints.); `jobs` (Create, read and cancel background jobs. Includes jobs:read.); `account:read` (Read the account, usage, the credit ledger, the request log, keys, webhook endpoints and events.). It can never manage the account: your user does that in the dashboard.

## Errors

The API's errors are documented at https://socialtap.dev/docs/errors/. A 401 means the key was revoked: register again, with your user's agreement.

## Revocation

```http
POST https://socialtap.dev/oauth2/revoke
Content-Type: application/x-www-form-urlencoded

token=<access_token>
```

Always 200. Your user can also revoke the key in the dashboard (https://socialtap.dev/dashboard/), where it is listed under its label.
