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

# Create a Coin

> Launch a new token from a connected user's Trench Wallet, with an optional first buy in the same transaction.

Uploads the image and metadata, builds the launch transaction, signs it with the user's delegated wallet, and submits it. When a first buy is included, the launch and the buy land together.

|                  |                                                                     |
| ---------------- | ------------------------------------------------------------------- |
| **Scope**        | `coin:create`                                                       |
| **Rate limit**   | 20 / minute, within your [tier budget](/concepts/rate-limits)       |
| **Requires**     | `tradingEnabled: true` on [`GET /partner/v1/me`](/api-reference/me) |
| **Content type** | `multipart/form-data`                                               |

This is the only partner endpoint that is not JSON. The token image is a required
file part, so the request must be multipart.

## Fields

All amounts are [integer strings in base units](/concepts/amounts), the same as
the trade endpoints. Decimals are rejected with `invalid_input`.

| Field                  | Type   | Required                     | Constraint                                                   |
| ---------------------- | ------ | ---------------------------- | ------------------------------------------------------------ |
| `image`                | file   | Yes                          | `image/png`, `image/jpeg`, `image/webp`, or `image/gif`      |
| `name`                 | string | Yes                          | Normalized, then 1 to 32 bytes UTF-8                         |
| `symbol`               | string | Yes                          | Normalized, then 1 to 10 bytes UTF-8, `A-Z` and `0-9` only   |
| `description`          | string | No                           | Free text                                                    |
| `website`              | string | No                           | URL                                                          |
| `twitter`              | string | No                           | URL or handle                                                |
| `telegram`             | string | No                           | URL or handle                                                |
| `priorityFeeLamports`  | string | No                           | Lamports, minimum `1000`. Defaults if omitted                |
| `initialBuySol`        | string | No                           | Lamports to spend on the first buy. `"100000000"` is 0.1 SOL |
| `initialBuyTokens`     | string | No                           | Token base units to receive. `"1000000"` is 1 token          |
| `initialBuyMaxSolIn`   | string | Only with `initialBuyTokens` | Lamports ceiling for the exact-output buy                    |
| `slippageBps`          | string | No                           | Integer from 0 to 10000                                      |
| `maxBypassFeeLamports` | string | Only when quoted             | Lamports. See [Launch limits](#launch-limits)                |

## The First Buy

The first buy is optional, and there are two mutually exclusive ways to ask for
one. Sending both `initialBuySol` and `initialBuyTokens` is rejected.

| Mode         | Field                                     | Behaviour                                                           |
| ------------ | ----------------------------------------- | ------------------------------------------------------------------- |
| Spend        | `initialBuySol`                           | Spends up to that many lamports                                     |
| Exact output | `initialBuyTokens` + `initialBuyMaxSolIn` | Buys exactly that many token base units, up to your lamport ceiling |

A first buy can never exceed **2.5% of supply**, and the two modes handle that
ceiling differently:

<Warning>
  `initialBuySol` is **clamped**, not rejected. If the amount you send would buy
  more than 2.5% of supply, the launch still succeeds and spends only as much SOL
  as fits under the cap. `initialBuyTokens` above the cap is **rejected**
  outright instead.
</Warning>

When a clamp happens the response says so, and you should read
`initialBuyPlan.expectedSolIn` rather than assuming your requested amount was
spent.

```json theme={null}
"initialBuyPlan": {
  "kind": "buy",
  "authorizedMaxSolIn": "5000000000",
  "expectedSolIn": "2310000000",
  "expectedTokensOut": "25000000000000",
  "capacityTokensOut": "25000000000000",
  "clamped": true,
  "clampReasons": ["token_balance", "net_bought"]
}
```

`clampReasons` lists every limit that tied for binding, so it can hold more than
one entry.

| Reason                | Limit that bound                                       |
| --------------------- | ------------------------------------------------------ |
| `token_balance`       | 2.5% of supply, measured against tokens already held   |
| `net_bought`          | 2.5% of supply, measured against tokens already bought |
| `migration_threshold` | Room left on the curve before migration                |

At launch both balances are zero, so a first buy clamped by the supply cap
reports `token_balance` and `net_bought` together.

Your client's `maxTradeLamports` and daily volume cap do **not** apply to a first
buy. The curve already bounds it at 2.5% of supply, which is a tighter and more
meaningful limit than a configured ceiling.

## Launch Limits

Two per-creator restrictions are checked before anything is uploaded. Both belong
to the connected user, not to your app.

| Error                           | Meaning                                                                 |
| ------------------------------- | ----------------------------------------------------------------------- |
| `deploy_cooldown_active`        | The user launched recently. The response carries the remaining cooldown |
| `launch_identity_limit_reached` | The user has hit their launch allowance for this name or ticker         |

`launch_identity_limit_reached` may quote a bypass fee. To take it, resend the
request with `maxBypassFeeLamports` set to at least the quoted
`totalBypassFeeLamports`. Sending a lower value, or omitting it, keeps the
rejection.

## Request

```bash cURL theme={null}
curl -X POST https://api.tren.ch/partner/v1/coins/create \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -F "image=@logo.png" \
  -F "name=Doge Classic" \
  -F "symbol=DOGEC" \
  -F "description=The original, again." \
  -F "twitter=https://x.com/dogeclassic" \
  -F "initialBuySol=500000000" \
  -F "slippageBps=300"
```

```ts TypeScript theme={null}
const form = new FormData();
form.set("image", new Blob([png], { type: "image/png" }), "logo.png");
form.set("name", "Doge Classic");
form.set("symbol", "DOGEC");
form.set("description", "The original, again.");
form.set("initialBuySol", "500000000"); // lamports, = 0.5 SOL
form.set("slippageBps", "300");

const res = await fetch("https://api.tren.ch/partner/v1/coins/create", {
  method: "POST",
  headers: { Authorization: `Bearer ${accessToken}` },
  body: form,
});
```

## Response

```json theme={null}
{
  "signature": "…",
  "mint": "…",
  "status": "submitted",
  "metadataUri": "ipfs://…",
  "imageUri": "ipfs://…",
  "initialBuyPlan": {
    "kind": "buy",
    "authorizedMaxSolIn": "500000000",
    "expectedSolIn": "500000000",
    "expectedTokensOut": "4820000000000",
    "capacityTokensOut": "25000000000000",
    "clamped": false,
    "clampReasons": []
  }
}
```

`initialBuyPlan` is `null` when no first buy was requested. When one was, the
launch and the buy are submitted as a bundle and `signatures` carries both.

`status` is `submitted`, not confirmed. Poll
[`GET /partner/v1/transactions/{signature}/status`](/api-reference/overview) for
the outcome.

## Errors

| Code                            | Meaning                                                      |
| ------------------------------- | ------------------------------------------------------------ |
| `image_required`                | No `image` file part in the request                          |
| `invalid_image_type`            | Image is not PNG, JPEG, WebP, or GIF                         |
| `invalid_multipart`             | Body could not be parsed as multipart                        |
| `invalid_input`                 | A field failed validation, or both first-buy modes were sent |
| `delegation_missing`            | The user has not enabled trading                             |
| `deploy_cooldown_active`        | See [Launch limits](#launch-limits)                          |
| `launch_identity_limit_reached` | See [Launch limits](#launch-limits)                          |
| `rpc_unavailable`               | Solana or the price oracle was unreachable                   |

See [Errors](/concepts/errors) for the shared response shape.
