Payments
Reading is always free. You pay only for monitors beyond your plan's free slots, and for monitors created without an account. Agents pay with the Machine Payments Protocol (MPP), an open standard by Stripe and Tempo that lets a client pay inside an ordinary HTTP request, using the 402 Payment Required status code. Payments are processed by Stripe for Symelo LTD, a VAT-registered company in Bulgaria (VAT BG207464756).
Prices
| Price per location | Renews | |
|---|---|---|
| Monthly (default) | $0.01 for 30 days | Automatically, from credit |
| Lifetime | $0.10 once | Never |
- A monitor's price is the per-location price times its number of locations. A heartbeat or webhook monitor counts as one location.
- Choose lifetime with
"billing_period": "lifetime"when creating the monitor. Without it, a paid monitor is monthly. - Adding a location to a paid monitor costs one period's price for that location (or the lifetime price, for a lifetime monitor).
- Prices are in US dollars and include VAT.
GET /api/v1/accountreturns the current prices. - Monitors that fit in your plan's free slots never cost anything and have no billing period.
- Paid monitors may check as often as every 10 seconds on any plan, the free plan included. Monitors in plan slots follow the plan (every 5 minutes at the fastest on Free).
How a payment happens
Every payment goes into your workspace's prepaid credit, and paid actions take their price from that credit. If the credit covers the price, nothing else happens: the request succeeds. If it does not, the response is a 402 with an MPP challenge for the difference.
Agent UpHeron Stripe
| POST /api/v1/monitors | |
|------------------------------------>| no free slot, credit too low |
| 402 + WWW-Authenticate: Payment ... | |
|<------------------------------------| |
| (wallet signs or issues a token) | |
| POST /api/v1/monitors | |
| Authorization: Payment ... | |
|------------------------------------>| verify and settle -------------->|
| | add to credit, create monitor |
| 201 Created + Payment-Receipt | |
|<------------------------------------| |
- The agent sends the request with its
X-API-Key. - UpHeron answers
402 Payment Required. TheWWW-Authenticate: Paymentheader carries one challenge per payment method, and the JSON body says what is due and why. - The agent's MPP client pays the challenge and repeats the request with an
Authorization: Payment …credential. Keep sendingX-API-Key. - UpHeron verifies the payment with Stripe, adds it to your credit, takes the price from it, and runs the request. The response carries a
Payment-Receiptheader.
Because payments land in credit first, money is never lost: if the request fails after payment (for example, the monitor is invalid), the payment stays in your credit for the next request.
A 402 response
HTTP/1.1 402 Payment Required
Content-Type: application/problem+json
Cache-Control: no-store
WWW-Authenticate: Payment id="…", realm="upheron.com", method="stripe", intent="charge", request="…", expires="…"
{
"type": "https://paymentauth.org/problems/payment-required",
"title": "Payment Required",
"status": 402,
"error": "payment_required",
"amount_due": "0.50",
"currency": "usd",
"quote": {
"billing": "paid",
"billing_period": "monthly",
"locations": ["fra-1", "nyc-1"],
"price_cents": 2,
"credit_cents": 0,
"amount_due_cents": 2
},
"offers": [{ "method": "stripe", "amount_cents": 50 }],
"credit_after_cents": 48,
"help": "Pay with an MPP client …"
}
You rarely read this yourself: MPP clients handle the challenge and retry automatically.
Payment methods
| Method | Minimum | Notes |
|---|---|---|
Card through a Stripe shared payment token (MPP method stripe), for example from a Link wallet |
$0.50 | Anything above the price stays as credit |
Stablecoin: USDC on Tempo (MPP method tempo) |
$0.01 | Coming soon: enabled once Stripe approves stablecoins for this account. Until then, pay by card. |
Stripe cannot charge a card less than $0.50, so a card payment is at least $0.50 and the rest is kept as credit for later monitors and renewals. At the default prices, $0.50 covers 50 location-months or 5 lifetime locations: one $0.01 monitor and 49 more months of monitoring, already paid for. The 402 response lists the methods it accepts and the amount for each in offers, and credit_after_cents says how much credit will be left.
Paying from code
With a card, using Stripe's Link CLI
link-cli issues one-time shared payment tokens from your Link wallet, after you approve the purchase. It pays any 402 from UpHeron, for example creating a monitor:
npx @stripe/link-cli auth login
npx @stripe/link-cli mpp pay https://upheron.com/api/v1/monitors \
-X POST \
-H "X-API-Key: $UPTIME_MONITOR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Checkout API", "url": "https://shop.example.com/health", "interval_seconds": 60}' \
--context "Create an UpHeron uptime monitor for my checkout API. The card is charged the 0.50 USD minimum; the rest stays as UpHeron credit for more monitors."
With the mppx SDK (TypeScript)
mppx wraps fetch: when a response is a 402, it pays the challenge with the configured method and retries. This example uses a stablecoin wallet (accepted once enabled; until then use a card).
import { Mppx, tempo } from "mppx/client";
import { privateKeyToAccount } from "viem/accounts";
const mppx = Mppx.create({
methods: [tempo({ account: privateKeyToAccount(process.env.WALLET_PRIVATE_KEY as `0x${string}`) })],
polyfill: false,
});
const response = await mppx.fetch("https://upheron.com/api/v1/monitors", {
method: "POST",
headers: {
"X-API-Key": process.env.UPTIME_MONITOR_API_KEY!,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({ name: "Checkout API", url: "https://shop.example.com/health", locations: ["fra-1", "nyc-1"] }),
});
console.log(response.status, await response.json());
Fund the wallet with USDC on Tempo. MPP also has SDKs for Python, Go and Rust.
From an MCP client
The MCP server takes MPP payments too: a paid tool answers with error -32042 and the challenge, and the agent's MPP client pays and repeats the call.
Any other MPP client
Any MPP-compatible client works the same way: send the request with your X-API-Key, let the client answer the 402, and keep the header on the retry. Validate the exchange end to end with npx mppx@latest validate.
Prepaid credit
Top up credit to avoid a payment per request, or to pay by card:
# Answers 402 with a challenge for $5.00; pay it with an MPP client.
curl https://upheron.com/api/v1/credits \
-H "X-API-Key: $UPTIME_MONITOR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"amount_cents": 500}'
- Top-ups run from $0.50 to $1,000.00, in whole cents.
GET /api/v1/accountshows your balance;GET /api/v1/account/creditlists every movement.- Credit does not expire and is not refunded as cash.
Monthly renewals
A monthly paid monitor has a paid_until date. Every hour, UpHeron renews monitors whose period has ended for another 30 days, from credit, at the current price for their current locations.
- Keep credit available and renewals happen without any action.
- If credit runs out, the monitor keeps running for a grace period of 3 days. After that it pauses, with
"billing_state": "overdue", and cannot be resumed until it is renewed. - To renew early or after a pause, call
POST /api/v1/monitors/{id}/renew. It pays from credit, or answers402for the price. Renewing early adds 30 days to the remaining time. Topping up credit is also enough: the next hourly run renews and resumes the monitor. - Lifetime monitors never renew and never pause for billing.
Without an account
An agent with an MPP wallet can create a monitor without any account or token. Send POST /api/v1/monitors without X-API-Key:
const response = await mppx.fetch("https://upheron.com/api/v1/monitors", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: "My API", url: "https://api.example.com/health", billing_period: "lifetime" }),
});
const { data, api_key, workspace } = await response.json();
// Store api_key: it is shown once and controls this monitor.
- The request is always paid: it gets a
402for the monitor's price, monthly or lifetime. - After payment UpHeron creates a pay-as-you-go workspace that owns the monitor, and returns its
api_key(shown once) andworkspace. Send that key asX-API-Keyto read status, change the monitor, add more monitors, renew, top up credit, or add notification contacts. - Pay-as-you-go workspaces have no free slots and cannot create group monitors. Their monitors may check every 10 seconds.
- A card pays at least $0.50; whatever the monitor does not use stays as the new workspace's credit.
- If the monitor could not be created after payment, the response still contains
api_key, and the payment is credit in that workspace: fix the request and retry with the key. - Monthly monitors in such a workspace renew from its credit; top it up with
POST /api/v1/creditsusing its key.
Quotes and idempotency
- Ask before paying.
POST /api/v1/monitors/quotetakes the same body as creating a monitor and returns the price, your credit and the amount due, without creating anything or charging.POST /api/v1/monitors/{id}/quoteprices a change andPOST /api/v1/monitors/{id}/renew/quotea renewal. - Retry safely. Send an
Idempotency-Keyheader (any unique string up to 255 characters) when creating a monitor. Repeating the request with the same key within 24 hours returns the monitor the first request created, withIdempotent-Replayed: true, and charges nothing. - Payment credentials are single-use. A replayed MPP credential is rejected, so a payment can never be counted twice.
Receipts and VAT
- Every paid response has a
Payment-Receiptheader with the payment method and its reference (a Stripe PaymentIntent ID for cards, a transaction hash for stablecoins). GET /api/v1/paymentslists your payments;GET /api/v1/payments/{id}/receiptreturns a receipt with the seller's details and the VAT breakdown, as JSON or, withAccept: text/markdown, as Markdown.- Prices include VAT. The seller is Symelo LTD, a VAT-registered company in Bulgaria (VAT BG207464756). The VAT treatment of each payment depends on where the buyer is:
| Buyer | Treatment |
|---|---|
| In Bulgaria | Bulgarian VAT included |
| A business elsewhere in the EU, with a VAT number on the account | Reverse charge: no VAT; the buyer accounts for it |
| A consumer elsewhere in the EU | VAT included |
| Outside the EU | Outside the scope of EU VAT |
Set your invoice details so receipts name your business and EU businesses get the reverse charge:
curl -X PUT https://upheron.com/api/v1/account/billing \
-H "X-API-Key: $UPTIME_MONITOR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"billing_name": "Example GmbH", "billing_address": "Musterstraße 1, 10115 Berlin", "billing_country": "DE", "billing_vat_id": "DE123456789"}'
Without invoice details, the country is taken from the request's IP address when available.
Errors
| Status | error |
What to do |
|---|---|---|
| 402 | payment_required |
Pay the MPP challenge, or top up credit and retry |
| 402 | renewal_required |
The monitor is paused for non-payment; call POST /monitors/{id}/renew |
| 402 | MPP problem verification-failed, invalid-challenge, malformed-credential |
The credential was rejected; the response carries a fresh challenge to pay instead |
| 422 | monitor_limit_reached |
No free slots and payments are switched off |
| 422 | paid_monitor_limit_reached |
The workspace has reached the maximum number of paid monitors |
| 422 | invalid_amount |
Top-ups must be whole cents between the minimum and $1,000 |
| 500 | payment_not_recorded |
The payment went through but was not credited yet; keep the receipt and contact support |
| 503 | payments_disabled |
Payments are temporarily unavailable; monitors in free slots still work |
MPP error responses follow RFC 9457 problem details; see the MPP protocol for the full list.