Skip to Content
MuoCeon Docs
v1auth contextCredential management

Email credential

Add an email, confirm it, resend the code, and promote it to primary.

Email is the most basic sign-in and delivery address. An account can bind several addresses, but only the primary one decides where verification codes and reset links go.

Endpoints

MethodPathPurposeStep-up
POST/v1/auth/credentials/email/optionsSend a code to the new addressmax_age=300
POST/v1/auth/credentials/emailSubmit the code to finish bindingNone
POST/v1/auth/credentials/email/resendResend the codeNone
POST/v1/auth/credentials/email/:credentialId/primaryMake it the primary emailmax_age=300

Step one: send the code

ParameterTypeRequiredNotes
emailstring✅Address to bind, 3–254 chars
{ "success": true, "expires_in": 600, "resend_after": 60 }

The address is pinned in server-side state and valid for 10 minutes. resend_after is "seconds until a resend is allowed", computed by the server. Do not count it down on the client: the cooldown is set only after the mail was actually sent, so a locally counted timer drifts away from the server's remaining time.

Step two: confirm

ParameterTypeRequiredNotes
codestring✅The received code, 4–32 chars
{ "success": true, "credential": { "id": "cred_...", "type": "email" } }

This step does not take an address

The address was already pinned in step one. Accepting it again would allow the combination "code sent to A, binding B". The account's first email automatically becomes the primary one.

Resending

No request body; the response has the same shape as step one. It only requires a normal session: the code lives 600 seconds while the step-one elevation window is 300, so requiring step-up here would bounce any user who waited out the timer to a fresh sign-in.

Repeated calls inside the cooldown are rejected with Retry-After.

Making it primary

{ "success": true, "credentials": [ { "id": "cred_...", "primary": true } ] }

It returns the whole email set rather than one row: primacy is a relation between rows, and returning a single row would leave the client to infer which one was demoted.

A primary email cannot be deleted, so this endpoint is the only way to move that anchor. Every call writes an audit entry.

On this page