> ## Documentation Index
> Fetch the complete documentation index at: https://docs.instantcampaign.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# OAuth apps

> Connect your own software to a workspace with OAuth 2.0 instead of API keys — as a signed-in member, or as the app itself with client credentials.

An **OAuth app** is a client id (and, usually, a secret) that your own software uses to get access tokens for this workspace. Compared with an API key, the secret can be rotated without touching the code that uses it, tokens expire after an hour, and every connection is visible and revocable under **Connected apps**.

<Note>
  OAuth apps are available on the **Pro** and **Enterprise** plans and need the **API keys** permission (Owners, Administrators, or a custom role that grants it). A workspace can have up to 10 apps.
</Note>

## Two ways to connect

| | On behalf of a member | As the app itself |
| - | - | - |
| Grant | `authorization_code` (+ `refresh_token`) | `client_credentials` |
| Who approves | A member with the API keys permission, on the consent page | Nobody — the app authenticates with its secret |
| Acts as | That member, on this workspace | The app's creator, on this workspace |
| Typical use | A tool your team members sign in to | A backend job, a sync service, a CRM connector |
| Token lifetime | 1 h access, refreshed automatically for 90 days | 1 h access; the app requests a new one when it expires |

Both act **only on the workspace that owns the app**. An OAuth app can never be granted for another workspace — that is the platform-wide kind of client, which only InstantCampaign registers.

## Create an app

<Steps>
  <Step title="Open Settings → Developers → OAuth apps">
    Click **Create app**.
  </Step>

  <Step title="Choose the client type">
    **Confidential** for a server that can keep a secret. **Public** for a desktop, mobile or browser app that cannot — it gets no secret and must use PKCE (see below).
  </Step>

  <Step title="Choose how it connects">
    Tick *on behalf of a signed-in member*, *as the app itself*, or both. The second is only offered to confidential apps.
  </Step>

  <Step title="Redirect URIs and permissions">
    For the member flow, list the exact URLs the browser may return to — `https://…`, or `http://localhost:<port>` for a desktop app. Tick the permissions (scopes) the app may request; the person approving still sees them.
  </Step>

  <Step title="Copy the secret">
    It is shown once. Store it where your software reads its configuration. You can rotate it later; the old one stops working the moment you do.
  </Step>
</Steps>

## Endpoints

| Purpose | URL |
| - | - |
| Authorization (browser) | `https://instantcampaign.ai/oauth/authorize` |
| Token | `https://instantcampaign.ai/api/oauth/token` |
| Revocation | `https://instantcampaign.ai/api/oauth/revoke` |
| Who am I | `https://instantcampaign.ai/api/v1/me` |
| Discovery | `https://instantcampaign.ai/.well-known/oauth-authorization-server` |

Access tokens start with `ica_` and are sent exactly like an API key: `Authorization: Bearer ica_…`. Every endpoint in the [API reference](/api-reference) accepts them.

## As the app itself (client credentials)

```bash theme={null}
curl -s -X POST https://instantcampaign.ai/api/oauth/token \
  -d grant_type=client_credentials \
  -d client_id=icapp_… -d client_secret=icsec_… \
  -d scope="contacts:read contacts:write"
```

The answer carries `access_token`, `expires_in` (3600) and `scope`, and no refresh token: request a new token the same way when this one expires. The connection appears under **Connected apps**, attributed to whoever created the app; disconnecting it there revokes every token at once.

## On behalf of a member (authorization code)

1. Send the browser to `/oauth/authorize?client_id=…&redirect_uri=…&response_type=code&scope=…&state=…` (add `code_challenge` and `code_challenge_method=S256` for PKCE — required for a public app, recommended for every app).
2. The member sees the consent page for this workspace and clicks **Allow access**. The browser returns to your `redirect_uri` with `code` and your `state`.
3. Exchange the code at the token endpoint with `grant_type=authorization_code`, the same `redirect_uri`, your credentials (or, for a public app, just `client_id` and `code_verifier`).
4. Use `refresh_token` with `grant_type=refresh_token` before the hour is up. Refresh tokens rotate on each use — keep the new one. Reusing an old one revokes the connection.

## Security notes

* A **public** app has no secret; PKCE binds each code to the app that started the flow, and a request without `code_challenge` is refused.
* Redirect URIs are matched **exactly**. Register every one you use.
* Deleting an app revokes its connections first, so a deleted client id never leaves a working token behind.
* A support session from InstantCampaign staff can view your apps but cannot create, rotate or delete them.
