Stargate Pay

Choose payment links or the Merchant RPC API, prepare stores and products, protect reveal-once credentials, and verify every payment.

Choose how you want to accept payments

OptionBest forWhat you do
Payment linkInvoices, chat sales and one-off requestsCreate a USD-priced link in Stargate Pay, then share its URL or QR code. No code is needed.
API integrationA website, bot or Mini AppYour backend creates products and payments, opens Stargate hosted checkout and verifies the final result.

Stores, review and stable IDs

Every product and payment belongs to one store. Choose a stable storeId for your own systems; a store name or later revision does not change it.

  1. Create a draft. You can create it in Stargate Pay or with store.create.
  2. Register return origins. Origins are stored separately for web, tma and bot.
  3. Submit the store for review in Stargate Pay. A new store cannot accept payments until approved.
  4. Publish later changes through revision review. An already approved version remains usable while its replacement is under review.

Only stores with status active or changes_under_review accept new payments. Draft, pending, rejected, suspended, archived and unknown stores return a neutral unavailable/not-found error as appropriate.

Create and maintain products

An API payment uses an active product as the authoritative store, name and USDT price. productId is stable within your merchant account and must be no more than 128 characters.

POST /api/merchant/rpc
X-Api-Key: api_key_REPLACE_WITH_YOUR_REVEAL_ONCE_SECRET
Content-Type: application/json

{
  "method": "product.create",
  "args": {
    "storeId": "shop-main",
    "productId": "monthly-membership",
    "name": "Monthly membership",
    "amountUsdt": "10",
    "config": {}
  }
}

Amounts are positive decimal strings, not floating-point numbers. Product results contain productId, storeId, name, amountUsdt, status, config, createdAt and updatedAt.

Reveal-once credentials

The API key and webhook secret belong to the merchant account, not one store. Stargate returns each raw secret only in the response that creates or rotates it. The readiness screen can report only whether an API key exists; it cannot know whether you saved or deployed the secret.

  • Keep secrets in a server-side secret manager. Never place them in browser code, a Mini App bundle, a URL, analytics, logs, screenshots or a repository.
  • Copy or download a reveal only when you are ready to store it. Closing the page clears the in-memory reveal.
  • Rotate immediately after suspected exposure. API-key rotation invalidates the previous key; configuring a callback or rotating its webhook secret invalidates the previous secret.
  • Deploy the replacement everywhere that needs it before relying on new traffic or callback verification.

Scope, return URLs and signed state

Every API payment requires scope (web, tma or bot) and return_url. Stargate compares the URL’s exact canonical origin—scheme, host and port—with the allowlist for that store and scope. HTTPS is required, except a registered tg:// deep link for TMA or bot scope.

A return is navigation, not proof of payment. Do not fulfil from a return-page query. Put only an opaque, signed, short-lived state token in the return URL, then verify the order through a signed callback or payment.get.

RPC transport and envelopes

Send server-to-server requests to POST /api/merchant/rpc with X-Api-Key. The JSON body is exactly {"method":"…","args":{…}}.

BoundaryResponse
SuccessHTTP 200 with {"result": ...}.
Authenticated validation/domain errorHTTP 200 with {"error":{"code":"stable_code","message":"safe message"}}.
Missing or invalid API keyHTTP 401. Do not retry until credentials are corrected.
Network failure or HTTP 5xxTransport failure. Retry with backoff; preserve the same idempotency inputs.

Implemented RPC methods

There is no payment.list RPC method. Use Stargate Pay for operational history.

MethodRequired or accepted argsResult
store.createstoreId, name; config and returnUrlOriginsStore object; a new store starts as a draft.
store.getstoreIdOne owner-scoped store.
store.listEmpty argsOwner-scoped store array.
store.return_url_origins.updatestoreId, returnUrlOriginsUpdated store/revision projection; review rules still apply.
product.createstoreId, productId, name, amountUsdt; optional configActive product object.
product.getproductIdOne owner-scoped product.
product.listEmpty argsOwner-scoped product array.
product.updateproductId, name, amountUsdt; optional configUpdated product object.
product.archiveproductIdArchived product object; it cannot create new payments.
payment.createstoreId, productId, externalId, scope, return_url; optional description, ttlSecondsPayment metadata without a checkout URL.
payment.getExactly one of merchantOrderId or externalIdThe same payment metadata shape.

Create a payment

POST /api/merchant/rpc
X-Api-Key: api_key_REPLACE_WITH_YOUR_REVEAL_ONCE_SECRET
Content-Type: application/json

{
  "method": "payment.create",
  "args": {
    "storeId": "shop-main",
    "productId": "monthly-membership",
    "externalId": "order-1042",
    "scope": "web",
    "return_url": "https://shop.example/payment-complete?state=OPAQUE_SIGNED_TOKEN",
    "description": "Monthly membership",
    "ttlSeconds": 3600
  }
}

externalId is your per-merchant idempotency key (maximum 128 characters). Repeating the same ID with the same store, product, normalized scope and return URL returns the original result. Changing those inputs returns idempotency_conflict. TTL is 300–86400 seconds and defaults to 3600.

storeId is required and must match the active product’s store. Missing arguments return invalid_params; unavailable stores, unavailable products and store/product mismatch use store_unavailable; an unknown payment lookup uses not_found.

{
  "result": {
    "merchantOrderId": "0198-example-uuid",
    "externalId": "order-1042",
    "productId": "monthly-membership",
    "storeId": "shop-main",
    "scope": "web",
    "return_url": "https://shop.example/payment-complete?state=OPAQUE_SIGNED_TOKEN",
    "status": "created",
    "amountUsdt": "10",
    "description": "Monthly membership",
    "expiresAt": "2026-07-30T11:00:00+00:00",
    "createdAt": "2026-07-30T10:00:00+00:00",
    "paidAsset": null,
    "paidAmount": null,
    "actuallyPaidUsdt": null,
    "feeAmount": null,
    "creditedAmount": null,
    "paidAt": null
  }
}

The RPC result intentionally has no payUrl, tmaUrl or allowedMethods.

Hosted checkout and payment status

Build the buyer-facing URL as /pay/{merchantOrderId}. That is the hosted UI. The separate GET /api/pay/{merchantOrderId} endpoint supplies public checkout data to the UI; neither route is an RPC result or proof of payment.

StatusMeaningYour action
createdThe buyer has not selected or started a method.Keep the order open until expiry or cancellation.
processingA method was selected or a transfer is awaiting detection/confirmations.Wait; do not replace the same business order.
partially_paidThe checkout expired after receiving less than the quoted crypto amount. The received funds are held for manual resolution.Do not fulfil. Reconcile the exact received amount and transaction list, then resolve with the buyer.
paidPayment and settlement were recorded.Fulfil idempotently.
expired / cancelledThis checkout did not complete.Create a new payment only if the buyer wants to try again.
refundedA completed payment was later refunded.Apply your refund and access policy.

Transaction detection and confirmation counts are progress signals, not extra payment statuses. Fulfil only on paid.

Signed callbacks, acknowledgements and retries

Stargate emits merchant_order.paid, .underpaid, .overpaid, .cancelled and .refunded. The underpaid event is terminal and includes the quoted amount, exact received amount and blockchain transaction snapshot for manual resolution. The overpaid event arrives alongside .paid when the buyer sent more than the invoice; payment.overpaid states the excess, which was credited to you in full and can be sent back from the payment receipt in the cabinet. Each body includes a stable event_id, event name, creation time, attempt number and a payment snapshot.

X-Stargate-Event: merchant_order.paid
X-Stargate-Signature: t=UNIX_TIMESTAMP,v1=HEX_HMAC_SHA256

signed_payload = UNIX_TIMESTAMP + "." + RAW_REQUEST_BODY
expected_v1 = HMAC_SHA256(signed_payload, webhook_secret)
  1. Read the raw body before JSON parsing.
  2. Parse t and v1, reject timestamps outside a five-minute tolerance, calculate the HMAC and compare it in constant time.
  3. Deduplicate by event_id. Events may be retried or arrive out of order, so compare authoritative order state and make fulfilment idempotent.
  4. Return any 2xx status only after durable processing; the response body is not inspected. Any other status, a redirect, a timeout or a connection failure is retried with bounded exponential backoff.

Use payment.get to reconcile after delayed or missed callbacks. Never accept an unsigned callback or trust only X-Stargate-Event.

A store can carry its own receiver and its own signing secret; events for that store go there and are signed with that secret, and every other store falls back to the account-wide receiver. Configure it from the Developers page with the store selected. An event that exhausted its retries can be redelivered from the callback journal with the same event_id, which is why deduplicating by that id is not optional.

Fees, settlement, Stars holds and refunds

The product price is denominated in USDT. The buyer’s checkout quote may use an available crypto asset or Telegram Stars. Stargate calculates the fee and credits the net amount in the asset actually paid. An expired underpayment is not credited automatically; it remains held for manual resolution.

Stars proceeds are held for 21 days because Telegram payments can be refunded. After release, Stars are converted through the Wallet flow before crypto payout. A recorded Stars refund changes the payment to refunded and debits the merchant’s credited Stars amount; account debt or restrictions can result if the available balance is insufficient.

Payment links without code

In Stargate Pay, open Payments, choose an eligible store and select Create payment link. Enter the USD amount, choose the server-provided payment methods and TTL, then create the link. Copy/share the URL or show its QR code.

  • Stargate Pay enforces the minimum, maximum, decimal precision, methods and TTL returned by Stargate. There are no client-side fallback limits.
  • A QR code or opened link is not payment proof.
  • You can cancel only before payment detection makes the order non-cancellable.
  • No-code links have no automatic return URL. The buyer closes or leaves hosted checkout manually.

Security, privacy and retention

  • Use least-privilege access for Stargate Pay, secret storage, callback logs and fulfilment tools.
  • Do not put customer identity, email, address or session data in externalId, descriptions, product config or return queries. Use opaque internal references.
  • Public checkout data is intentionally limited. Owner views use a privacy-safe customer summary; callback payment data may include rail-specific reconciliation fields such as a blockchain sender address, so protect and minimize your copy.
  • Do not use Stargate history as a permanent customer database or complete archive. Stargate does not currently publish a guaranteed MerchantOrder/customer-summary retention period; keep only the records your own legal and operational policy requires.
  • Never expose raw credentials, callback signatures/bodies, return state, pay URLs or buyer data in analytics or error telemetry.

Integration test checklist

  • Repeat an identical payment.create and confirm it returns the same order; change an idempotency input and expect idempotency_conflict.
  • Retry the same callback event, deliver events out of order and delay your HTTP acknowledgement. Confirm fulfilment still happens once.
  • Exercise delayed blockchain confirmation, partial payment, expiry/cancellation and a later refund. Never fulfil before paid.
  • Reject bad HMACs, stale timestamps, missing API keys, wrong store/product pairs and non-allowlisted return origins.
  • Verify no secret or customer value reaches browser bundles, URLs, logs, screenshots, analytics or source control.