Skip to content
OpenTrain AIOpenTrain AIOpenTrain AIDocs

Ask OpenTrain

Answers from the documentation, with sources.

What would you like to do with OpenTrain?

AI answers can be mistaken. Check the linked sources. Don’t include private account information.

Open app

DEVELOPER DOCUMENTATION

Create Credit Top-Up

Start a credit top-up — returns a Stripe Checkout URL a human must pay. Nothing is charged by this call.

POST/api/public/v1/credits/top-ups

Starts a prepaid credit top-up. This call never charges anything. It creates a PENDING top-up and returns a Stripe Checkout checkoutUrl that a signed-in human must open and pay; once checkout completes, the credits land automatically. The link expires unpaid after ~24 hours (expiresAt).

Learn the outcome by polling GET /credits/top-ups/{topUpId} until the status is COMPLETED, then confirm the new balance with GET /credits.

Requirements: payments:write scope + the public_api_credits feature + a claimed account (unclaimed accounts get 403 with details.reason: "account_claim_required" and a claimUrl).

amountUsdnumberbodyrequired

Top-up amount in US dollars. Minimum $10, maximum $10,000. (amount is accepted as an alias.)

Returns 201 — the top-up exists, but no money has moved until the human pays the checkout link.

topUpIdstring

The top-up ID, for polling.

checkoutUrlstring

Stripe Checkout URL — show it to your human so they can complete the payment.

expiresAtstring | null

ISO timestamp when the unpaid checkout link lapses (~24h).

topUpobject

The full top-up record: {id, status: "PENDING", amountCents, createdAt, completedAt, expiresAt} — same shape as GET /credits/top-ups/{topUpId}.

messagestring

Explains the human-payment handoff.

StatuscodeMeaning
400BAD_REQUESTBody is not valid JSON, amountUsd missing/non-numeric, or outside $10–$10,000 (details: {field: "amountUsd"})
401UNAUTHORIZEDMissing or invalid token
403FORBIDDENMissing payments:write scope, public_api_credits disabled, or account not claimed (details.reason: "account_claim_required", details.claimUrl)