Create a tip
Add a tip that TipPage didn’t take payment for. It enters the TTS queue (and the media queue when media_url is given) and plays like any other tip, with TTS pre-rendered. These tips deliberately skip the word filter (the author is trusted). Fires tip.created with source: "api".
Two independent fields decide how the tip is counted:
sourcelabels where the tip came from - a stable lower-case slug per platform (kofi,youtube-superchat,ayupcc). Reports list one row per distinct source. On its own it makes a free tip: shown and read out on stream, never counted as money.paid: truesays real money was processed on that platform (a Ko-fi payment, a Super Chat, a legacy tipping service you’re bridging). The tip then counts as revenue on the streamer’s overview and in their PDF reports under that source, climbs the leaderboard and moves the tip goal. Requiressource.referenceis your own transaction id for that payment, shown to the streamer for reconciliation.
Neither field - a manual tip, exactly like the dashboard’s manual-tip form: visible on stream, never in the money totals, itemised separately in reports.
Requires tips:create.
POST
/tipsAuthorization
AuthorizationBearer token (tp_live_... or tpat_...) · headerrequiredA TipPage API key (`tp_live_...`, created in Dashboard → Settings → Developer) or an OAuth 2.0 access token (`tpat_...`, see the OAuth guide). Both carry the same scopes and are accepted on every endpoint.
Request body
requiredapplication/jsonnamestringrequiredThe display name shown on stream.
max length 22
amountnumberrequiredDisplayed amount, in the streamer's currency.
min 0 · max 100000
messagestringmax length 255
media_urlstring<uri>Optional video to queue alongside (YouTube supported).
media_start_timeintegerVideo start offset in seconds.
min 0 · default: 0
sourcestringWhere the tip came from, as a lower-case slug (`kofi`, `youtube-superchat`, `ayupcc`). A label only - pair it with `paid: true` when money really moved there.
matches ^[a-z0-9][a-z0-9._-]{1,47}$
paidbooleanReal money was processed on `source`. Makes the tip count as revenue (overview, reports, leaderboard, tip goal). Requires `source`.
default: false
referencestringYour own reference for the payment on that platform (a transaction or order id). Requires `source`.
max length 128
Responses
201Tip queued.
tipobjectThe tip as `GET /tts/queue` lists it. `tts_url` is `null` here - the audio is pre-rendered in the background (`tip.tts_ready`). `source` is `api`, `external_source` / `external_ref` / `is_paid` echo what you sent.
Show propertiesHide properties
order_idstringnamestringDisplay name (post-filter).
amountnumber | nullmessagestring | nullThe tip message (post-filter - what shows on stream).
tts_urlstring<uri> | nullAudio for this tip. AI-voice tips are rendered at payment; standard voices are rendered when an alert box first plays the tip (in that box's voice) or the streamer previews it - `null` until then. Listen for `tip.tts_ready`.
is_replaybooleanis_sub_rewardbooleansourcestringWhere the tip came from: `stripe`, `paypal`, `manual` (dashboard manual tip), `api` (POST /tips), `sub_reward`, `replay`, `test`, `ayupcc`, or `unknown` for tips older than source tracking.
external_sourcestring | nullDeveloper-API tips only - the `source` label the caller sent (`kofi`, `ayupcc`); `null` for every other source. Says where the tip came from, not whether money moved - see `is_paid`.
external_refstring | nullDeveloper-API tips only - the caller's own payment reference.
is_paidbooleanReal money changed hands (Stripe, PayPal, or a developer-API tip sent with `paid: true`). `false` for manual tips, free integration tips and sub rewards - those never count toward the streamer's totals.
platformstring | nullThe platform of the account the donor was signed in with when they tipped; `null` for an unattributed tip.
Allowed:
twitchkicknullplatform_user_idstring | nullThe donor's id on that platform, when signed in.
name_was_filteredbooleanmessage_was_filteredbooleanqueued_atstring<date-time>media_queuedbooleanWhether a media item was queued alongside.
400Validation failed (name/amount/message/media URL).
errorstringrequiredHuman-readable message.
codestringMachine-readable code (e.g. `missing_scope`, `not_in_queue`).
401Missing or invalid credential (`missing_api_key` / `invalid_api_key`, or `invalid_token` for an expired/revoked OAuth access token).
errorstringrequiredHuman-readable message.
codestringMachine-readable code (e.g. `missing_scope`, `not_in_queue`).
403The key lacks the required scope (`missing_scope`).
errorstringrequiredHuman-readable message.
codestringMachine-readable code (e.g. `missing_scope`, `not_in_queue`).
required_scopestring429Rate limit exceeded - check the `RateLimit-*` headers.
errorstringRequest
curl -X POST "https://api.tippage.com/v1/tips" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "string",
"amount": 100000,
"message": "string",
"media_url": "http://example.com",
"media_start_time": 0,
"source": "kofi",
"paid": false,
"reference": "kofi_txn_8f3a2c"
}'const response = await fetch("https://api.tippage.com/v1/tips", {
method: "POST",
headers: {
"Authorization": "Bearer YOUR_TOKEN",
"Content-Type": "application/json"
},
body: JSON.stringify({
"name": "string",
"amount": 100000,
"message": "string",
"media_url": "http://example.com",
"media_start_time": 0,
"source": "kofi",
"paid": false,
"reference": "kofi_txn_8f3a2c"
})
});import requests
response = requests.post(
"https://api.tippage.com/v1/tips",
headers={
"Authorization": "Bearer YOUR_TOKEN",
"Content-Type": "application/json"
},
json={
"name": "string",
"amount": 100000,
"message": "string",
"media_url": "http://example.com",
"media_start_time": 0,
"source": "kofi",
"paid": False,
"reference": "kofi_txn_8f3a2c"
},
)Response
{
"tip": {
"order_id": "tip_1755100000000_ab12cd",
"name": "string",
"amount": 5,
"message": "string",
"tts_url": "http://example.com",
"is_replay": true,
"is_sub_reward": true,
"source": "string",
"external_source": "string",
"external_ref": "string",
"is_paid": true,
"platform": "twitch",
"platform_user_id": "string",
"name_was_filtered": true,
"message_was_filtered": true,
"queued_at": "2019-08-24T14:15:22Z"
},
"media_queued": true
}{
"error": "string",
"code": "string"
}{
"error": "string",
"code": "string"
}{
"error": "string",
"code": "string",
"required_scope": "string"
}{
"error": "string"
}