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

# Official Make integration API

> OAuth 2.0, attached webhook, link, and conversion endpoints used by the private-preview Biqli Make integration.

<Warning>
  This is a pre-release implementation reference. The official Biqli app is
  not yet installable from Make's public app directory and must not be treated
  as supported until the documented end-to-end smoke tests pass.
</Warning>

The official Biqli Make integration uses an OAuth 2.0 authorization-code
connection, dedicated attached webhooks, instant triggers, and workspace-scoped
action modules. Each Make connection is bound to one Biqli workspace.

<Note>
  This page documents the Biqli-managed client and endpoints used by the
  official Make app. To connect your own product directly, create a
  [self-service OAuth app](/docs/api-reference/oauth-apps) and request only the
  granular scopes it needs.
</Note>

## Connection flow

When you create a Biqli connection in Make, Make redirects you to Biqli. Sign
in, select one workspace, and approve the requested permissions. Biqli then
returns you to Make through the exact registered callback URL.

| Purpose                    | Method | URL                                  |
| :------------------------- | :----- | :----------------------------------- |
| Authorization              | `GET`  | `https://biq.li/oauth/authorize`     |
| Token exchange and refresh | `POST` | `https://biq.li/api/v1/oauth/token`  |
| Token revocation           | `POST` | `https://biq.li/api/v1/oauth/revoke` |
| Connection test and label  | `GET`  | `https://biq.li/api/v1/oauth/me`     |

The authorization request includes:

| Parameter       | Required | Description                                                    |
| :-------------- | :------- | :------------------------------------------------------------- |
| `client_id`     | Yes      | Identifier for the official Make OAuth client managed by Biqli |
| `redirect_uri`  | Yes      | Exact callback URL registered for the official Make app        |
| `response_type` | Yes      | Must be `code`                                                 |
| `state`         | Yes      | Opaque value generated and verified by Make                    |
| `scope`         | Yes      | Space-separated permissions required by the official modules   |

The user must own the selected workspace or have the workspace permissions
required by the requested scopes. Workspace roles, product entitlements,
quotas, and resource ownership continue to apply after OAuth approval.

### Connect from Make

Authorized pre-release testers will connect the app from a Make scenario:

1. Add any Biqli module and select **Create a connection**.
2. Continue to Biqli, sign in, and select the intended workspace.
3. Review and approve the requested permissions.
4. Return to Make and confirm the connection label shows the selected
   workspace.
5. Use a separate Make connection when a scenario needs another workspace.

Never paste a Biqli client secret, access token, or refresh token into a module
field. The official connection stores and refreshes credentials server-side.

### Permissions requested by Make

| Scope               | Access                                                              |
| :------------------ | :------------------------------------------------------------------ |
| `workspace.read`    | Read the connected user and workspace identity                      |
| `webhooks.read`     | Read representative event payloads                                  |
| `webhooks.write`    | Attach and detach Make webhook subscriptions                        |
| `links.read`        | Retrieve links from the connected workspace                         |
| `links.write`       | Create, update, upsert, and delete links in the connected workspace |
| `conversions.write` | Record attributed lead and sale events in the connected workspace   |

## Token exchange and refresh

Make exchanges the single-use authorization code through a confidential,
server-to-server request. The client secret never passes through the browser.

```bash theme={null}
curl --request POST \
  --url https://biq.li/api/v1/oauth/token \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=authorization_code' \
  --data-urlencode 'client_id=YOUR_CLIENT_ID' \
  --data-urlencode 'client_secret=YOUR_CLIENT_SECRET' \
  --data-urlencode 'code=AUTHORIZATION_CODE' \
  --data-urlencode 'redirect_uri=YOUR_REGISTERED_REDIRECT_URI'
```

A successful response contains an access token, rotating refresh token, access
token lifetime, refresh-family lifetime, and granted scopes. Authorization
codes expire after five minutes. Access tokens expire after one hour by
default.

When the access token expires, Make exchanges the current refresh token:

```bash theme={null}
curl --request POST \
  --url https://biq.li/api/v1/oauth/token \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=refresh_token' \
  --data-urlencode 'client_id=YOUR_CLIENT_ID' \
  --data-urlencode 'client_secret=YOUR_CLIENT_SECRET' \
  --data-urlencode 'refresh_token=YOUR_REFRESH_TOKEN'
```

Every successful refresh returns a new access token and refresh token. Make
must replace both stored values. Reusing the previous refresh token revokes the
connection and its attached webhook subscriptions.

## Test or revoke the connection

Make validates and labels the connection with:

```bash theme={null}
curl --request GET \
  --url https://biq.li/api/v1/oauth/me \
  --header 'Accept: application/json' \
  --header "Authorization: Bearer $ACCESS_TOKEN"
```

The response identifies the OAuth connection, user, and selected workspace.
The official app displays the workspace name in Make's connection list.

Revocation accepts the current access token or refresh token:

```bash theme={null}
curl --request POST \
  --url https://biq.li/api/v1/oauth/revoke \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'client_id=YOUR_CLIENT_ID' \
  --data-urlencode 'client_secret=YOUR_CLIENT_SECRET' \
  --data-urlencode 'token=TOKEN_TO_REVOKE'
```

Revocation invalidates the connection's access token and deletes only webhook
subscriptions owned by that OAuth connection.

## Instant triggers

The planned app will provide these instant triggers:

| Make module        | Event          |
| :----------------- | :------------- |
| Watch Link Created | `link.created` |
| Watch Link Updated | `link.updated` |
| Watch Link Deleted | `link.deleted` |
| Watch Link Clicked | `link.clicked` |
| Watch Lead Created | `lead.created` |
| Watch Sale Created | `sale.created` |

Each module uses a dedicated attached webhook. When you activate a trigger,
Make creates a unique receiver URL and registers it with Biqli. When you remove
the trigger, Make detaches that exact subscription.

### Attach a webhook

```bash theme={null}
curl --request POST \
  --url https://biq.li/api/v1/integrations/make/webhooks \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --header "Authorization: Bearer $ACCESS_TOKEN" \
  --data '{
    "target_url": "https://hook.example.make.com/REDACTED",
    "event": "link.created"
  }'
```

```json theme={null}
{
  "id": "wh_01M34EXAMPLE000000000000",
  "event": "link.created"
}
```

Make stores the returned `id` with its webhook component and uses it when the
trigger is detached. Biqli accepts only public HTTP or HTTPS destinations. It
rejects private, loopback, link-local, reserved, credential-bearing, and
unresolvable targets. A target URL can have only one subscription in a
workspace.

### Detach a webhook

```bash theme={null}
curl --request DELETE \
  --url https://biq.li/api/v1/integrations/make/webhooks/wh_01M34EXAMPLE000000000000 \
  --header 'Accept: application/json' \
  --header "Authorization: Bearer $ACCESS_TOKEN"
```

Detachment is idempotent. Biqli removes the endpoint only when its public ID,
workspace, Make receiver type, and creating OAuth connection all match.

### Load representative trigger data

```bash theme={null}
curl --request GET \
  --url https://biq.li/api/v1/integrations/make/events/link.created/sample \
  --header 'Accept: application/json' \
  --header "Authorization: Bearer $ACCESS_TOKEN"
```

Unlike the Zapier REST Hook sample, the Make sample is one canonical event
object:

```json theme={null}
{
  "id": "evt_01M34EXAMPLE000000000000",
  "event": "link.created",
  "createdAt": "2026-09-27T12:00:00+00:00",
  "data": {
    "id": "biq_lnk_01M34EXAMPLE00000000000",
    "externalId": "campaign_1842",
    "name": "Example campaign",
    "url": "https://example.com/products/new",
    "shortUrl": "https://biq.li/example",
    "key": "example",
    "workspaceId": "biq_ws_01M34EXAMPLE00000000000"
  }
}
```

See [Webhook event types](/webhooks/event-types) for every event payload and
[Delivery attempts and retries](/webhooks/delivery-retries) for delivery
semantics. Treat delivery as at least once and deduplicate by event `id`.

## Action modules

The planned app will expose these workspace-scoped actions:

| Make module     | Scope               | Method and endpoint                                | Complete field contract                                    |
| :-------------- | :------------------ | :------------------------------------------------- | :--------------------------------------------------------- |
| Create a Link   | `links.write`       | `POST /api/v1/integrations/make/links`             | [Create a link](/docs/api-reference/links/create)          |
| Retrieve a Link | `links.read`        | `GET /api/v1/integrations/make/links/{link}`       | [Retrieve a link](/docs/api-reference/links/get)           |
| Update a Link   | `links.write`       | `PATCH /api/v1/integrations/make/links/{link}`     | [Update a link](/docs/api-reference/links/update)          |
| Upsert a Link   | `links.write`       | `POST /api/v1/integrations/make/links/upsert`      | See [Upsert a link](#upsert-a-link)                        |
| Delete a Link   | `links.write`       | `DELETE /api/v1/integrations/make/links/{link}`    | [Delete a link](/docs/api-reference/links/delete)          |
| Track a Lead    | `conversions.write` | `POST /api/v1/integrations/make/conversions/leads` | [Track a lead](/docs/api-reference/conversions/track-lead) |
| Track a Sale    | `conversions.write` | `POST /api/v1/integrations/make/conversions/sales` | [Track a sale](/docs/api-reference/conversions/track-sale) |

The OAuth connection selects the workspace. Requests never accept an internal
workspace database ID. Link IDs outside the connected workspace return `404`
without revealing whether the resource exists.

### Link actions

**Create a Link** requires `long_url`. It returns the complete link under
`link`. A synchronously accepted link returns `201`; a link waiting for an
asynchronous safety scan returns `202` with `status: "pending"`.

**Update a Link** is a partial update. Omitted fields remain unchanged. Send
JSON `null` only for nullable fields supported by the canonical update contract.

#### Upsert a link

Upsert requires `external_id` and `long_url`. Biqli updates the workspace link
with that external ID when it exists, or creates it when it does not. The
response includes `operation: "updated"` or `operation: "created"`.

```bash theme={null}
curl --request POST \
  --url https://biq.li/api/v1/integrations/make/links/upsert \
  --header "Authorization: Bearer $ACCESS_TOKEN" \
  --header 'Content-Type: application/json' \
  --data '{
    "external_id": "crm_contact_1842",
    "long_url": "https://example.com/customers/1842",
    "name": "Customer 1842"
  }'
```

**Delete a Link** uses the public `biq_lnk_...` ID and runs the same cleanup,
activity logging, and `link.deleted` event behavior as a dashboard deletion.

### Conversion actions

Track Lead and Track Sale use Biqli's canonical attribution, validation,
currency, and durable idempotency paths. Conversion tracking must be enabled in
the connected workspace.

Send a stable `Idempotency-Key` on every retry. Track Lead also requires a
stable `eventId`. Track Sale requires a stable `invoiceId` and can also receive
`eventId`. Reusing an idempotency identity with the identical validated payload
returns the stored response and sets `Idempotency-Replayed: true`. Reusing it
with different data returns `409 idempotency_conflict`.

```bash theme={null}
curl --request POST \
  --url https://biq.li/api/v1/integrations/make/conversions/leads \
  --header "Authorization: Bearer $ACCESS_TOKEN" \
  --header 'Idempotency-Key: lead_signup_1842' \
  --header 'Content-Type: application/json' \
  --data '{
    "clickId": "fGQimsCLcpoa",
    "eventId": "lead_signup_1842",
    "eventName": "Signed up",
    "customerExternalId": "customer_1842"
  }'
```

```bash theme={null}
curl --request POST \
  --url https://biq.li/api/v1/integrations/make/conversions/sales \
  --header "Authorization: Bearer $ACCESS_TOKEN" \
  --header 'Idempotency-Key: invoice_1842' \
  --header 'Content-Type: application/json' \
  --data '{
    "clickId": "fGQimsCLcpoa",
    "customerExternalId": "customer_1842",
    "amount": 1299,
    "currency": "usd",
    "invoiceId": "invoice_1842",
    "eventName": "Purchase"
  }'
```

Amounts use the currency's integer minor unit. For example, `1299` means
`$12.99` USD.

## Make an API Call

The planned app includes one universal **Make an API Call** module. It accepts
only paths relative to `https://biq.li`; it cannot send the OAuth token
to another host. The pre-release module allowlists `/api/v1/oauth/me` and the
`/api/v1/integrations/make/*` namespace, rejects parent-directory segments,
and still enforces the connection's OAuth scopes and workspace permissions.

## Errors

| Status | Meaning                                                                     |
| :----- | :-------------------------------------------------------------------------- |
| `400`  | Invalid OAuth request, client, redirect URI, grant, or scope                |
| `401`  | Missing, expired, revoked, or invalid credentials                           |
| `403`  | Missing OAuth scope, workspace permission, entitlement, or tracking setting |
| `404`  | Unsupported event or resource unavailable in the connected workspace        |
| `409`  | Idempotency identity reused with a different conversion payload             |
| `422`  | Invalid webhook, link, attribution, conversion, or action payload           |
| `429`  | Request rate limit exceeded                                                 |

OAuth errors contain `error` and `error_description`. Workspace API errors
contain `error.code`, `error.message`, and `request_id`. Validation details are
included when available.

## Troubleshooting

| Symptom                                                      | Cause and resolution                                                                                                                                           |
| :----------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Biqli reports a callback or redirect mismatch                | The Make callback URL does not exactly match the URI registered on the official client. Do not modify it; report the callback shown by Make to Biqli support.  |
| A module returns `403` for a missing scope                   | Reconnect using the official app so the fixed module permissions are approved. A token cannot gain a new scope after issuance.                                 |
| A module returns `403` after workspace access changed        | The connected user no longer has the required workspace role or permission. Restore access or reconnect as an authorized member.                               |
| Track Lead or Track Sale returns `403`                       | Enable conversion tracking for the connected workspace and confirm the member can use it.                                                                      |
| Webhook attachment returns `422` for a duplicate URL         | Remove the existing subscription that uses the same Make receiver URL, then activate the trigger again.                                                        |
| Requests return `429`                                        | Let Make retry after the server-provided delay and reduce scenario concurrency or request frequency. Keep the same conversion idempotency identity on retries. |
| Refresh stops working or the connection becomes unauthorized | The refresh family may have expired, been revoked, or detected reuse of an old rotating token. Create a new Make connection.                                   |

When contacting support, include the request ID and UTC time. Never send an
access token, refresh token, authorization code, client secret, or full Make
webhook URL.
