---
title: "Create a connect link"
url: https://docs.light-ai.app/api-reference/partners/create-connect-link.md
canonical_url: https://docs.light-ai.app/api-reference/partners/create-connect-link
last_updated: 2026-10-13
summary: "POST /v1/partner/connect_links: A single-use link (7 days at most) a contractor's owner opens to approve your access."
api_status: beta
related:
  - https://docs.light-ai.app/api-reference/partners
---

# Create a connect link

> POST /v1/partner/connect_links: A single-use link (7 days at most) a contractor's owner opens to approve your access.

`POST /v1/partner/connect_links`

A single-use link (7 days at most) a contractor's owner opens to approve your access. The owner signs in (or signs up), sees your verified legal name, domain and every scope, and approves. Never email API keys: send connect links. The `url` is returned only here (and on an Idempotency-Key replay).

|   |   |
| --- | --- |
| Credential | Partner API key (a key of a partner account). |
| Test mode | Live keys only (answers 400 `test_mode_unsupported` to a test key). |
| Idempotency | `Idempotency-Key` supported. See [Idempotency](https://docs.light-ai.app/idempotency). |

## Headers

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `Light-AI-Version` | string |  | Pin a dated API version (defaults to the key's version). One of: `2026-11-01`. |
| `Idempotency-Key` | string |  | Retry-safe writes: the same key and body replay the first response for 24 hours (`Idempotent-Replayed: true`). 8–128 characters. |

## Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `scopes` | string[] | yes | One of: `leads:read`, `leads:write`, `clients:read`, `clients:write`, `projects:read`, `projects:write`, `quotes:read`, `quotes:write`, `quotes:share_link`, `quotes:asset_links`, `webhooks:manage`, `events:read`, `mockups:read`, `mockups:write`, `forms:read`, `forms:write`. 1–16 items. |
| `organization` | string |  | Bind the link to one organization (when you already know its id). Id prefix `org_`. |
| `client_label` | string |  | Required for unbound links: who you are connecting (shown to you on confirmation). 1–120 characters. |
| `external_reference` | string |  | 1–255 characters. |
| `metadata` | object |  |  |
| `redirect_uri` | string |  | https URL on your verified domain to return to after consent. Light AI appends `connect_link` (cl_…), `grant` (grant_…), `organization` (org_…) and `grant_status` (`active`, or `pending` when an unbound link still needs POST /v1/partner/grants/{grant_id}/confirm); your own query parameters are kept, so one redirect_uri can serve every contractor. At most 2048 characters. |
| `expires_in_hours` | integer |  | Default 168 (7 days). 1–168. |

## Response 201

The link (with its url).

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Id prefix `cl_`. |
| `object` | string | yes | Always `connect_link`. |
| `scopes` | string[] | yes | One of: `leads:read`, `leads:write`, `clients:read`, `clients:write`, `projects:read`, `projects:write`, `quotes:read`, `quotes:write`, `quotes:share_link`, `quotes:asset_links`, `webhooks:manage`, `events:read`, `mockups:read`, `mockups:write`, `forms:read`, `forms:write`. |
| `bound_organization` | string \| null | yes | Id prefix `org_`. |
| `client_label` | string \| null | yes |  |
| `external_reference` | string \| null | yes |  |
| `metadata` | object | yes |  |
| `redirect_uri` | string \| null | yes |  |
| `status` | string | yes | One of: `open`, `consumed`, `expired`, `revoked`. |
| `grant` | string \| null | yes | Id prefix `grant_`. |
| `created_at` | timestamp | yes | RFC 3339 timestamp (UTC, milliseconds). |
| `expires_at` | timestamp | yes | RFC 3339 timestamp (UTC, milliseconds). |
| `consumed_at` | timestamp \| null | yes | RFC 3339 timestamp (UTC, milliseconds). |
| `url` | string |  | The link to send to the contractor. Returned only when created. |

## Errors

| Status | Meaning |
| --- | --- |
| `400` | Bad request. [`bad_request`](https://docs.light-ai.app/errors#bad_request), [`test_mode_mismatch`](https://docs.light-ai.app/errors#test_mode_mismatch), [`test_mode_unsupported`](https://docs.light-ai.app/errors#test_mode_unsupported), [`unsupported_api_version`](https://docs.light-ai.app/errors#unsupported_api_version) |
| `401` | Missing or invalid credential. [`authentication_required`](https://docs.light-ai.app/errors#authentication_required), [`invalid_api_key`](https://docs.light-ai.app/errors#invalid_api_key), [`api_key_revoked`](https://docs.light-ai.app/errors#api_key_revoked), [`api_key_expired`](https://docs.light-ai.app/errors#api_key_expired), [`api_key_suspended`](https://docs.light-ai.app/errors#api_key_suspended) |
| `403` | Not allowed. [`insufficient_scope`](https://docs.light-ai.app/errors#insufficient_scope), [`plan_upgrade_required`](https://docs.light-ai.app/errors#plan_upgrade_required), [`organization_paused`](https://docs.light-ai.app/errors#organization_paused), [`organization_off_season`](https://docs.light-ai.app/errors#organization_off_season), [`api_disabled`](https://docs.light-ai.app/errors#api_disabled), [`api_access_not_enabled`](https://docs.light-ai.app/errors#api_access_not_enabled), [`ip_not_allowed`](https://docs.light-ai.app/errors#ip_not_allowed), [`forbidden`](https://docs.light-ai.app/errors#forbidden) |
| `404` | Not found (also for objects of other organizations and for organizations without an active grant). |
| `409` | Conflict. [`stale_state`](https://docs.light-ai.app/errors#stale_state), [`conflict`](https://docs.light-ai.app/errors#conflict), [`idempotency_in_progress`](https://docs.light-ai.app/errors#idempotency_in_progress), [`idempotency_scope_mismatch`](https://docs.light-ai.app/errors#idempotency_scope_mismatch), [`quote_already_decided`](https://docs.light-ai.app/errors#quote_already_decided), [`quote_not_current`](https://docs.light-ai.app/errors#quote_not_current), [`billing_review_required`](https://docs.light-ai.app/errors#billing_review_required) |
| `413` | Request bodies are limited to 256 KB. |
| `415` | The body is not JSON: send Content-Type: application/json. [`unsupported_media_type`](https://docs.light-ai.app/errors#unsupported_media_type) |
| `422` | Validation failed. [`idempotency_key_reused`](https://docs.light-ai.app/errors#idempotency_key_reused) |
| `429` | Rate limited or daily cap reached. See Retry-After and the RateLimit headers. [`rate_limited`](https://docs.light-ai.app/errors#rate_limited), [`daily_cap_reached`](https://docs.light-ai.app/errors#daily_cap_reached) |
| `500` | Unexpected server error. Safe to retry with exponential backoff; quote the Request-Id to support. [`internal_error`](https://docs.light-ai.app/errors#internal_error) |
| `503` | Temporarily unavailable. Retry with exponential backoff. [`service_unavailable`](https://docs.light-ai.app/errors#service_unavailable) |

## Examples

**Request**

curl:

```bash
curl -X POST "https://api.light-ai.app/v1/partner/connect_links" \
  -H "Authorization: Bearer $LIGHT_AI_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "scopes": [
    "leads:read",
    "leads:write",
    "clients:read",
    "projects:read",
    "quotes:read",
    "quotes:write",
    "webhooks:manage"
  ],
  "client_label": "Bright Nights Lighting",
  "external_reference": "ghl-location-AbC123",
  "redirect_uri": "https://app.acme-automations.com/light-ai/connected"
}'
```

JavaScript:

```javascript
const response = await fetch('https://api.light-ai.app/v1/partner/connect_links', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.LIGHT_AI_API_KEY}`,
    'Idempotency-Key': crypto.randomUUID(),
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "scopes": [
      "leads:read",
      "leads:write",
      "clients:read",
      "projects:read",
      "quotes:read",
      "quotes:write",
      "webhooks:manage"
    ],
    "client_label": "Bright Nights Lighting",
    "external_reference": "ghl-location-AbC123",
    "redirect_uri": "https://app.acme-automations.com/light-ai/connected"
  }),
});
const data = await response.json();
```

Python:

```python
import os, uuid, requests

response = requests.post(
    "https://api.light-ai.app/v1/partner/connect_links",
    headers={
        "Authorization": f"Bearer {os.environ['LIGHT_AI_API_KEY']}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
      "scopes": [
        "leads:read",
        "leads:write",
        "clients:read",
        "projects:read",
        "quotes:read",
        "quotes:write",
        "webhooks:manage"
      ],
      "client_label": "Bright Nights Lighting",
      "external_reference": "ghl-location-AbC123",
      "redirect_uri": "https://app.acme-automations.com/light-ai/connected"
    },
    timeout=30,
)
data = response.json()
```

**Response 201**

```json
{
  "id": "cl_3f9c2a7be41d…",
  "object": "connect_link",
  "scopes": [
    "leads:read"
  ],
  "bound_organization": "org_3f9c2a7be41d…",
  "client_label": "string",
  "external_reference": "string",
  "metadata": {},
  "redirect_uri": "string",
  "status": "open",
  "grant": "grant_3f9c2a7be41d…",
  "created_at": "2026-10-12T14:03:11.000Z",
  "expires_at": "2026-10-12T14:03:11.000Z",
  "consumed_at": "2026-10-12T14:03:11.000Z",
  "url": "https://example.com/…"
}
```
