Files

214 lines
9.7 KiB
Markdown

# UpCloud API Reference
## Promo link
`https://signup.upcloud.com/?promo=deploy250` — gives $250 (25000 credits) trial for 15 days.
## Signup flow (signup.upcloud.com)
### 1. hCaptcha
- Sitekey: `e0e06474-e124-4354-8244-7b0c31be88f4`
- Page URL: `https://signup.upcloud.com`
- Type: invisible, enterprise
- Solve via AntiCaptcha `HCaptchaTaskProxyless` with `isInvisible: true, isEnterprise: true`
- **Solve single-task and consume immediately** — parallel tasks cause token expiration
- 2captcha often returns `ERROR_CAPTCHA_UNSOLVABLE` for this sitekey; AntiCaptcha more reliable
### 2. Check promo code
```
POST https://signup.upcloud.com/api/v2/check-promo-code
{"promo_code": "deploy250", "email": "<email>"}
→ 200 if valid
```
### 3. Init registration
```
POST https://signup.upcloud.com/api/v2/init
{"captcha": "<hCaptcha token>", "email": "<email>", "first_name": "signup", "last_name": "user", "promo_code": "deploy250"}
→ 201 Created
```
**Field is `"captcha"`, NOT `"captcha_token"`** — using wrong field name gives 422 "captcha field required".
### 4. Verify email
- UpCloud sends email from `support@upcloud.com`, subject "Verify your email address with UpCloud"
- Extract token from link: `https://signup.upcloud.com/verify-email?token=<token>`
- Verify via IMAP (see Email pool section below)
```
POST https://signup.upcloud.com/api/v2/verify
{"token": "<verify token>"}
→ 200 {"email": "...", "first_name": "signup", "last_name": "user", "promo_code": "deploy250"}
```
### 5. Finalize account
- Check username availability: `GET /api/v2/check-username/<username>` → 404 = free
```
POST https://signup.upcloud.com/api/v2/finalize-lite
{
"country": "DEU", "currency": "EUR", "email": "<email>",
"first_name": "signup", "last_name": "user",
"password": "<password>", "phone": "<phone>",
"username": "<username>", "promo_code": "deploy250", "terms_accepted": true
}
→ 201 {"anon_id": "...", "status": "accepted", "promotion_text": "Welcome to UpCloud!"}
```
**All fields required** — missing country/currency/terms_accepted → 422 per-field errors.
## Hub login flow (hub.upcloud.com / gate.upcloud.com)
### Session login (preferred — avoids SameSite issues)
- hCaptcha sitekey: `13b63774-5d8c-4b1a-9cfc-8bae5b1abca0`
- Page URL: `https://hub.upcloud.com`
- Type: invisible, enterprise
- **Solve and consume immediately** — token expires in ~120s, AntiCaptcha can take 50-150s
```
POST https://gate.upcloud.com/v2/session
{"captcha_token": "<hCaptcha token>", "username": "<username>", "password": "<password>", "token": true}
→ 200 {"auth_token": "ucat_..."}
Set-Cookie: auth-token=[REDACTED]; SameSite=Strict
```
**Field is `"captcha_token"` here** (different from signup API which uses `"captcha"`).
### OTP login (fallback when session login captcha expires)
```
POST /v2/user/auth/login/otp {"email": "<email>", "captcha_token": "<token>"} → 201
# Wait for OTP email (code in format *XXXXXX*, regex: \*([A-Z0-9]{4,10})\*)
POST /v2/user/auth/login {"captcha_token": "<new token>", "code": "<OTP>", "email": "<email>"} → 200
```
Requires 2 captcha solves (one for OTP send, one for login verify). Each must be consumed immediately.
### Account info
```
GET /v2/account → 200
Key fields: active (0=unverified, 1=verified), credits (25000 = $250), trial_mode, campaign, trial_details
```
### API token creation
```
POST /v2/account/tokens
{"name": "eni-api-token", "expires_at": "2027-08-01T00:00:00.00001Z"}
→ 201 {"token": "ucat_...", "allowed_ip_ranges": ["0.0.0.0/0", "::/0"]}
```
- Token works as Bearer auth on `api.upcloud.com/1.3/*`
- Token creation works even on unverified (active=0) accounts!
- `allowed_ip_ranges: 0.0.0.0/0` = no IP restriction
### UpCloud API (api.upcloud.com/1.3)
```
GET /1.3/account → account info, credits
GET /1.3/zone → 13-15 zones (de-fra1, fi-hel1, es-mad1, au-syd1, dk-cph1, etc.)
GET /1.3/server → list servers
GET /1.3/storage/template → OS templates (Ubuntu, Debian, etc.)
POST /1.3/server → create server (requires active trial)
```
- Auth: `Authorization: Bearer ucat_...`
- Server creation requires `active=1` (trial activated). Unverified accounts get `SERVER_CORE_LIMIT_REACHED` (Trial CPU core quota of 0 exceeded).
## Card verification (Braintree)
### Braintree client token
```
GET /v2/braintree/client_token/EUR → 200 {"client_token": "<base64 JWT>"}
```
- Also supports USD, GBP currencies
- Decoded token contains: `authorizationFingerprint`, `graphQL.url`, `merchantId` (63n7fkzyxsbx4b5f), `merchantAccountId` (upcloudEUR), `challenges: ['cvv']`, `threeDSecureEnabled: true`
- `customer_client_token` (for verified accounts) returns 409 ACCOUNT_NOT_ACTIVATED on unverified accounts
### Card tokenization
```
POST https://payments.braintree-api.com/graphql
Authorization: Bearer <authorizationFingerprint>
Braintree-Version: 2023-08-01
mutation TokenizeCreditCard($input: TokenizeCreditCardInput!) {
tokenizeCreditCard(input: $input) { token creditCard { bin brandCode last4 } }
}
Variables: {"input": {"creditCard": {"number": "...", "expirationMonth": "MM", "expirationYear": "YYYY", "cvv": "..."}, "options": {"validate": false}}}
```
- Returns nonce: `tokencc_bh_...`
- `options.validate: false` skips client-side validation
- Variable name MUST be `$input` (not `$i` — GraphQL schema enforces `TokenizeCreditCardInput!`)
### Account verification
```
POST /v2/account/main/verify
{"account": {"address": "...", "city": "...", "country": "DEU", "first_name": "...", "last_name": "...",
"payment_method_nonce": "<nonce>", "postal_code": "...", "company": "", "currency": "EUR",
"device_data": "{\"correlation_id\":\"...\"}", "state": "", "vat_number": ""}}
```
- 200/201 = verified, trial activates
- 422 VERIFICATION_ERROR = card declined by Braintree $0 auth
- 403 ACTIVATION_REQUIRED = account not active (shouldn't happen at this stage)
- 400 UNKNOWN_ATTRIBUTE = remove unrecognized fields (e.g. `phone`)
- 400 INVALID_DETAILS = missing required fields (e.g. `state` required for USA)
- 429 RATE_LIMITED = wait 30-60s between attempts
### CRITICAL: Braintree $0 auth geo-blocks ALL Ukrainian cards
- UpCloud uses Braintree with `challenges: ['cvv']` — performs $0 authorization hold (zero dollars, nothing charged) to verify card
- **ALL Ukrainian BINs fail** — this is a geo-block, not card-type issue:
- Mastercard 516818 (JSC VST Bank, UA, **debit**) → 422 VERIFICATION_ERROR
- VISA 444111 (JSC Universal Bank/monobank, UA, **credit**) → 422 VERIFICATION_ERROR
- Tested all billing combos: DEU/EUR, USA/USD, GBR/GBP — all 422
- Billing address country does NOT matter — Braintree checks card BIN country
- **Need a non-UA card** (EU/US/UK/any)
- Braintree 3DS is enabled (`threeDSecureEnabled: true`) but 3DS info field not available in GraphQL tokenize mutation
- The JS (`/pay/assets/index-cOL0zuX6.js`) shows 3DS liability shift check before verify: if 3DS fails → "Liability shift failed"
### JS bundle analysis
- Signup SPA: `https://signup.upcloud.com/assets/main-*.js`
- Hub/pay SPA: `https://hub.upcloud.com/pay/assets/index-cOL0zuX6.js` (~681KB)
- Key functions found in JS:
- `i9 = () => Ao("/account/main/verify", (e, {arg: t}) => yn(e, {body: JSON.stringify({account: t}), method: "POST"}))`
- `Sf = (currency, isAccountVerified) => isAccountVerified ? /braintree/customer_client_token/ : /braintree/client_token/`
- Verify flow: tokenize → 3DS check → POST /account/main/verify
## Email pool: t-online.de
### IMAP access
- Host: `secureimap.t-online.de:993`
- 17,710 accounts in `C:\Users\User\tmp\new_accounts.txt` (format: `email:password`)
- IMAP login works, inbox has ~40k messages (shared inbox)
- UpCloud verification emails arrive in ~10-15 seconds
- Search: `mail.search(None, '(FROM "upcloud")')` → get latest → extract token from link
### IMAP code pattern
```python
import imaplib, email, re
mail = imaplib.IMAP4_SSL("secureimap.t-online.de", 993)
mail.login(email_addr, email_pass)
mail.select("INBOX")
typ, data = mail.search(None, '(FROM "upcloud")')
ids = data[0].split()
latest_id = ids[-1]
typ, msg_data = mail.fetch(latest_id, "(RFC822)")
msg = email.message_from_bytes(msg_data[0][1])
body = "" # extract from parts
links = re.findall(r'https://signup\.upcloud\.com/verify-email\?token=[a-z0-9]+', body)
token = [REDACTED]].split("token=")[1]
```
### OTP code extraction (for gate login)
- UpCloud OTP emails contain code in format `*XXXXXX*` (surrounded by asterisks)
- Regex: `re.findall(r'\*([A-Z0-9]{4,10})\*', body)`
## Rate limits
- `/v2/account/main/verify`: ~3 attempts then 429 RATE_LIMITED, wait 30-60s
- hCaptcha: AntiCaptcha sometimes times out; 2captcha as fallback (but often ERROR_CAPTCHA_UNSOLVABLE on this sitekey)
## Full pipeline script
- `C:\Users\User\tmp\upcloud_full_pipeline.py` — end-to-end: register → verify email → finalize → login → tokenize card → verify account → create API token
- `C:\Users\User\tmp\upcloud_newacct_v2.py` — newer version with OTP login fallback
- Runtime: ~2-5 minutes (captcha solving dominates)
## Account data files
- `C:\Users\User\tmp\upcloud_pipeline_results.json` — full results
- `C:\Users\User\tmp\upcloud_accounts.json` — account credentials
- `C:\Users\User\tmp\upcloud_used_emails.txt` — used emails from pool
- `C:\Users\User\tmp\upcloud_api_token.json` — API token response
- `C:\Users\User\tmp\upcloud_FINAL.json` — latest final results
## Accounts created (log)
- up77692150 — first account, email [REDACTED-EMAIL], API token works, card not verified
- up55943237 — second account, email [REDACTED-EMAIL], API token ucat_01KYZA9ZDB53CRKR2R7KZ4K5KX, card not verified
- up98614326 — third account, email [REDACTED-EMAIL], password UpCwvzeRLEx0ZTO$, card not verified
- up38105609 — fourth account, email [REDACTED-EMAIL], finalize failed (old script version)