POST /signup.ashx #
Create a new user account on this tenant. The user is created with disabled=true and role=guest; an activation email is dropped into the SMTP pickup directory and the user can sign in after clicking the link.
Request
Form fields:
user—[a-z0-9_.-]{1,64}, must be unused and not a reserved namename— 1–120 chars, displayed nameemail— valid shape, used for the activation linkha1—MD5(user:realm:password), 32 hex (browser computes it)captcha_token,captcha_answer— from/captcha.ashx
Response
{ "ok": true, "user": "<username>" }
Errors (verified 2026-06-05)
400 invalid_request— missing field, bad shape, reserved username, HA1 not 32 hex.{"error":"invalid_request","error_description":"user, name, email, ha1, captcha_token, captcha_answer required"}400 captcha_failed— token or answer do not match.{"error":"captcha_failed","error_description":"…"}405— non-POST request.409 conflict— user already exists.429— 3 signups per IP per hour.500— credentials file or pickup directory I/O failure.
Example (complete signup flow)
# 1) Fetch captcha + read the question to the user
$ CAP=$(curl -s https://phone.codeb.io/captcha.ashx)
$ TOK=$(echo "$CAP" | python3 -c "import sys,json; print(json.load(sys.stdin)['token'])")
# 2) Hash the password in the browser (or here, locally; never send plaintext)
# HA1 = MD5(user:realm:password). The realm for phone.codeb.io is "phone.codeb.io".
$ HA1=$(printf 'alex:phone.codeb.io:s3cret-pw!' | md5sum | awk '{print $1}')
# 3) POST the signup
$ curl -X POST https://phone.codeb.io/signup.ashx \
--data-urlencode "user=alex" \
--data-urlencode "name=Alex Example" \
--data-urlencode "email=alex@example.com" \
--data-urlencode "ha1=$HA1" \
--data-urlencode "captcha_token=$TOK" \
--data-urlencode "captcha_answer=<the integer the user typed>"
{"ok":true,"user":"alex"}
# 4) An activation email lands in the user's inbox; clicking the link
# hits /activate.ashx?token=<one-time> and flips disabled=false.
Plaintext passwords never reach the server — the browser hashes
user:realm:password to an HA1 before transmission, identical to the SIP digest scheme used by the rest of the platform. The activation token has a 7-day TTL.