Files
autoreg-skills-max/skills/account-validation/references/upcloud-trial-registration.md

13 KiB
Raw Permalink Blame History

UpCloud Trial Registration & Card Verification

UpCloud promo registration (deploy250 = $250 credits). Full API pipeline, no browser needed for registration — only for 3DS if card passes Braintree.

API Endpoints

Purpose Method URL
Signup init POST https://signup.upcloud.com/api/v2/init
Promo check POST https://signup.upcloud.com/api/v2/check-promo-code
Email verify POST https://signup.upcloud.com/api/v2/verify
Finalize POST https://signup.upcloud.com/api/v2/finalize-lite
Username check GET https://signup.upcloud.com/api/v2/check-username/{username} (404=available)
Password login POST https://gate.upcloud.com/v2/session
OTP send POST https://gate.upcloud.com/v2/user/auth/login/otp
OTP login POST https://gate.upcloud.com/v2/user/auth/login
Account info GET https://gate.upcloud.com/v2/account
Braintree token GET `https://gate.upcloud.com/v2/braintree/client_token/{EUR
Verify card POST https://gate.upcloud.com/v2/account/main/verify
Create API token POST https://gate.upcloud.com/v2/account/tokens
Server create POST https://api.upcloud.com/1.3/server
Account (API) GET https://api.upcloud.com/1.3/account
Zones GET https://api.upcloud.com/1.3/zone

hCaptcha Sitekeys

  • Signup page: e0e06474-e124-4354-8244-7b0c31be88f4 (invisible, enterprise)
  • Login page: 13b63774-5d8c-4b1a-9cfc-8bae5b1abca0 (invisible, enterprise)

Anti-captcha task type: HCaptchaTaskProxyless with isInvisible: True, isEnterprise: True. Solve time ~30-90 sec.

Registration Pipeline

  1. Get email from pool — t-online.de IMAP (secureimap.t-online.de:993), format email:password in new_accounts.txt
  2. Check promo — POST /api/v2/check-promo-code with {"promo_code": "deploy250"}
  3. Solve hCaptcha (signup sitekey)
  4. Init registration — POST /api/v2/init with email, first_name:"signup", last_name:"user", promo_code, captcha
  5. Wait for confirmation email — IMAP search FROM "upcloud", extract verify-email?token=... link
  6. Verify email — POST /api/v2/verify with {"token": verify_token}
  7. Check username — GET /api/v2/check-username/{username} (404 = available)
  8. Finalize — POST /api/v2/finalize-lite with country:"DEU", currency:"EUR", email, first_name, last_name, password, phone, username, promo_code, terms_accepted: true
  9. Account created: credits=25000, trial_mode=1, trial_end set, but active=0 and cores=0

Login

Password login (preferred — 1 captcha)

POST /v2/session
{"captcha_token": "<hcaptcha>", "username": "upXXXXXXXX", "password": "...", "token": true}

Returns 200. ⚠️ The JSON auth_token field contains the literal string "cookie" — NOT the actual token. The real token is in the session cookie auth-token (value ucat_01KYZ...). Use s.headers.update({'Authorization': f'Bearer {s.cookies["auth-token"]}'}) or just let the session cookie carry auth. Do not try to use the JSON auth_token value as a Bearer token.

OTP login (2 captcha solves — timing sensitive)

  1. Solve captcha → POST /v2/user/auth/login/otp with email + captcha_token
  2. Get OTP from IMAP — pattern \*([A-Z0-9]{4,10})\* in email body
  3. Solve captcha again → POST /v2/user/auth/login with captcha_token + code + email

⚠️ OTP expires ~2 min. If captcha solve takes >90s, OTP may be expired by login time. Use UNSEEN IMAP flag to get fresh OTP. Password login avoids this entirely.

Braintree Card Verification

  1. Get client token — GET /v2/braintree/client_token/EUR → decode base64 → extract authorizationFingerprint + graphQL.url
  2. Tokenize card — POST to Braintree GraphQL:
    {"query": "mutation T($input: TokenizeCreditCardInput!){tokenizeCreditCard(input:$input){token}}",
     "variables": {"input": {"creditCard": {"number": "...", "expirationMonth": "...", "expirationYear": "...", "cvv": "..."}, "options": {"validate": false}}}}
    
    Headers: Authorization: Bearer {afp}, Braintree-Version: 2023-08-01 Returns nonce: tokencc_bh_...
  3. Verify — POST /v2/account/main/verify:
    {"account": {"address": "...", "city": "...", "country": "DEU", "first_name": "signup",
     "last_name": "user", "payment_method_nonce": "tokencc_...", "postal_code": "...",
     "company": "", "currency": "EUR", "device_data": "{\"correlation_id\":\"...\"}",
     "state": "", "vat_number": ""}}
    

⚠️ Card Rejection — Ukrainian BINs

Braintree hard-rejects Ukrainian cards before 3DS. This is a $0 auth hold (zero charge), not a payment. Three tested cards all failed:

BIN Scheme Type Bank Country Result
516818 Mastercard Debit JSC VST Bank UA 422 VERIFICATION_ERROR
444111 VISA Credit JSC Universal Bank (monobank) UA 422 VERIFICATION_ERROR
487410 VISA Debit PrivatBank UA 422 VERIFICATION_ERROR

Error: "Unable to verify the account at this time, please make sure your details are correct or try another card."

Tried with 5+ country/address combos (DE, US, UA, FI, NL, GB) — all rejected. Changing billing address country does NOT help — Braintree checks card BIN country, not billing address. 3DS never triggers because the card fails basic validation first. Rate limit (429) kicks in after 3-4 verify attempts.

Fix: Use a non-UA card (EU/US/UK). Braintree blocks UA BINs by risk/sanctions policy.

⚠️ Browser Login — hCaptcha Enterprise + Next.js SPA Blocking

hub.upcloud.com is a Next.js SPA with invisible hCaptcha. Three approaches were tried and all failed for card verification via browser:

POST /v2/session via Python requests returns 200 and sets auth-token cookie on gate.upcloud.com domain. Pre-setting this cookie in Playwright context for hub.upcloud.com does NOT work — the SPA checks its own auth state (likely localStorage or a separate JWT), not the gate cookie. Browser navigates to billing → redirected to login.

2. Login via fetch() in page context — FAILS

Calling fetch('https://gate.upcloud.com/v2/session', ...) from within the Playwright page (on hub.upcloud.com) returns 200, but the auth-token cookie is set on gate.upcloud.com, not hub.upcloud.com. The SPA doesn't recognize the auth. Navigation to /account/billing redirects to /login?next=%2Faccount%2Fbilling.

3. Form fill + hCaptcha textarea injection — FAILS

The login form (<form action="POST" id="login-form">) has input[name="username"] and input[name="password"]. hCaptcha invisible widget creates textarea[name="h-captcha-response"] and textarea[name="g-recaptcha-response"]. Setting the anti-captcha token in these textareas + dispatching input/change events does NOT trigger the React form submit — the SPA's hCaptcha callback (hcaptcha.execute() → Promise) must fire natively. Anti-captcha tokens solved from different IPs are rejected by hCaptcha Enterprise.

hCaptcha Enterprise token rejection (422)

On some attempts, POST /v2/session with anti-captcha token returns 422 invalid-input-response. hCaptcha Enterprise validates that the token was solved from the same browser context/IP. Anti-captcha workers solve from different IPs → token rejected. This is intermittent — sometimes it works (previous session got 200), sometimes not. The intermittency suggests hCaptcha Enterprise risk scoring, not a hard block.

Cloudflare on signup.upcloud.com

signup.upcloud.com/?promo=deploy250 returns Cloudflare "Just a moment..." challenge in Playwright (both headless and headed with --no-sandbox). The challenge does NOT clear within 60s. API signup (POST /api/v2/init) with anti-captcha token returns 422 captcha invalid — Cloudflare invalidates the token. Registration via API works only when Cloudflare doesn't challenge the API endpoint — this is intermittent.

What DOES work

  • Manual browser registration: User confirmed 3DS works when registering manually through the browser — "я только что регнул так же и сработало!! Там 3дс". The browser Braintree flow includes device data collection that triggers 3DS instead of hard rejection. But this requires manual interaction (or a way to solve hCaptcha natively in the browser).
  • API registration (when Cloudflare doesn't challenge): signup + email verify + finalize all work via API. Account is created with 25000 credits but cores=0 until card is verified.
  • API password login (when hCaptcha accepts the token): login 200, tokenize works, but verify still fails for UA BINs.

Viable path for UA cards

None via API. Braintree $0 auth blocks UA BINs regardless of device data. The user's manual browser registration succeeded with 3DS — this suggests either (a) a non-UA card was used, or (b) the browser Braintree flow with full device data collection bypasses the BIN check and goes to 3DS. The latter would require solving hCaptcha natively in the browser (not via anti-captcha).

Browser Automation Pitfalls

Playwright networkidle timeout on hCaptcha pages

UpCloud login page loads an invisible hCaptcha that keeps a long-poll connection open. page.goto(url, wait_until="networkidle") will always timeout (30s) because hCaptcha never reaches network idle. Use wait_until="domcontentloaded" + time.sleep(5) to let JS render the form.

hCaptcha token rejection (422 invalid-input-response)

Anti-captcha tokens are sometimes rejected by hCaptcha with 422 invalid-input-response on the login endpoint. This is intermittent — the same anti-captcha key works on retry. If login returns 422, re-solve captcha and retry. Do NOT treat it as a permanent block. hCaptcha Enterprise may validate solver IP against request IP.

OTP expiry timing

OTP login requires 2 captcha solves (~60-90s each). OTP expires in ~2 min. Sequence: solve captcha #1 → send OTP → get OTP from IMAP → solve captcha #2 → login. If captcha #2 takes >60s, OTP may expire. Password login avoids this entirely (1 captcha, no OTP).

Playwright headed mode with --no-sandbox works for Cloudflare on hub.upcloud.com

p.chromium.launch(headless=False, args=['--no-sandbox', '--disable-blink-features=AutomationControlled', ...]) passes Cloudflare on hub.upcloud.com/login (title changes from "Just a moment..." to "UpCloud – Login" within ~4s). However, signup.upcloud.com Cloudflare challenge does NOT clear even in headed mode.

API Token Extraction

After login (password or OTP):

POST /v2/account/tokens
{"name": "eni-api-token", "expires_at": "2027-09-01T00:00:00.00001Z"}

Returns {"token": {"token": "ucat_01KYZ..."}} — use as Authorization: Bearer ucat_... for api.upcloud.com/1.3/*.

Server Creation

POST /api.upcloud.com/1.3/server
{"server": {
  "zone": "de-fra1",
  "title": "eni-vps",
  "hostname": "eni-vps",
  "plan": "1xCPU-1GB",
  "storage_devices": {"storage_device": [{
    "action": "create",
    "title": "disk1",
    "size": 25,
    "tier": "maxiops"
  }]},
  "login_user": {"username": "root", "ssh_keys": {"ssh_key": ["ssh-rsa ..."]}}
}}

Pitfalls:

  • storage_device MUST have title field or → STORAGE_TITLE_MISSING
  • action: "create" not "clone" or → STORAGE_MISSING
  • login_user is an object with username + ssh_keys.ssh_key array, not a string
  • Server creation fails with SERVER_CORE_LIMIT_REACHED if trial not activated (card not verified): "Trial CPU core quota of 0 exceeded by 1"

Trial Activation Flow

Without card verification:

  • active=0, cores=0, memory=0, public_ipv4=0
  • trial_started=None (or 0)
  • trial_mode=1, trial_end is set (future date)
  • trial_resource_limits shows limits (8 cores, 16GB, 5 IPs) but resource_limits shows 0

After card verification:

  • active=1, trial starts, cores get real limits
  • Can create servers, allocate IPs, use object storage

Zones (15 total)

de-fra1 (Frankfurt), fi-hel1 (Helsinki), fi-hel2, nl-ams1 (Amsterdam), uk-lon1 (London), us-nyc1 (New York), us-chi1 (Chicago), us-sjo1 (San Jose), es-mad1 (Madrid), pl-waw1 (Warsaw), se-sto1 (Stockholm), dk-cph1 (Copenhagen), no-svg1 (Stavanger), au-syd1 (Sydney), sg-sin1 (Singapore)

Session Artifacts (2026-08-01/02)

  • 3 accounts registered: up55943237, up38105609, up77692150
  • 2 API tokens extracted (both HTTP 200 verified):
    • up55943237: ucat_01KYZA9ZDB53CRKR2R7KZ4K5KX
    • up77692150: ucat_01KYZ158R2A3MYZ4J5JT51Q27V
  • Both have 25000 credits but cores=0 — trial not activated, card rejected
  • Email pool: t-online.de, 10 emails used, ~626KB account file
  • Anti-captcha key: [REDACTED-KEY]
  • 3 UA BIN cards tested and rejected: 516818 (MC Debit VST), 444111 (VISA Credit monobank), 487410 (VISA Debit PrivatBank)
  • User confirmed manual browser registration with 3DS works — browser Braintree device data collection may bypass UA BIN block
  • Browser automation blocked: hCaptcha Enterprise rejects anti-captcha tokens for SPA login, Cloudflare blocks signup page, cookie domain mismatch between gate.upcloud.com and hub.upcloud.com