Billing¶
TEBHOS takes payments through Polar, its only payment provider. The routes on this page open a Polar checkout or customer-portal session and return its URL; the browser then finishes the purchase on Polar's hosted pages. When a payment completes, Polar notifies TEBHOS, which grants the purchase (TEBHOS Pro, a Pro gift, Business Class, boosts or shop items). Premium describes the resulting entitlement state.
All routes here are user-only: a bot token is rejected with 403 ACCESS_DENIED. TEBHOS never sees or stores card details.
Purchases are granted asynchronously
A checkout route only returns a URL. Nothing is granted until Polar confirms the payment. After the redirect back to TEBHOS, re-read Get my premium status (or the relevant resource) to see the new state.
Redirect URL object¶
Every checkout and portal route answers with one URL to open in a browser.
| Field | Type | Description |
|---|---|---|
| url | string | Absolute URL of the Polar checkout or customer portal session |
Checkout currency¶
Checkout sessions open in Turkish lira (try) or US dollars (usd). The currency is chosen in this order:
- The
currencyfield of the request body, when it istryorusd(case-insensitive). Other values are ignored. - Otherwise,
trywhen the caller's country is Turkey (from theCF-IPCountryheader, or IP geolocation). - Otherwise, the product's default (USD).
TEBHOS also pre-fills the checkout with the account's email address and country, and links the Polar customer to the TEBHOS user ID.
Create subscription checkout¶
POST /premium/checkout
Opens a Polar checkout for a TEBHOS Pro subscription and returns a redirect URL object. After payment, the browser returns to https://tebhos.com/premium/callback?status=success.
JSON body¶
The body is optional; without one the monthly plan is used.
| Field | Type | Description |
|---|---|---|
| plan? | string | monthly (default) or yearly. cycle is accepted as an alias; annually, annual and year also select the yearly plan |
| currency? | string | try or usd, see checkout currency |
Response¶
| Status | Body | Condition |
|---|---|---|
| 200 | redirect URL object | The checkout session was created |
| 400 | error response | Unknown plan, or the yearly plan is not configured on this instance (BAD_REQUEST) |
| 500 | error response | Polar is not configured or rejected the request |
Example¶
curl -X POST "https://tebhos.com/api/v1/premium/checkout" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"plan":"yearly","currency":"try"}'
Create gift checkout¶
POST /premium/checkout/gift
Opens a Polar checkout that buys TEBHOS Pro for a friend. When the payment completes, the membership is applied directly to the recipient's account (see Gifts) and the optional message is delivered to them. The browser returns to https://tebhos.com/premium/callback?status=gift-success.
JSON body¶
| Field | Type | Description |
|---|---|---|
| recipient_id | snowflake | The user receiving the gift. Required |
| plan? | string | monthly (1 month, default) or yearly (12 months); cycle is accepted as an alias |
| message? | string | A note for the recipient, truncated to 190 characters |
| currency? | string | try or usd, see checkout currency |
Response¶
| Status | Body | Condition |
|---|---|---|
| 200 | redirect URL object | The checkout session was created |
| 400 | error response | No or invalid recipient_id, the recipient is the caller, unknown plan, or gifts are not configured on this instance (BAD_REQUEST) |
| 403 | error response | The recipient is not the caller's friend (FORBIDDEN) |
| 404 | error response | The recipient does not exist (NOT_FOUND) |
Create Business Class checkout¶
POST /business/checkout
Opens a Polar checkout for a Business Class subscription on one guild. Only the guild owner can buy it.
JSON body¶
| Field | Type | Description |
|---|---|---|
| guild_id | snowflake | The guild to upgrade. Required |
| plan? | string | monthly (default) or yearly (annually, annual, year also accepted) |
| currency? | string | try or usd, see checkout currency |
Response¶
| Status | Body | Condition |
|---|---|---|
| 200 | redirect URL object | The checkout session was created |
| 400 | error response | Invalid guild_id or plan, the guild already has Business Class, or Business Class is not configured on this instance (BAD_REQUEST) |
| 404 | error response | The caller does not own the guild (NOT_FOUND, so the guild's existence is not revealed) |
Rate limit¶
10 requests per hour per user, on the business:checkout bucket.
Boost and shop checkouts¶
Two other routes can answer with a checkout URL:
- Boost guild (
POST /servers/{guild_id}/boost) applies free boosts immediately and returns a checkout URL for the paid remainder. - Purchase shop item and purchase shop bundle always return a checkout URL.
Create customer portal¶
POST /premium/billing-portal
Returns a redirect URL object for the Polar customer portal, where the user manages payment methods and downloads invoices. Available only to accounts that have a Polar subscription; has_billing_account in Get my premium status tells a client whether to offer it.
Response¶
| Status | Body | Condition |
|---|---|---|
| 200 | redirect URL object | The portal session was created |
| 400 | error response | The account has no Polar subscription or customer record (BAD_REQUEST) |
Rate limit¶
20 requests per hour per user, on the premium:portal bucket.
Create Business Class customer portal¶
POST /business/guilds/{guild_id}/billing-portal
Same as Create customer portal for a guild's Business Class subscription. Owner only; a non-owner or a guild without a Business Class subscription receives 404 NOT_FOUND.
Rate limit¶
20 requests per hour per user, on the business:portal bucket.
List transactions¶
GET /premium/transactions
Returns the caller's Polar order history, 10 per page. An account without a Polar subscription receives an empty list rather than an error.
Query parameters¶
| Field | Type | Description |
|---|---|---|
| page? | integer | The page, starting at 1 (default 1) |
Response¶
| Field | Type | Description |
|---|---|---|
| items | array[transaction object] | The orders on this page |
| total_pages | integer | The number of pages |
| current_page | integer | The page that was returned |
Transaction object¶
| Field | Type | Description |
|---|---|---|
| id | string | The Polar order ID |
| amount | integer | The order total in minor units (kuruş or cents) |
| amount_paid | integer | Same as amount when the order is paid, otherwise 0 |
| refunded_amount | ?integer | The refunded amount in minor units |
| currency | ?string | The uppercase currency code, for example TRY |
| status | ?string | The Polar order status |
| type | ?string | The billing reason, for example purchase, subscription_create or subscription_cycle |
| description | ?string | The product name |
| created_at | ?string | When the order was created |
| period_start | null | Always null |
| period_end | null | Always null |
{
"items": [
{
"id": "9b2f6c1e-2d6a-4f0e-9a51-0c9d1e2f3a4b",
"amount": 8999,
"amount_paid": 8999,
"refunded_amount": 0,
"currency": "TRY",
"status": "paid",
"type": "subscription_create",
"description": "TEBHOS Pro",
"created_at": "2026-09-01T10:00:00Z",
"period_start": null,
"period_end": null
}
],
"total_pages": 1,
"current_page": 1
}
Cancel subscription¶
POST /premium/cancel-subscription
Schedules the caller's Polar subscription to end at the end of the current billing period and returns 204. Premium stays active until premiumUntil. Calling it again while cancellation is already scheduled succeeds without contacting Polar. Refunds are not issued.
Response¶
| Status | Body | Condition |
|---|---|---|
| 204 | empty | Cancellation is scheduled |
| 400 | error response | The account has no Polar subscription (BAD_REQUEST) |
Rate limit¶
5 requests per minute per user, on the premium:cancel-subscription bucket.
Cancel premium¶
POST /premium/cancel
A broader cancel used by the TEBHOS client. It returns the updated premium status object (with premiumWillCancel true) instead of 204, and also works for premium that did not come from a Polar subscription:
- With a Polar subscription, it behaves like Cancel subscription.
- With time-limited premium from a gift or a staff grant, it marks the membership to end at
premiumUntil. - With lifetime premium, which has no end date, premium is removed immediately.
Rate limit¶
10 requests per hour per user, on the premium:cancel bucket.
Reactivate subscription¶
POST /premium/reactivate-subscription
Undoes a scheduled cancellation on the caller's Polar subscription and returns 204. If no cancellation is scheduled, it returns 204 without changes.
| Status | Body | Condition |
|---|---|---|
| 204 | empty | The subscription will renew |
| 400 | error response | The account has no Polar subscription (BAD_REQUEST) |
Rate limit¶
5 requests per minute per user, on the premium:reactivate-subscription bucket.
Cancel and reactivate Business Class¶
POST /business/guilds/{guild_id}/cancel
POST /business/guilds/{guild_id}/reactivate
Schedule or undo the end-of-period cancellation of a guild's Business Class subscription. Owner only. Both return {"ok": true, "will_cancel": <bool>}.
| Status | Body | Condition |
|---|---|---|
| 200 | {ok, will_cancel} |
Done |
| 400 | error response | Cancel: the subscription is not active. Reactivate: no cancellation is scheduled (BAD_REQUEST) |
| 404 | error response | The caller does not own the guild, or it has no Business Class subscription (NOT_FOUND) |
Rate limit¶
Both share 10 requests per hour per user, on the business:cancel bucket.
Not supported on TEBHOS¶
Not supported on TEBHOS
Localised card preapproval, age verification sessions, self-service refunds and refund eligibility have no TEBHOS endpoints. Refunds cannot be requested through the API.