> For the complete documentation index, see [llms.txt](https://developers.gleantap.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers.gleantap.com/authentication.md).

# Authentication

Authenticate with your API Secret or OAuth 2.1.

The v3 API supports two ways to authenticate. Both send a bearer token:

```
Authorization: Bearer <token>
```

|             | **API Secret**                             | **OAuth 2.1**                                             |
| ----------- | ------------------------------------------ | --------------------------------------------------------- |
| Use it for  | Your own server-side integration           | Third-party apps and AI agents acting for a Gleantap user |
| Token       | The **API Secret** from Settings → API     | `gltp_at_...` access token + rotating refresh token       |
| Permissions | Full access to the account                 | Only the scopes the user approves                         |
| Workrooms   | All (narrow per request with `?workroom=`) | Only the workrooms the user selects at consent            |

## API Secret

### Get your API Secret

1. In Gleantap, click **Settings** in the top-right menu and open the **API** tab.
2. If the table is empty, click **Generate New Key**.
3. Copy the value in the **API Secret** column. The **API Key** column is your account ID; v3 doesn't need it.

### Use it

```bash
curl https://api.gleantap.com/v3/contacts \
  -H "Authorization: Bearer YOUR_API_SECRET"
```

You can send the secret bare or with a `gltp_sk_live_` prefix (`Bearer gltp_sk_live_YOUR_API_SECRET`). Both work the same way.

The API Secret is account-scoped and carries **every permission** on the account. There is no per-key scope selection. Keep it on your server, never in browser or mobile code. To revoke it, delete it with the trash icon under **Settings → API**. Generate one secret per integration so you can revoke them independently.

{% hint style="warning" %}
**There is no sandbox.** Every request runs against your real account, and sends reach real people. Develop against a test contact or a dedicated test workroom (`?workroom=...`).
{% endhint %}

{% hint style="info" %}
The same API Secret also works as the `X-SECRET-KEY` header for the [legacy v2 API](https://developers.gleantap.com/v2).
{% endhint %}

## OAuth 2.1

Use OAuth when your app acts on behalf of a Gleantap user. The user signs in to Gleantap, approves the scopes you request, and chooses which workrooms to share.

|                     |                                                                                                                                  |
| ------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| Discovery           | `https://api.gleantap.com/v3/.well-known/oauth-authorization-server`                                                             |
| Authorize           | `https://api.gleantap.com/v3/oauth/authorize`                                                                                    |
| Token               | `POST https://api.gleantap.com/v3/oauth/token`                                                                                   |
| Revoke              | `POST https://api.gleantap.com/v3/oauth/revoke`                                                                                  |
| Introspect          | `POST https://api.gleantap.com/v3/oauth/introspect`                                                                              |
| Client registration | `POST https://api.gleantap.com/v3/oauth/register` ([dynamic client registration](https://datatracker.ietf.org/doc/html/rfc7591)) |

{% stepper %}
{% step %}

### Register your client

Register once via dynamic client registration to get a `client_id` and `client_secret`, with your `redirect_uris`.
{% endstep %}

{% step %}

### Send the user to authorize

Redirect to `/v3/oauth/authorize` with `response_type=code`, `client_id`, `redirect_uri`, `scope` (space-separated), `state`, and a PKCE `code_challenge` with `code_challenge_method=S256`. **PKCE is required.**
{% endstep %}

{% step %}

### Exchange the code

```bash
curl -X POST https://api.gleantap.com/v3/oauth/token \
  -u "CLIENT_ID:CLIENT_SECRET" \
  -d grant_type=authorization_code \
  -d code=AUTH_CODE \
  -d redirect_uri=https://yourapp.example.com/callback \
  -d code_verifier=PKCE_VERIFIER
```

The response contains an `access_token` (`gltp_at_...`) and a `refresh_token`.
{% endstep %}

{% step %}

### Call the API and refresh

Send the access token as `Authorization: Bearer gltp_at_...`. When it expires, use `grant_type=refresh_token`. **Refresh tokens rotate on every use**, so always store the new one you get back.
{% endstep %}
{% endstepper %}

### Scopes

Scopes are `resource:action` pairs. Request only what you need.

| Scope                                                | Grants                                                            |
| ---------------------------------------------------- | ----------------------------------------------------------------- |
| `contacts:read` / `contacts:write`                   | Read / create, update, soft-delete contacts                       |
| `contacts:delete_hard`                               | Permanently delete contacts                                       |
| `events:read` / `events:write`                       | Read / record events                                              |
| `segments:read` / `segments:write`                   | Read and preview / manage segments                                |
| `templates:read` / `templates:write`                 | Read / manage message templates                                   |
| `campaigns:manage`                                   | Create, schedule, cancel campaigns; read recipients and analytics |
| `flows:read` / `flows:write`                         | Read / create and edit flows                                      |
| `flows:publish`                                      | Publish and unpublish flows                                       |
| `messaging:send`                                     | Send transactional SMS, email, and voice                          |
| `conversations:read`                                 | Read conversations and messages                                   |
| `pipelines:manage`                                   | Manage pipelines and stages                                       |
| `tasks:read` / `tasks:manage`                        | Read / manage tasks                                               |
| `appointments:read` / `appointments:manage`          | Read / manage appointments                                        |
| `calendars:read` / `calendars:write`                 | Read / manage booking calendars                                   |
| `forms:manage`                                       | Manage forms and read submissions                                 |
| `pages:read` / `pages:write`                         | Read / manage landing pages                                       |
| `keyword_campaigns:read` / `keyword_campaigns:write` | Read / manage SMS keyword campaigns                               |
| `scorecards:read` / `scorecards:write`               | Read / manage scorecards and metrics                              |
| `webhooks:manage`                                    | Manage webhook endpoints                                          |
| `workrooms:configure`                                | Change workroom settings                                          |
| `staff:read`                                         | Read staff users                                                  |
| `secondary_objects:read`                             | Read synced records (memberships, classes, …)                     |
| `copilot:invoke`                                     | Use Gleantap's AI assistant features                              |

The live list is always in the `scopes_supported` field of the discovery document.

### Workroom access

On the consent screen the user chooses which workrooms your app can see. Requests for anything in other workrooms return `not_found`, even if the record exists.

## Connecting an AI assistant?

You don't need to build OAuth yourself. See [Connect AI Tools (MCP)](/connect-ai-tools-mcp.md).
