---
title: "SIWE login (first login creates account)"
method: POST
path: "/auth/siwe/login"
tags: ["Auth"]
---

# SIWE login (first login creates account)

`POST /auth/siwe/login`

## Request

- Base URL: `https://console-api.blockvectra.com/v1`
- URL: `https://console-api.blockvectra.com/v1/auth/siwe/login`
- Auth: none required

Submit raw challenge message and signature. Request `Origin` mode must match challenge: browser challenge must send same `Origin` (`https://<stored domain>`), programmatic challenge must omit `Origin`, otherwise returns 400 `siwe_invalid` (reason `domain_mismatch`). Verification failure returns 400 `siwe_invalid` with `reason` indicating failure type (expired, chain_mismatch, domain_mismatch, signature; nonce reuse classified as expired). Message must be submitted verbatim: modifying any content (including Chain ID) results in reason `signature`; `chain_mismatch` occurs only if configured Chain ID changes after challenge issuance. If wallet identity does not exist, an account is created (`account_created: true`, new account balance 0).

Scope of support:
- Supported: EOA wallets on Ethereum mainnet (Chain ID 1).
- Not supported: Any other chains (Chain ID is embedded by server; submitting modified Chain ID fails byte-for-byte check returning 400 `siwe_invalid`, reason `signature`), contract wallets (EIP-1271), and smart accounts (eth_call verification not supported; mismatch returns siwe_invalid).

## Request body

- SiweLoginRequest
  - `message` string, required: EIP-4361 message (LF line endings, no trailing newline), up to 2048 bytes.
  - `signature` string, required: 65-byte ECDSA signature (r||s||v).
  - `ref` string, nullable: Optional sign-up channel attribution tag, saved once only when creating a new account. Lowercase letters, digits, `.`, `_`, `-`, 1–64 characters; any other value (including uppercase, empty string) returns 400 `invalid_request` without case folding.
  - `referrer` string, nullable: Optional referrer URL or hostname, saved once only when creating a new account, storing hostname only (lowercase, IDNA ASCII, without protocol, port, path, query). An omitted or null referrer is treated as omitted. A string from which no usable hostname can be extracted, including a blank string, is also treated as omitted (stored as null), with account creation succeeding normally. Only non-null, non-string values return 400 invalid_request.

## Response `200`

Login successful. Session token appears only this once; response includes `Cache-Control: no-store`.

- SessionResponse
  - `session` object, required
    - `token` string, required: Session token, displayed only this once.
    - `expires_at` string, date-time, required: RFC 3339 UTC, second precision, ending in `Z` (`2026-09-26T08:00:00Z`); no fractional seconds, without `+00:00` timezone offsets.
    - `idle_timeout_secs` integer, required: Idle timeout (seconds).
  - `account_created` boolean, required: Whether this login created a new account.

## Other responses

- `400`: Signature or message verification failed, unknown fields, invalid `ref`.
- `403`: Account has been disabled; login not permitted.
- `413`: Request body exceeds 64 KiB limit. Exceeding this limit returns 413 (`payload_too_large`).
- `429`: Rate limit exceeded during login: request rate limit is `rate_limited`; sign-up budget exhaustion is `signup_rate_limited`, with `reason` `per_ip` (same network prefix) or `global` (all sources combined).
- `500`: Internal server error.
- `503`: New account creation temporarily unavailable; affects new registrations only; existing users log in normally.

---

[API](https://skmtc.dev/blockvectra/apis/blockvectra-console-api.md) · [All operations](https://skmtc.dev/blockvectra/apis/blockvectra-console-api/llms.txt) · [OpenAPI document](https://skmtc.dev/blockvectra/apis/blockvectra-console-api/revisions/28c91298f433?raw)
