Login

Overview

Authenticates an email/password credential. On success, it issues a Passport bearer token plus the user, company, theme, white-label and (for account companies) plan context. Several cases are rejected before a token is issued. These are locked accounts, SSO-only accounts (sso_required), inactive/unverified users, users with no company, and companies with bundle_id < 1.

Prerequisites

  • No authentication — this endpoint is public.

Base URL

EnvironmentURL
Productionhttps://production-api.shoutaboutus.com
Developmenthttps://development-api.shoutaboutus.com

Endpoint

POST /api/v1/login

Authentication

  • No bearer token required — this is a public endpoint.

  • Who can call it: Any user (Partner, Account, or other roles).

  • Public route (no authentication); throttled at 10/min per IP.

  • No partner/account scoping — it authenticates any user regardless of role.

  • The returned account's bundle_id (1=partner, 2=location, 3=account) tells the SPA which role logged in.

  • The endpoint validates the referer host against allowed/white-label hosts via allowHost.

Rate limit

  • 10 requests/min per IP.

Request body

  • Body:
FieldTypeRequiredDescription
emailstringconditionalemail:rfc, max 255. Required unless code is sent.
passwordstringconditionalmax 100. Required unless code is sent.
codestringnoAdmin-issued partner-impersonation code; when sent, email/password are not required.
rememberMebooleannonullable; passed for long-lived session
{
  "email": "[email protected]",
  "password": "<your password>",
  "rememberMe": false
}

Response

  • data.status (string) — "success"
  • data.token (string) — Passport access token
  • data.user (object) — id, username, email, inactive_at (nullable), email_verified_at, phone_number, first_name (person.firstname), last_name (person.lastname), title, role (person.role or "User"), total_location (count of stores reachable by the user)
  • data.company (object) — id, name, bundle_id, plus appended enable_insight_report (0/1), enable_competitive_analysis (0/1), dormant_accounts_enabled (0/1), companyindustry_id, company_industry (id/name), is_sub_partner (0/1), and included company_option (company_id, who_will_pay, enable_generic_alert, enable_insight_report, enable_competitive_analysis)
  • data.theme_options (string) — JSON string
  • data.white_label (object) — logo, white_url, favicon, title, status, login_logo, company_id, email_templates_enabled
  • data.plan (object|null) — only populated when company.bundle_id == 3 (account). The assigned plan (id, plan_name, status, plan_type, enforcement_mode, is_admin_managed) with features (id, plan_id, feature_name, enabled, hard_stop). Null otherwise.

Error cases (not {data}): 401 "Invalid email or password!" / locked-account message; 403 SSO-required ({sso_required:true, sso_url}) or no-company; 400 white-label not allowed / inactive / email not verified / subscription not active.

200 Success · 200

{
  "data": {
    "status": "success",
    "token": "<access-token>",
    "user": {
      "id": 8,
      "username": "[email protected]",
      "email": "[email protected]",
      "first_name": "HiPages",
      "last_name": "Admin",
      "role": "Owner",
      "total_location": 6
    },
    "company": {
      "id": 9,
      "name": "HiPages",
      "bundle_id": 1,
      "companyindustry_id": 7,
      "company_industry": { "id": 7, "name": "Trades & Services" },
      "is_sub_partner": 0
    }
  }
}

401 Invalid credentials · 401

{
  "status": "error",
  "message": "Invalid email or password!",
  "errors": []
}

Errors

StatusMeaning
400The request was rejected — the response explains why
401Invalid email or password! (or the locked-account message)
403The account must sign in via SSO (sso_required), or the user has no company
422The request failed validation — the response names the fields
500Unexpected server error

Example request

curl --request POST \
  --url "https://production-api.shoutaboutus.com/api/v1/login" \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{"email": "[email protected]", "password": "<your password>", "rememberMe": false}'

Did this page help you?