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

# OAuth 2.0

> Set up OAuth 2.0 authentication for your Lofty API integration.

OAuth 2.0 is the recommended authentication method for multi-tenant integrations. Lofty supports two grant types:

| Grant Type                    | Use Case                                            |
| ----------------------------- | --------------------------------------------------- |
| **Authorization Code**        | Web apps where a user authorizes access via browser |
| **Authorization Code + PKCE** | SPAs and native apps (no client secret required)    |

## Prerequisites

You need a **Developer Platform account** and a **registered application**. Sign up at the [Lofty Developer Portal](https://api.lofty.com/vendor/frontend/static/index.html#/login).

## Authorization Code flow

<Steps>
  <Step title="Register your application">
    Create a new application in the Developer Portal. Provide your app name, description, and redirect URI(s).

    New applications start in **Development Mode** — you can test the full OAuth flow without review.
  </Step>

  <Step title="Obtain credentials">
    After registration, you'll receive a **Client ID** and **Client Secret**.

    <Warning>
      Never expose your Client Secret in client-side code, public repositories, or logs.
    </Warning>
  </Step>

  <Step title="Request an access token">
    Exchange your credentials for an access token via the OAuth 2.0 authorization code flow.

    ```bash theme={null}
    curl -X POST https://crm.lofty.com/api/user-web/oauth/token \
      -H "Content-Type: application/x-www-form-urlencoded" \
      -H "Authorization: Basic <BASE64_OF_CLIENT_ID:CLIENT_SECRET>" \
      -d "grant_type=authorization_code" \
      -d "code=<AUTHORIZATION_CODE>" \
      -d "client_id=<CLIENT_ID>" \
      -d "redirect_uri=<REDIRECT_URI>"
    ```

    The `Authorization` header uses HTTP Basic authentication: Base64-encode `<CLIENT_ID>:<CLIENT_SECRET>` to produce the credential string.

    For complete token endpoint details, see the [OAuth 2.0 API Reference](https://help.lofty.com/hc/en-us/articles/47801571926811).
  </Step>

  <Step title="Authenticate requests">
    Pass the access token in the `Authorization` header:

    ```bash theme={null}
    curl https://api.lofty.com/v1.0/leads \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer <ACCESS_TOKEN>"
    ```
  </Step>
</Steps>

## PKCE flow

For SPAs and native apps that cannot securely store a client secret. Uses a code verifier/challenge instead.

```bash theme={null}
curl -X POST https://crm.lofty.com/api/user-web/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "client_id=<CLIENT_ID>" \
  -d "code=<AUTHORIZATION_CODE>" \
  -d "code_verifier=<CODE_VERIFIER>" \
  -d "redirect_uri=<REDIRECT_URI>"
```

No `client_secret` is required. The Lofty CLI uses this flow for interactive browser login (`lofty-cli auth login-browser`).

## Permission scopes

Each token is scoped to the endpoints granted to your application in the Developer Portal. Calling an out-of-scope endpoint returns `HTTP 403`:

```json theme={null}
{
  "code": 200100,
  "message": "Sorry, the vendor does not have permission for this API."
}
```

<Warning>
  **Adding scopes is a breaking change.** When you add new permission scopes to a production app, all existing tokens are invalidated (`authorized_api_ids` changes). Existing users must re-authorize your app. Always notify users before adding scopes.
</Warning>

## Rate limits by app mode

| Mode            | Rate Limit       |
| --------------- | ---------------- |
| **Development** | 100 requests/min |
| **Production**  | 500 requests/min |

Rate limits are **per-app**, not per-account. Set on `app_info.rate_limit_per_minute`.

## App lifecycle

| Stage            | Description                                                       |
| ---------------- | ----------------------------------------------------------------- |
| **Development**  | Test the full OAuth flow without review. Rate limit: 100/min.     |
| **Under Review** | Submitted for production access.                                  |
| **Production**   | Approved. Real users can authorize your app. Rate limit: 500/min. |
| **Declined**     | Not approved. Edit and resubmit at any time.                      |

## Updating a production app

Once in production, edits require review before taking effect. Your app continues operating with the current approved configuration during review.

**Non-breaking changes** — app name, description, redirect URIs, removing scopes. Existing connections are unaffected.

**Breaking changes** — adding new permission scopes invalidates existing tokens. Users must re-authorize. Notify users before submitting.

<Accordion title="Can I edit while a review is pending?">
  No. Edit controls are locked during review. Cancel the pending edit first if you need to make urgent changes.
</Accordion>

<Accordion title="What happens if my edit is declined?">
  Your app continues operating with its current configuration. You'll receive the decline reason via email and can resubmit after making adjustments.
</Accordion>
