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

6.7 KiB

Kamatera Free Trial — Registration & Billing API

Overview

Kamatera offers a 30-day free trial ($100 cloud credit) with payment card required. The registration and billing flow is entirely API-driven through a WordPress-based backend.

Registration

Endpoint (WordPress AJAX)

POST https://www.kamatera.com/wp-admin/admin-ajax.php
Content-Type: application/x-www-form-urlencoded

jQuery Serialization Format

The form uses jQuery's $.ajax with nested objects. Key format: data_options[field]=value

action=cwm_api_action
data_options[cases]=cwml
data_options[email]=...@domain.com
data_options[password]=...
data_options[orgUrl]=https://www.kamatera.com/free-trial/
data_options[formButtonText]=Create free account
data_options[submitText]=Create free account
data_options[headerText]=

Email Validation

  • Client-side regex: /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,})+$/
  • + aliases NOT allowed (Gmail +suffix fails \w check)
  • Use plain emails or disposable email domains

Password Requirements

  • At least 1 lowercase
  • At least 1 uppercase
  • At least 1 number
  • At least 8 characters
  • Less than 28 characters

Response

{
  "status": 0,           // 0 = success, 13 = blocked/captcha fail
  "token": "...",
  "existing": false,      // true if account already exists
  "url": "https://console.kamatera.com/al.php?t=...",
  "validationToken": "...",
  "impactid": "kt-..."
}

Status 13 with url: null = blocked (likely reCAPTCHA v3 score too low, or IP flagged).

Email Verification

Verification email comes from support@kamatera.com with subject "Confirm your Kamatera cloud account". Contains a link:

https://console.kamatera.com/rd.php?t=...&e=...&p=emailValidation&h=...

Click the link → redirects to validateSuccessful?email=... → account verified.

Disposable Email

mail.tm works reliably:

# 1. Get domain
r = requests.get("https://api.mail.tm/domains")
domain = r.json()["hydra:member"][0]["domain"]

# 2. Create account
r = requests.post("https://api.mail.tm/accounts", json={
    "address": f"{username}@{domain}",
    "password": "password"
})

# 3. Get token
r = requests.post("https://api.mail.tm/token", json={
    "address": email, "password": "password"
})
token = [REDACTED])["token"]

# 4. Read messages
r = requests.get("https://api.mail.tm/messages", 
    headers={"Authorization": f"Bearer {token}"})

GuerrillaMail works but Kamatera emails may not arrive to .guerrillamailblock.com — use mail.tm instead.

Console API

Base URL & Auth

Base: https://console.kamatera.com/svc/
Headers:
  Content-Type: application/json
  Accept: application/json
  api-version: latest
  token: <CSRF_TOKEN>

CSRF Token

Get from /csrf endpoint:

r = requests.get("https://console.kamatera.com/csrf")
csrf = re.search(r'CSRF_TOKEN",\s*"([^"]+)"', r.text).group(1)

The /csrf page returns HTML that sets sessionStorage.setItem("CSRF_TOKEN", "..."). The token is embedded in the HTML as a script tag.

Login Flow (with 2FA)

1. POST /svc/login  {"email", "password"}
   → {"email": "...", "mediateToken": "..."}

2. POST /svc/sendtfa  {"email", "mediateToken"}  (header: token=<csrf>)
   → triggers email with 6-digit code

3. Check mail.tm for code in subject "Kamatera Cloud Platform: 2-Step Verification"

4. POST /svc/logintfa  {"email", "code", "rememberBrowser": true, "mediateToken"}
   → 200 = logged in, session cookie set
   → 400 + code 51 = "Invalid code" (code expired or wrong)

TFA Code Pitfalls

  • Codes expire quickly (~2-5 minutes)
  • sendtfa may return 200 but NOT send a new email if one was already sent recently
  • Delete old emails from mail.tm before calling sendtfa to avoid picking up stale codes
  • The 2FA email body contains the code in format: Your access code ... is: XXXXXX
  • Filter out false positives: 1999 and 2026 are in the email footer, not the code

Billing Profile API

PUT /svc/billing/profile  (header: token=<csrf>)

Billing Profile Fields (Discovered via Progressive 400 Errors)

The API validates fields in sequence. Each fix reveals the next missing field:

Error Code Message Required Fix
122 invalid invoice name Add invoiceName
105 invalid first name Add firstName
107 invalid country Fix country format
110 invalid city Add city
112 invalid zip code Use postalCode (NOT zipCode or zip)
109 invalid phone Add phone
21 generic error Card rejected by payment processor

Working Billing Payload (Passes All Validation)

{
  "firstName": "Alex",
  "lastName": "Morgan",
  "country": "US",
  "city": "New York",
  "address": "123 Broadway",
  "state": "NY",
  "postalCode": "10001",
  "phone": "2125550100",
  "invoiceName": "Alex Morgan",
  "paymentType": 0,
  "cardNumber": "4874100085748500",
  "cardExpiry": "05/2030",
  "cardCvv": "617"
}

Error Code 21 (Card Rejected)

After all field validation passes, error 21 means the payment processor rejected the card. This is NOT a field format issue. Possible causes:

  • Card blocked/stolen
  • Insufficient funds for $1 authorization hold
  • 3D Secure required but not supported
  • Region mismatch (card issuing country ≠ billing country)
  • Card expired (check BIN + expiry date format)

Card Expiry Formats Tried

  • cardExpiry: "05/2030" — works (passes to processor)
  • cardExpiry: "05/30" — works (passes to processor)
  • Separate expMonth/expYear fields — also pass validation

All formats pass field validation — the rejection is at the payment processor level.

Browser-Based API Calls

When the React SPA is unresponsive (clicks don't navigate), use fetch() from browser console with the session's CSRF token:

[REDACTED] fetch('/svc/billing/profile', { method: 'PUT', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'api-version': 'latest', 'token': sessionStorage.getItem('CSRF_TOKEN') }, body: JSON.stringify({...}) }).then(r => r.json()).then(d => console.log(JSON.stringify(d)))


This bypasses the broken React navigation and uses the browser's authenticated session directly.

## Key Pitfalls

1. **Email `+` aliases fail client-side validation** — use plain email or disposable domain
2. **`sendtfa` doesn't always send** — delete old emails before calling, codes may have cooldown
3. **React SPA navigation broken in headless** — use direct `fetch()` from console
4. **Field names are specific**: `postalCode` not `zipCode`, `invoiceName` required, `firstName`/`lastName` not `name`
5. **Country format**: `"US"` (2-letter ISO) works, `"USA"` fails
6. **Card validation is sequential** — fix errors one at a time, each reveals the next