> For the complete documentation index, see [llms.txt](https://docs.feel.cash/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.feel.cash/developers-and-integrators/partner-launch-api.md).

# Partner Launch API

Review the Feel.cash Partner Launch API for approved teams, including authentication, supported chains, and one-call or prepare-and-execute launches.

> **Access by approval.** The API contract is public, but API keys and sponsored allowances are available only to approved Feel partners.

The Feel Partner Launch API lets an approved team launch official Feel coins on Base or Robinhood Chain from its own server. Base remains the default when the request omits `chain`. The API supports both a one-call launch and an optional two-step `prepare -> execute` flow that reveals the future CREATE2 contract address before deployment.

The API is ready for approved pilot integrations. The production base URL is:

```
https://api.feel.cash
```

## What makes a launch official

An official Feel launch must pass through the Feel app or this API. Feel then:

* validates the launch configuration;
* records durable creator and launch provenance;
* applies the official Creator Fees settlement;
* indexes the coin and makes it available on Feel;
* enforces idempotency, quotas, and recovery;
* uses the same versioned Doppler recipes as the Feel launch UI.

Doppler Airlock remains permissionless. Calling it directly is possible, but that deployment is not automatically treated as an official Feel launch and does not automatically receive Feel attribution, Creator Fees settlement, or listing.

Partner attribution is private backend provenance. The partner name, API key, client ID, and API launch source are not added to the token contract or public token metadata, and Feel does not display a public “partner launch” label. The normal creator account remains visible in the same places as a launch made through the Feel UI.

## Partner API or x402?

Feel offers two separate server-to-server launch lanes:

|           | Partner Launch API                       | [x402 launch API](/developers-and-integrators/x402-launches.md) |
| --------- | ---------------------------------------- | --------------------------------------------------------------- |
| Access    | Approved Feel account and API key        | Public; no API key                                              |
| Identity  | Creator is derived from the approved key | Accountless launch with later ownership claim                   |
| Payment   | Sponsored pilot allowance                | 1 USDC per launch through x402                                  |
| Future CA | Optional `prepare -> execute`            | One-call payment flow                                           |
| Chains    | Base or Robinhood Chain                  | Base or Robinhood Chain                                         |
| Limits    | Client quota and minimum interval        | Payment and public API limits                                   |

Use the Partner API when the launch must belong to an approved Feel creator, use Feel Creator Fees settlement immediately, or expose the future CA before deployment. Use x402 for an accountless agent or service that can pay per launch and does not need an invite-only credential.

## Request access

Access is tied to one Feel account and is granted manually.

1. Sign in to [Feel.cash](https://feel.cash).
2. Open **Account -> Developer**.
3. Enter your work email and briefly describe what you are building.
4. Select **Request API access**.
5. Wait for the Feel team to review the request.
6. After approval, refresh **Account -> Developer**.
7. Select **Create API key**.
8. Copy the full key immediately into your server-side secret manager.

The full key is revealed only once. Feel stores a hash, not the plaintext key, so it cannot be shown again later. The pilot does not offer self-service key rotation or revocation. If a key may have been exposed, contact the Feel team through your partner channel without including the key itself.

An approved account can create only one pilot key. A second key-creation attempt is rejected with `409 api_key_already_created`. This is an Account -> Developer key-management error, not a launch endpoint error.

The approved team decides which of its backend services may use the key. Do not share it with end users or put it in client-side software.

## Protect the API key

Keys have this form:

```
feel_live.<key-id>.<secret>
```

Treat the key like a production signing credential:

* use it only from a trusted backend;
* store it in a secret manager or encrypted environment variable;
* never put it in browser, mobile, desktop, or bot client code;
* never commit it to source control;
* never include it in a URL or query parameter;
* never paste it into Telegram, Slack, email, support tickets, logs, analytics, or error trackers;
* never expose it through a frontend proxy endpoint.

Send it only in the Bearer authorization header:

```http
Authorization: Bearer feel_live.<key-id>.<secret>
```

## Choose a launch workflow

Both workflows create the same type of official Feel launch.

### Direct launch

Use `POST /v1/partner/launches` for a one-call experience. Feel validates, prepares, sponsors, and deploys the launch. Internally, the backend still builds and simulates the CREATE2 deployment before broadcasting.

```
POST /v1/partner/launches
```

This is the simplest choice when you do not need the contract address in advance.

### Prepare, then execute

Use `POST /v1/partner/launches/prepare` when you need the future contract address before deployment—for example, to prepare separately signed buys, bundles, monitoring, or indexing infrastructure.

```
POST /v1/partner/launches/prepare
POST /v1/partner/launches/<job-id>/execute
```

`prepare` validates and resolves the inputs, reserves the Feel identity and slug, freezes the Doppler configuration, mines the vanity salt, simulates the deployment, and returns the predicted CREATE2 address.

It is **not a premint**:

* no contract exists onchain;
* no supply exists;
* no transaction is signed or broadcast;
* no sponsored launch allowance is consumed.

The prepared reservation is valid for at most 24 hours and occupies the client's single active-job slot. `execute` reloads and deploys exactly that persisted configuration. The request cannot replace its address, curve, fee wallets, salt, token URI, or other deployment parameters.

## Request schema

Direct and prepared launches accept the same JSON body.

Provide either `prompt`, or both `name` and `symbol`. Explicit fields take precedence over values inferred from `prompt`.

```json
{
  "name": "Glint",
  "symbol": "GLINT",
  "chain": "robinhood",
  "listed": true,
  "description": "A small chrome oracle",
  "imagePrompt": "A luminous chrome oracle orb on black",
  "socials": {
    "x": "https://x.com/example",
    "telegram": "https://t.me/example",
    "website": "https://example.com"
  },
  "launchMode": "standard",
  "tradeFeelingPreset": "balanced"
}
```

| Field                | Type              | Rules                                                                                                                        |
| -------------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `prompt`             | string            | 1–2,000 characters                                                                                                           |
| `name`               | string            | 1–50 characters                                                                                                              |
| `symbol`             | string            | 1–12 characters; starts with A–Z; remaining characters A–Z or 0–9                                                            |
| `chain`              | string            | `base` (default) or `robinhood`                                                                                              |
| `listed`             | boolean           | `false` (default) keeps the coin unlisted; `true` opts into Feel.cash UI discovery                                           |
| `description`        | string or null    | Up to 500 characters                                                                                                         |
| `imagePrompt`        | string or null    | 1–2,000 characters; used only when `image` is omitted                                                                        |
| `image`              | object or null    | Final image source as inline base64 or a trusted Feel CDN URL; takes precedence over `imagePrompt`                           |
| `socials.x`          | HTTPS URL or null | Up to 2,048 characters                                                                                                       |
| `socials.telegram`   | HTTPS URL or null | Up to 2,048 characters                                                                                                       |
| `socials.website`    | HTTPS URL or null | Up to 2,048 characters                                                                                                       |
| `launchMode`         | string            | `standard` (default) or `degen`                                                                                              |
| `tradeFeelingPreset` | string            | `balanced` (default), `fast-start`, or `late-rush`; standard mode only                                                       |
| `disableSniperFees`  | boolean           | Degen mode only; omitted/false keeps sniper fees enabled                                                                     |
| `disableReferralFee` | boolean           | Set to `true` to remove the 0.15% referral fee and use a 1.35% terminal swap fee; omitted/false keeps the standard 1.50% fee |

Unknown fields are rejected.

### Choose a chain

Set `chain` explicitly when launching on Robinhood Chain:

```json
{
  "name": "Glint",
  "symbol": "GLINT",
  "chain": "robinhood"
}
```

Omitting `chain` launches on Base. Partner launches use Feel's server-owned Doppler configuration and WETH pairing on both networks. The selected chain is part of the idempotent launch identity and cannot be changed between retries, preparation, and execution.

### Choose visibility

Partner launches are unlisted by default. Omit `listed` or send `"listed": false` to keep the coin out of Feel.cash UI discovery surfaces: feeds, featured placements, search, and public profiles. It is also omitted from the sitemap.

An unlisted coin is still live: its direct coin page, trading, and holdings remain available. Send `"listed": true` when the coin should appear in Feel.cash UI discovery.

```json
{
  "name": "Glint",
  "symbol": "GLINT",
  "listed": true
}
```

Feel fixes the visibility choice during preparation. Retrying or resuming the same idempotent job preserves the original value, and `execute` cannot change it.

### Images

Send an inline JPEG, PNG, or WebP image as base64:

```json
{
  "image": {
    "type": "base64",
    "mimeType": "image/png",
    "data": "iVBORw0KGgo..."
  }
}
```

The encoded `data` value may contain up to 7,000,000 characters.

A URL reference is accepted only when it is an HTTPS asset already hosted on Feel's trusted CDN. Arbitrary remote image URLs are not fetched.

```json
{
  "image": {
    "type": "url",
    "url": "https://cdn.charms.ai/path/to/image.png"
  }
}
```

An explicit `image` is authoritative and is not regenerated or visually modified by AI. If both `image` and `imagePrompt` are present, Feel uses `image` and ignores `imagePrompt`.

Feel still validates and normalizes the supplied file before storing it on its trusted CDN. The server auto-rotates it, crops it to a 1,024 × 1,024 square, flattens transparency onto a white background, and encodes it as JPEG at 90% quality. This preserves the supplied visual rather than creating a new one, but it is not a byte-for-byte copy of the upload. The approved partner remains responsible for the image content it submits.

If no explicit image is supplied, Feel can generate one from `imagePrompt`, the launch prompt, or the resolved coin identity.

## Launch modes

### Standard

Standard mode supports the named Trade Feeling presets:

```json
{
  "launchMode": "standard",
  "tradeFeelingPreset": "fast-start"
}
```

Available presets are `balanced` (the default), `fast-start`, and `late-rush`.

### Degen with sniper fees

Degen uses its own fixed Trade Feeling recipe. Do not send `tradeFeelingPreset` with Degen.

```json
{
  "launchMode": "degen"
}
```

Sniper fees are enabled by default and decay according to the versioned Degen recipe.

### Degen without sniper fees

Set `disableSniperFees` to `true` to select the immutable Degen recipe without sniper fees:

```json
{
  "launchMode": "degen",
  "disableSniperFees": true
}
```

`disableSniperFees` is rejected in standard mode. A standard Trade Feeling preset is rejected in Degen mode.

## Unsupported overrides

The pilot is intentionally narrow and uses WETH pairing and Feel-owned configuration on both supported chains. Do not send:

* unsupported chain values or pair-token overrides;
* `userId`, creator ID, partner ID, or client ID;
* creator-wallet or fee-recipient overrides;
* raw salt, pool, tick, curve, hook, gas, or transaction parameters;
* developer-buy fields such as `devBuyUsd`.

The creator identity and fee ownership are derived exclusively from the Feel account approved for the API key. The key authorizes launching; it does not authorize spending funds from the creator's wallet. A partner may use the prepared contract address for its own separately authorized transactions.

## Idempotency

Every logical launch must use a stable UUID in the `Idempotency-Key` header:

```http
Idempotency-Key: 00000000-0000-4000-8000-000000000001
```

Generate the UUID once and persist it with your launch record. Repeating the same endpoint with the same key and identical body returns or resumes the same job. It does not create a second launch or consume quota twice.

Token names, symbols, and descriptions do not need to be unique. To create a new token and contract address with identical metadata, use a new `Idempotency-Key`. Reusing the same key with an identical request returns the existing job and contract address; reusing it with different content returns `409 idempotency_conflict`.

Reusing the key with different content—or switching between direct and prepared execution—returns `409 idempotency_conflict`.

After a timeout, connection reset, ambiguous `5xx`, or process crash, do not invent a new key. Retry the original request first.

## Direct launch quickstart

```bash
export FEEL_API_KEY='feel_live.<key-id>.<secret>'
export FEEL_IDEMPOTENCY_KEY='00000000-0000-4000-8000-000000000001'

curl --request POST 'https://api.feel.cash/v1/partner/launches' \
  --header "Authorization: Bearer ${FEEL_API_KEY}" \
  --header "Idempotency-Key: ${FEEL_IDEMPOTENCY_KEY}" \
  --header 'Content-Type: application/json' \
  --data '{
    "name": "Glint",
    "symbol": "GLINT",
    "chain": "robinhood",
    "description": "A small chrome oracle",
    "launchMode": "standard",
    "tradeFeelingPreset": "balanced"
  }'
```

The endpoint returns `201` when the launch finishes during the request, `202` while durable work continues, or `422` for a terminal launch failure.

## Prepare and execute quickstart

### 1. Prepare

```bash
export FEEL_API_KEY='feel_live.<key-id>.<secret>'
export FEEL_IDEMPOTENCY_KEY='00000000-0000-4000-8000-000000000002'

curl --request POST 'https://api.feel.cash/v1/partner/launches/prepare' \
  --header "Authorization: Bearer ${FEEL_API_KEY}" \
  --header "Idempotency-Key: ${FEEL_IDEMPOTENCY_KEY}" \
  --header 'Content-Type: application/json' \
  --data '{
    "name": "Glint",
    "symbol": "GLINT",
    "chain": "robinhood",
    "description": "A small chrome oracle",
    "launchMode": "degen",
    "disableSniperFees": false
  }'
```

A completed preparation returns `201`:

```json
{
  "id": "2d5a8822-2ca8-4ad1-99fe-823bbac44b83",
  "executionMode": "prepare_execute",
  "status": "pending",
  "statusUrl": "https://api.feel.cash/v1/partner/launches/2d5a8822-2ca8-4ad1-99fe-823bbac44b83",
  "executeUrl": "https://api.feel.cash/v1/partner/launches/2d5a8822-2ca8-4ad1-99fe-823bbac44b83/execute",
  "prepared": {
    "tokenId": "8e6eced4-86b3-4e67-bdc7-a5217763b70f",
    "tokenAddress": "0x1234567890abcdef1234567890abcdef12345678",
    "slug": "glint",
    "url": "https://feel.cash/glint",
    "explorerUrl": "https://robinhoodchain.blockscout.com/token/0x1234567890abcdef1234567890abcdef12345678",
    "chain": "robinhood",
    "chainId": 4663,
    "preparedAt": "2026-08-20T08:00:00.000Z",
    "expiresAt": "2026-08-21T08:00:00.000Z",
    "deploymentState": "not_deployed"
  },
  "launch": null,
  "error": null
}
```

A response may initially be `202`. Poll `statusUrl` or retry the same prepare request until `prepared` is non-null.

### 2. Confirm no deployment yet

Before execution, the returned address has no contract bytecode. This is an optional integration check:

```bash
curl --request POST 'https://rpc.mainnet.chain.robinhood.com' \
  --header 'Content-Type: application/json' \
  --data '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_getCode",
    "params": ["0x1234567890abcdef1234567890abcdef12345678", "latest"]
  }'
```

The result should be `0x` before `execute`.

### 3. Execute

The execute body is empty:

```bash
export FEEL_JOB_ID='2d5a8822-2ca8-4ad1-99fe-823bbac44b83'

curl --request POST \
  "https://api.feel.cash/v1/partner/launches/${FEEL_JOB_ID}/execute" \
  --header "Authorization: Bearer ${FEEL_API_KEY}"
```

Do not send a new launch body or a new idempotency key to `execute`. Repeating the endpoint is safe and returns the same durable job and deployment result.

## Check job status

```bash
curl \
  "https://api.feel.cash/v1/partner/launches/${FEEL_JOB_ID}" \
  --header "Authorization: Bearer ${FEEL_API_KEY}"
```

Only a key belonging to the same approved client can access the job.

Public job statuses are `pending`, `processing`, `succeeded`, and `failed`.

A successful response contains the final address and transaction:

```json
{
  "id": "2d5a8822-2ca8-4ad1-99fe-823bbac44b83",
  "executionMode": "prepare_execute",
  "status": "succeeded",
  "statusUrl": "https://api.feel.cash/v1/partner/launches/2d5a8822-2ca8-4ad1-99fe-823bbac44b83",
  "executeUrl": null,
  "prepared": null,
  "launch": {
    "tokenId": "8e6eced4-86b3-4e67-bdc7-a5217763b70f",
    "tokenAddress": "0x1234567890abcdef1234567890abcdef12345678",
    "slug": "glint",
    "transactionHash": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd",
    "url": "https://feel.cash/glint",
    "explorerUrl": "https://robinhoodchain.blockscout.com/token/0x1234567890abcdef1234567890abcdef12345678",
    "chain": "robinhood",
    "chainId": 4663
  },
  "error": null
}
```

Poll with exponential backoff and jitter. A reasonable starting interval is 2 seconds, capped around 15 seconds. Stop on `succeeded` or `failed`.

If preflight stopped before its resolved snapshot was persisted, `GET` cannot reconstruct removed inline image bytes. Retry the originating `POST` with the same body and `Idempotency-Key`. A status read may resume a direct job or an already accepted execution, but it never executes an unaccepted prepared job.

## TypeScript example

```ts
type LaunchJob = {
  id: string;
  executionMode: "direct" | "prepare_execute";
  status: "pending" | "processing" | "succeeded" | "failed";
  statusUrl: string;
  executeUrl: string | null;
  prepared: {
    tokenAddress: string;
    chain: "base" | "robinhood";
    chainId: 8453 | 4663;
    expiresAt: string;
  } | null;
  launch: {
    tokenAddress: string;
    transactionHash: string | null;
    chain: "base" | "robinhood";
    chainId: 8453 | 4663;
  } | null;
  error: string | null;
};

type PreparedLaunchJob = LaunchJob & {
  executeUrl: string;
  prepared: NonNullable<LaunchJob["prepared"]>;
};

const apiKey = process.env.FEEL_API_KEY;
if (!apiKey) throw new Error("FEEL_API_KEY is required");

const headers = {
  Authorization: `Bearer ${apiKey}`,
  "Content-Type": "application/json",
};

const idempotencyKey = crypto.randomUUID();
const requestBody = JSON.stringify({
  name: "Glint",
  symbol: "GLINT",
  chain: "robinhood",
  launchMode: "standard",
  tradeFeelingPreset: "balanced",
});
const sleep = (milliseconds: number) =>
  new Promise((resolve) => setTimeout(resolve, milliseconds));

async function prepareLaunch(): Promise<PreparedLaunchJob> {
  let delayMs = 2_000;
  for (;;) {
    // Repeating the original POST safely resumes the same preparation. A GET
    // alone cannot reconstruct inline image bytes removed after persistence.
    const response = await fetch(
      "https://api.feel.cash/v1/partner/launches/prepare",
      {
        method: "POST",
        headers: { ...headers, "Idempotency-Key": idempotencyKey },
        body: requestBody,
      },
    );
    const payload: unknown = await response.json();
    if (!response.ok) {
      throw new Error(`Prepare failed: ${JSON.stringify(payload)}`);
    }

    const job = payload as LaunchJob;
    if (job.prepared && job.executeUrl) {
      return { ...job, prepared: job.prepared, executeUrl: job.executeUrl };
    }
    if (response.status !== 202) {
      throw new Error(`Unexpected prepare response: ${JSON.stringify(job)}`);
    }

    await sleep(delayMs + Math.floor(Math.random() * 500));
    delayMs = Math.min(15_000, Math.round(delayMs * 1.5));
  }
}

const prepared = await prepareLaunch();

// Prepare any separately authorized partner transactions here.

const executeResponse = await fetch(prepared.executeUrl, {
  method: "POST",
  headers,
});
const executePayload: unknown = await executeResponse.json();
if (!executeResponse.ok) {
  throw new Error(`Execute failed: ${JSON.stringify(executePayload)}`);
}

let executed = executePayload as LaunchJob;
let statusDelayMs = 2_000;
while (executed.status === "pending" || executed.status === "processing") {
  await sleep(statusDelayMs + Math.floor(Math.random() * 500));
  const statusResponse = await fetch(executed.statusUrl, {
    headers: { Authorization: `Bearer ${apiKey}` },
  });
  const statusPayload: unknown = await statusResponse.json();
  if (!statusResponse.ok) {
    throw new Error(`Status failed: ${JSON.stringify(statusPayload)}`);
  }
  executed = statusPayload as LaunchJob;
  statusDelayMs = Math.min(15_000, Math.round(statusDelayMs * 1.5));
}

if (executed.status === "failed") {
  throw new Error(`Launch failed: ${executed.error ?? "unknown error"}`);
}
```

In production, validate response JSON at runtime and handle `202`, `409`, `422`, `429`, and retryable `503` responses explicitly.

## Sponsored pilot limits

Default limits are shown in **Account -> Developer** and enforced per approved client:

* 20 accepted launches per rolling 24 hours;
* at least 60 seconds between accepted launches;
* one active launch job at a time;
* one non-expiring product key.

`prepare` alone does not consume launch allowance. Allowance is consumed when `execute` crosses the atomic sponsorship boundary. Direct launch crosses that boundary within its one-call flow. Retrying an already accepted job does not consume another allowance.

An abandoned unaccepted job stops blocking a different idempotency key after 25 hours when it has no live worker lease. A prepared reservation normally expires after 24 hours.

## Errors

Except for validation failures, immediate request errors return an HTTP status and stable `code`:

| HTTP | Code                             | Meaning                                                                                             |
| ---: | -------------------------------- | --------------------------------------------------------------------------------------------------- |
|  400 | no `code`                        | Header or body validation failed; the body contains `error`, `details`, and optionally `formErrors` |
|  401 | `invalid_api_key`                | Key is missing, malformed, expired, revoked, or incorrect                                           |
|  403 | `api_access_disabled`            | Feel disabled the approved client                                                                   |
|  404 | `launch_not_found`               | The job does not exist for this client                                                              |
|  409 | `idempotency_conflict`           | The UUID was reused with different content or execution mode                                        |
|  409 | `launch_in_progress`             | Another launch for the client is active                                                             |
|  409 | `launch_not_prepared`            | Execute was requested before preparation completed                                                  |
|  409 | `invalid_execution_mode`         | Execute was requested for a direct-launch job                                                       |
|  409 | `prepared_launch_expired`        | The prepared reservation expired                                                                    |
|  409 | `prepared_configuration_changed` | Executable parameters no longer match the prepared hash                                             |
|  429 | `launch_rate_limited`            | The minimum launch interval has not elapsed                                                         |
|  429 | `launch_quota_exceeded`          | The rolling sponsored allowance is exhausted                                                        |
|  503 | `persistence_unavailable`        | Durable storage or authentication is temporarily unavailable                                        |

Execution-stage failures are persisted on the durable job in its `error` field. Terminal failures return the job with HTTP `422`; retryable failures normally return the job with HTTP `202` so the same operation can be resumed:

| HTTP | Job `error`               | Meaning                                                                |
| ---: | ------------------------- | ---------------------------------------------------------------------- |
|  422 | `content_rejected`        | Content policy rejected the request                                    |
|  422 | `image_rejected`          | The image could not be accepted                                        |
|  422 | terminal launch code      | The launch cannot succeed without changed input                        |
|  202 | `preflight_unavailable`   | Text, image, moderation, or simulation work is temporarily unavailable |
|  202 | `prepare_unavailable`     | The reserved launch could not be prepared yet                          |
|  202 | `sponsorship_unavailable` | The sponsorship boundary could not be completed yet                    |
|  202 | `launch_unavailable`      | Deployment or recovery is temporarily unavailable                      |

The `202` and `422` rows above describe responses from the operation `POST` endpoints. `GET /v1/partner/launches/<job-id>` normally returns HTTP `200` for a job that exists, including one with a persisted failure. Always inspect its `status` and `error` fields.

Invalid public option combinations fail request validation with HTTP `400`. For example, `disableSniperFees` outside Degen mode or a `tradeFeelingPreset` in Degen mode is a validation error. The internal `unsupported_configuration` guard is a defensive `422` for a resolved launch that violates a server invariant; schema-valid partner requests should not normally encounter it.

`429` responses include `Retry-After` when available. Respect it before retrying. For retryable failures, reuse the original request and idempotency key.

## Ownership and Creator Fees

The API key maps to one approved Feel account. Feel derives the canonical creator and fee ownership server-side; requests cannot redirect either one.

The resulting coin follows the same ownership, Creator Fees, recovery, and public Feel indexing path as a launch made in the app. The public contract and metadata do not reveal the partner client or API key.

## Front-running considerations

Revealing a CREATE2 address before deployment necessarily creates a window in which other parties know the future CA. Feel fails closed if bytecode appears at that address before Feel broadcasts, unless Feel's durable send ledger proves the deployment was broadcast by Feel. The API never adopts an unproven third-party deployment as an official launch.

Partners remain responsible for the privacy and ordering of any transactions they prepare around the predicted address.

## Support and security

Use your Feel partner channel for onboarding, quota, and operational questions. Never paste an API key into that channel.

If a credential may have been exposed:

1. stop sending new requests with it;
2. contact the Feel team immediately through the partner channel;
3. provide the visible key prefix or last four characters, never the secret;
4. wait for the team to disable or replace the key through internal tooling.

For public market data that does not require launch authorization, use the [Public API v1](/developers-and-integrators/api.md).
