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

# Invite-only Indicators

> Sell an indicator through your own checkout and grant access with the Access Grants API: how it works, what the buyer sees, setup, and the error codes.

Keep selling your indicator where you already sell it — Whop, Stripe, Discord, Patreon, Gumroad or your own site. When someone pays, your checkout calls the **Access Grants API** with the buyer's email, and the indicator appears on their charts until the date you set.

You keep your payment provider, your pricing, your bundles and your customer list. TakeProfit only handles the access.

## Two ways to use it

**Publish the indicator as invite-only.** It has no price, it is not listed on the Marketplace and it does not come up in search — its page is visible only to you, to admins and to the people you give access to. There is no review, so it goes live as soon as you publish. Publishing one needs a paid platform plan.

**Or keep it paid and grant access on top.** A paid indicator stays listed and anyone can still buy it at your price. Grants are a second way in, for buyers who paid you directly.

Free indicators cannot be granted.

## How it works

1. Your payment platform confirms the purchase — a webhook, a Zapier trigger or a CSV export.
2. You call the API with the buyer's **email** and an end date.
3. The buyer opens the platform and finds the indicator under the **Invited** filter in the indicator panel, and in their Favorites.
4. Renewals extend the date with the same call. Refunds remove access, or you let the date pass.

The buyer does not need an account first. If the email has one, the indicator is waiting on their next visit. If it does not, they get an invite email and the indicator is there the first time they sign in — as long as they sign up with **the same email you sent**.

| Rule | What it means |
| - | - |
| **Email or username** | The API takes either. Email is the better default: your checkout already has one, and it works whether or not the buyer has an account. Emails are case-insensitive. |
| **End date** | Every grant carries an `expiresAt` date in UTC. Access ends automatically at that moment. |
| **No end date** | `expiresAt: null` grants access that does not expire, for lifetime deals. |
| **Repeat calls extend** | Calling `PUT` again for the same buyer replaces the end date rather than adding a second grant, so retries are safe. |
| **Revoke anytime** | `DELETE` removes access immediately, for refunds and chargebacks. |
| **Pending until opened** | A grant is `pending` until the buyer opens the indicator, then `active`. An invite nobody claimed stays `pending`, so the list tells you who never turned up. |

## What the buyer sees

* **In the indicator panel** the script sits under the **Invited** filter, next to Subscribed, and its card has **Add to chart** on it rather than a padlock and a price. It is in their Favorites as well.
* **The card shows no end date.** If your automation extends access on every charge the date keeps moving, so showing one would only mislead.
* **On the product page** of a paid indicator, the buyer block reads **Access granted**, with **Managed by the author** below it. There is no Subscribe button while the grant is active.
* **When access ends**, an invite-only indicator disappears from the buyer again. A paid one goes back to showing your price and a **Subscribe** button.

## Set up invite-only access

**1. Publish the indicator**

Publish it from the IDE as described in [How to publish an indicator](https://takeprofit.com/docs/guide/monetization-tools/Sell-your-indicators.md#how-to-publish-an-indicator) and choose **invite-only** as the type. There is no review and no price, so it is live immediately.

A paid indicator works too, if you would rather also sell it on the Marketplace — that one goes through the usual review.

**2. Copy the product ID**

Open your indicator's publication page or its product page. As the owner you see its **Product ID** — copy it.

> [!NOTE]
>
> Use the **product** ID, not the indicator ID. The product ID does not change when you publish a new version of the indicator, so automations built on it keep working.

**3. Create an API token**

Go to **Settings → Login & Security → Personal API Tokens**, the same place you create a Market Data API token, and click **Generate New Token**. Name it after where you will use it, for example `whop-webhook`, and give it the indicator access scopes:

* `indicator:access:write` — grant, extend and revoke access
* `indicator:all:read` — list who has access

Copy the token straight away. It is shown only once. See [Personal API Tokens](https://takeprofit.com/docs/guide/getting-started/mfa.md#personal-api-tokens) for how tokens are managed and revoked.

> [!WARNING]
>
> Tokens need an active paid plan. Without a subscription the block shows **Upgrade Plan and Generate** instead of the generate button. If your subscription ends, every token you hold is revoked — which stops your grants automation until you subscribe again and generate a new one.

**4. Test your setup**

Check it works before you automate it. Grant access to one of your own addresses:

```bash theme={null}
export TP_API_KEY="your-token"
export TP_PRODUCT_ID="your-product-id"
export TP_BUYER="buyer@example.com"

curl -X PUT \
  "https://takeprofit.com/api/marketplace/indicators/$TP_PRODUCT_ID/grants/$TP_BUYER" \
  -H "x-api-key: $TP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "expiresAt": "2026-12-31T00:00:00Z" }'
```

A response with `"success": true` means your token, its scopes and the product ID all work. Fix any errors here, before you add your payment platform — [Errors](#errors) below says what each failure means.

**5. Automate it**

Let your payment platform make the call on every sale, renewal and refund. Anything that can send an HTTP request when a payment completes will do — a webhook from Whop, Stripe, Discord, Patreon or Gumroad, a no-code step in Zapier, Make or n8n, or a script run against a CSV export of your buyers.

They all need the same three things: the buyer's email, your product ID, and your token in the `x-api-key` header.

## Access Grants API

**Base URL:** `https://takeprofit.com/api/marketplace`

Send your API token in the `x-api-key` header on every call. Every date — the `expiresAt` you set, and the timestamps that come back — is ISO 8601 in UTC, like `2026-12-31T00:00:00Z`.

| Path parameter | What it is |
| - | - |
| `productId` | The product ID, not the indicator ID. Shown on the product page to its owner. |
| `buyer` | The buyer's email or TakeProfit username. The API grants access to whatever you send, so check it before you send it. |

### Grant or extend access

```
PUT /api/marketplace/indicators/{productId}/grants/{buyer}
```

Grants access, or updates `expiresAt` if the buyer already has it.

Request body:

```json theme={null}
{ "expiresAt": "2026-12-31T00:00:00Z" }
```

Response, granting by email:

```json theme={null}
{
  "success": true,
  "data": {
    "productId": "21bd6f72-408c-4e03-a609-2a0341911ace",
    "username": null,
    "invitedEmail": "john@example.com",
    "status": "pending",
    "expiresAt": "2026-12-31T00:00:00Z",
    "createdAt": "2026-10-27T10:00:00Z",
    "updatedAt": "2026-10-27T10:00:00Z"
  }
}
```

Granting by username returns the same shape with `username` filled in and `invitedEmail` null.

> [!NOTE]
>
> A new grant on an invite-only indicator emails the buyer. Extending or shortening an existing one sends nothing, so renewals stay quiet. Paid indicators send no email at all.

### Remove access

```
DELETE /api/marketplace/indicators/{productId}/grants/{buyer}
```

```json theme={null}
{ "success": true }
```

Deleting by email removes the invite and whatever access came from it, claimed or not. Deleting something that does not exist still returns success, so retries are safe.

### List who has access

```
GET /api/marketplace/indicators/{productId}/grants
```

Returns everyone with access, newest first, with claimed grants before unclaimed invites. Expired ones are left out. A `null` `expiresAt` is a grant with no end date.

```json theme={null}
{
  "success": true,
  "data": {
    "items": [
      {
        "productId": "21bd6f72-408c-4e03-a609-2a0341911ace",
        "username": "john",
        "invitedEmail": null,
        "status": "active",
        "expiresAt": "2026-12-31T00:00:00Z",
        "createdAt": "2026-10-27T10:00:00Z",
        "updatedAt": "2026-10-27T10:00:00Z"
      },
      {
        "productId": "21bd6f72-408c-4e03-a609-2a0341911ace",
        "username": null,
        "invitedEmail": "anna@example.com",
        "status": "pending",
        "expiresAt": null,
        "createdAt": "2026-10-26T09:00:00Z",
        "updatedAt": "2026-10-26T09:00:00Z"
      }
    ]
  }
}
```

## Errors

A failed call returns an HTTP status and a code you can switch on in your automation.

| Status | Code | What it means |
| - | - | - |
| `400` | `schema_error` | The request is malformed. Either `expiresAt` is absent, is not ISO 8601, or is in the past — send `null` rather than omitting the field when you want access that does not expire — or the value in the path is neither a valid email nor a valid username. |
| `401` | `invalid_api_key` | The key is missing, revoked or unknown, or it has gone over its request limit. |
| `403` | `missing_scope` | The token does not carry the scope the call needs. |
| `403` | `not_product_owner` | The product exists, but you are not its owner. |
| `404` | `product_not_found` | There is no active paid or invite-only indicator with this ID. Free and unpublished indicators fail here. |
| `404` | `user_not_found` | The username is not registered on TakeProfit. Only ever returned for a username — an email never fails this way. |

The one you are most likely to hit in production is `schema_error`, on a date your automation built in the wrong format or in the past. Granting by email removes the other common failure, since there is no username to get wrong.

## Who does what

| Task | Owner |
| - | - |
| Selling, payments, refunds | You |
| Calling the API from your automation | You |
| Authenticating calls and checking that you own the indicator | TakeProfit |
| Granting, extending, expiring and revoking access | TakeProfit |
| Emailing the buyer their invite | TakeProfit |
| Adding the indicator to the buyer's Favorites | TakeProfit |

## Moving buyers from another platform

A list of buyer emails is all you need. Loop over it and call `PUT` once per email.

* **Buyers without an account are fine.** Each gets an invite email, and the indicator is waiting when they sign up with that address.
* **They must sign up with the invited email.** Tell them that when you announce the move; signing up with a different address means the invite does not reach them.
* **Check who never turned up.** `GET` the grant list and look for `status: "pending"` — those are the invites nobody has opened.

## Good to know

* **Sign-up is not a prerequisite.** Grant access by email first; the buyer can create the account afterwards.
* **Keep your token on a server.** Never put it in a web page, a browser extension or a public repository. Anyone holding it can change access to your indicators.
* **A paid indicator can carry both.** Granting access to someone who already subscribed does no harm, and removing a grant does not cancel a subscription.

## Frequently asked questions

> [accordion] Is my indicator source code protected when granting invite-only access?
>
> Yes. All invite-only scripts run entirely server-side. The terminal only receives the output values to plot on the chart — the underlying source code is never transmitted to the client, ensuring it cannot be decompiled, viewed, or extracted.

> [accordion] How does selling invite-only scripts work, and are there platform fees or pricing caps?
>
> You manage payments directly through your own checkout or billing provider (such as Whop, Stripe, or Lemon Squeezy). TakeProfit does not take any platform cut or commission on these sales, and the public Marketplace price limits (up to \$100) do not apply — you set your own pricing and terms.

> [accordion] How do access automation and API limits work?
>
> There is no limit to the number of users you can invite per indicator. You can automate access grants using our [Access Grants API](#access-grants-api) via Zapier, Make, or custom webhooks. If an invited user hasn't registered yet, you can still grant access by email — they will receive an invite, and the indicator will be waiting in their account as soon as they sign up.
>
> > [!NOTE]
> >
> > If your paid plan expires, your API tokens will be revoked until renewed.

> [accordion] Can Freeroll users access invite-only indicators, and can they create alerts?
>
> Yes. Users on Freeroll can receive and use invite-only indicators, subject to the standard limit of 2 indicators per chart. Users on either plan can set alerts on invite-only indicators they have access to, within their plan's allowance (Freeroll: 5 indicator alerts expiring after 3 months; All-In: up to 500 indicator alerts, non-expiring available). See [Alert limitations](https://takeprofit.com/docs/guide/alerts/Alert-limitations-delivery-history.md).

> [accordion] Do alerts run continuously when the terminal is closed, and where are they delivered?
>
> Yes. All alerts execute in the cloud 24/7, continuing to fire whether your browser is closed or your device is locked. Alerts can be delivered in real time to [Telegram](https://takeprofit.com/docs/guide/alerts/Telegram-alerts.md), [webhooks](https://takeprofit.com/docs/guide/alerts/Webhook-notifications.md), or email (capped at 1 email per minute per address).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.