POST

LoginWithOtp

Passwordless login with username only (no password). username accepts an email address or numeric user id (same account lookup style as Login). First call sends a one-time code to the user's email. Second call with the same username plus otp returns a bearer token (same token shape as Login).

Permissions

  • This function can be called without a bearer token.

Action

  • Runs the LoginWithOtp function and returns JSON.

Push Service

No push is sent because this function only reads data or returns helper information.

Automation

No automation is run for this function.

Special Instructions

  • This route does not use password. For username/password (+ optional OTP) use Login.
  • Also callable as /app/Login.WithOtp (same handler).
  • username may be an email ([email protected]) or user id (47). Lookup matches active user_detail like Login (id / user_name / email).
  • OTP is always sent to the matched user's email address on file.
  • Step 1: POST username only → success=3, otp_required=true, and a 6-digit code is emailed.
  • Step 2: POST the same username with otp → success=1 and token / token_type Bearer.
  • OTP expires in about 10 minutes. Wrong OTP returns invalid_otp and keeps otp_required=true.
  • LoginWithOtp OTP storage is separate from password Login OTP so the two flows do not conflict.
  • After success, call protected routes with Authorization: Bearer TOKEN, then usually User.Basic.

Required Parameters

NameTypeSampleExplanation
username
post
string[email protected]Login identifier — email address or numeric user id (same lookup as Login). Aliases: email, id, user.

Optional Parameters

NameTypeSampleWhat it gives
otp
post
string123456One-time code from the email after the first call. Omit on the first call to request a new OTP. Alias: email_otp.

Sample Request

{
    "url": "\/app\/LoginWithOtp",
    "method": "POST",
    "body": {
        "username": "[email protected]"
    },
    "curl_step1": "curl --location 'https:\/\/YOUR_HOST\/app\/LoginWithOtp' \\\n--data-urlencode '[email protected]'",
    "curl_step2": "curl --location 'https:\/\/YOUR_HOST\/app\/LoginWithOtp' \\\n--data-urlencode '[email protected]' \\\n--data-urlencode 'otp=123456'",
    "curl_by_id": "curl --location 'https:\/\/YOUR_HOST\/app\/LoginWithOtp' \\\n--data-urlencode 'username=47'",
    "url_user": "https:\/\/{user}.bull36.com\/app\/LoginWithOtp",
    "url_domain": "https:\/\/{domain}\/app\/LoginWithOtp"
}

Endpoint

POST /app/LoginWithOtp
POST https://{user}.bull36.com/app/LoginWithOtp
POST https://{domain}/app/LoginWithOtp

Sample Output

{
    "success": "1",
    "message": "Login Success",
    "token": "YOUR JWT TOKEN",
    "token_type": "Bearer",
    "expires_in": 43200,
    "expires_at": "2026-07-17T13:00:00+00:00",
    "user": {
        "id": 47,
        "owner_id": 14,
        "email": "[email protected]",
        "user_name": "eli"
    },
    "daily_password": 0
}

OTP Response

{
    "success": "3",
    "message": "OTP send in your email...!",
    "otp_required": true,
    "expires_in": 600
}

Protection

Login attempts are limited to 8 attempts per 60 seconds. Too many attempts will pause new attempts for 300 seconds.

JavaScript Example

async function loginWithOtp({ domain = 'https://{domain}', username, otp = '' }) {
  const body = new URLSearchParams({ username });
  if (otp) body.set('otp', otp);

  const res = await fetch(`${domain}/app/LoginWithOtp`, {
    method: 'POST',
    body
  });

  const data = await res.json();
  if (data.otp_required) {
    return { otpRequired: true, message: data.message, data };
  }
  if (!data.token) {
    throw new Error(data.message || 'LoginWithOtp failed');
  }

  return {
    token: data.token,
    tokenType: data.token_type || 'Bearer',
    expiresAt: data.expires_at || null,
    raw: data
  };
}

// 1) Request OTP with email or user id (no password).
const first = await loginWithOtp({
  domain: 'https://{user}.bull36.com',
  username: 'USER EMAIL OR USER ID'
});
if (first.otpRequired) {
  // 2) Complete login with the emailed OTP.
  const auth = await loginWithOtp({
    domain: 'https://{user}.bull36.com',
    username: 'USER EMAIL OR USER ID',
    otp: '123456'
  });
  console.log(auth.token);
}

Error Example

{
    "success": "0",
    "message": "User not exist"
}