POST

Login

Login with username, email, id, or phone and receive a bearer token or an OTP-required response. OTP is required only when the account has two_auth enabled, or when the organization owner has two_auth_for_team_option enabled (same rules as dashboard Login. On a company subdomain (e.g. user.bull36.com) Host must match account user_domain — mismatch returns success=0 (user does not exist in this company). On a main brand host (bull36.com, www.bull36.com, biz1.co.il, mastrocrm.com, …) domain match is skipped: username/password alone is enough. Custom user_detail.domain hosts are allowed; localhost/IP/unknown brands skip the check. For passwordless OTP login (username = email or user id, no password), use LoginWithOtp instead.

Permissions

  • This function can be called without a bearer token.

Action

  • Runs the Login 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

  • OTP gate matches dashboard: user.two_auth OR owner.two_auth_for_team_option. Personal Two auth off is not enough if Settings → Two auth for team is on.
  • Domain gate (company subdomain only): after password OK, Host must equal {user_domain}.{bull36.com|biz1.co.il|mastrocrm.com}. Wrong subdomain (e.g. eli.bull36.com for user_domain=user) returns success=0, error user_not_in_company — no bearer token.
  • Main brand hosts (bull36.com, www.bull36.com, biz1.co.il, mastrocrm.com, …) skip the company domain gate — login with username/password only.
  • The same Host ↔ company gate runs on every protected App API when called on a company subdomain. On a main brand host the gate is also skipped.
  • When otp_required is true, response may include otp_reason: user_two_auth | two_auth_for_team | force_otp (rate-limit security).
  • After success=3, POST the same username/password again with otp from the email.

Required Parameters

NameTypeSampleExplanation
password
post
stringYOUR PASSWORDPassword for the login identifier.

Optional Parameters

NameTypeSampleWhat it gives
email
post
stringeli@example.comEmail address for login. You may send username, id, or phone instead.
username
post
stringeliUsername for login. Used when email is not sent.
id
post
int47Numeric user id for login. Used when email/username are not sent.
phone
post
string0500000000Phone value for login when supported by the account lookup.
otp
post
string123456One-time code emailed after the first password-only Login when 2FA is required. Send the same username/password again with this otp field.

Sample Request

{
    "url": "\/app\/Login",
    "method": "POST",
    "body": {
        "username": "eli",
        "password": "YOUR PASSWORD"
    },
    "url_user": "https:\/\/{user}.bull36.com\/app\/Login",
    "url_domain": "https:\/\/{domain}\/app\/Login"
}

Endpoint

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

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",
    "redirect_to": "dashboard\/admin"
}

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 getBearerToken({ domain = 'https://{domain}', username, password, otp = '' }) {
  const body = new URLSearchParams({ username, password });
  if (otp) body.set('otp', otp);

  const res = await fetch(`${domain}/app/Login`, {
    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 || 'Login failed');
  }

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

// 1) First call returns otp_required and emails a 6-digit code.
const first = await getBearerToken({
  domain: 'https://{user}.bull36.com',
  username: 'USER EMAIL',
  password: 'USER PASSWORD'
});
if (first.otpRequired) {
  // 2) Second call completes login with the emailed OTP.
  const auth = await getBearerToken({
    domain: 'https://{user}.bull36.com',
    username: 'USER EMAIL',
    password: 'USER PASSWORD',
    otp: '123456'
  });
  console.log(auth.token);
}

Error Example

{
    "success": "0",
    "message": "Login failed"
}