> For the complete documentation index, see [llms.txt](https://pred-1.gitbook.io/pred-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://pred-1.gitbook.io/pred-docs/documentation/api-reference/authentication.md).

# Authentication

Required headers, token refresh, and EIP-712 CreateProxy signature for login. For overview, getting started, and environment configuration, see **Overview**.

### Required headers

* `Authorization: Bearer <token>` (for authenticated endpoints)
* `X-API-Key: <api_key>` (required for login-with-signature only)
* `X-Wallet-Address: <wallet_address>` (for order and portfolio endpoints)
* `X-Proxy-Address: <proxy_wallet_address>` (for order and portfolio endpoints)

**Token refresh:** Access tokens are automatically refreshed by the SDK whenever their remaining lifetime drops below the configured threshold. The default threshold is **5 minutes**, and can be overridden via the `RefreshThresholdSeconds` client option.

### EIP-712 login signature — CreateProxy

Format: `0x<r><s><v>` (132 hex characters). Low-s normalized: `s <= curveOrderHalf`.

**Domain (NO version field):** All values below are ENV-specific; use the row for your chosen environment (see Environment configuration in **Overview**).

```
EIP712Domain type: "EIP712Domain(string name,uint256 chainId,address verifyingContract)"
name: "Pred Contract Proxy Factory"
chainId:        <Chain ID from environment table — Testnet 84532, Mainnet 8453>
verifyingContract: <Login Contract from environment table>
```

**Message:**

```
CreateProxy type: "CreateProxy(address paymentToken,uint256 payment,address paymentReceiver)"
paymentToken: 0x0000000000000000000000000000000000000000
payment: 0
paymentReceiver: 0x0000000000000000000000000000000000000000
```

**Normalization constants:**

* `curveOrder = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141`
* `curveOrderHalf = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0`

## Login with wallet signature

> Authenticate using an EIP-712 CreateProxy wallet signature. \*\*Required header:\*\* \`X-API-Key\`.\
> \
> See \*\*Authentication\*\* section for CreateProxy domain, message, and signature format (contract addresses, normalization).<br>

````json
{"openapi":"3.1.0","info":{"title":"PRED Trading Platform API","version":"1.0.0"},"tags":[{"name":"Authentication","description":"Required headers, token refresh, and EIP-712 CreateProxy signature for login. For overview, getting started, and environment configuration, see **Overview**.\n\n## Required headers\n\n- `Authorization: Bearer <token>`\n  (for authenticated endpoints)\n- `X-API-Key: <api_key>`\n  (required for login-with-signature only)\n- `X-Wallet-Address: <wallet_address>`\n  (for order and portfolio endpoints)\n- `X-Proxy-Address: <proxy_wallet_address>`\n  (for order and portfolio endpoints)\n\n**Token refresh:** Access tokens are automatically refreshed by the SDK whenever their remaining lifetime drops below the configured threshold. The default threshold is **5 minutes**, and can be overridden via the `RefreshThresholdSeconds` client option.\n\n## EIP-712 login signature — CreateProxy\n\nFormat: `0x<r><s><v>` (132 hex characters). Low-s normalized: `s <= curveOrderHalf`.\n\n**Domain (NO version field):** All values below are ENV-specific; use the row for your chosen environment (see Environment configuration in **Overview**).\n```\nEIP712Domain type: \"EIP712Domain(string name,uint256 chainId,address verifyingContract)\"\nname: \"Pred Contract Proxy Factory\"\nchainId:        <Chain ID from environment table — Testnet 84532, Mainnet 8453>\nverifyingContract: <Login Contract from environment table>\n```\n\n**Message:**\n```\nCreateProxy type: \"CreateProxy(address paymentToken,uint256 payment,address paymentReceiver)\"\npaymentToken: 0x0000000000000000000000000000000000000000\npayment: 0\npaymentReceiver: 0x0000000000000000000000000000000000000000\n```\n\n**Normalization constants:**\n- `curveOrder = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141`\n- `curveOrderHalf = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0`\n"}],"servers":[{"url":"https://testnet.pred.app","description":"Testnet (ENV-specific). Base Sepolia; chain ID 84532. Use with Testnet row in Environment configuration."},{"url":"https://www.pred.app","description":"Mainnet (ENV-specific). Base; chain ID 8453. Use with Mainnet row in Environment configuration."}],"paths":{"/api/v1/auth/login-with-signature":{"post":{"tags":["Authentication"],"summary":"Login with wallet signature","description":"Authenticate using an EIP-712 CreateProxy wallet signature. **Required header:** `X-API-Key`.\n\nSee **Authentication** section for CreateProxy domain, message, and signature format (contract addresses, normalization).\n","operationId":"loginWithSignature","parameters":[{"name":"X-API-Key","in":"header","required":true,"description":"PRED API key","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginWithSignatureRequest"}}}},"responses":{"200":{"description":"Login successful","headers":{"X-Access-Token":{"description":"JWT access token (also in response body)","schema":{"type":"string"}},"Set-Cookie":{"description":"Refresh token cookie: `refresh_token=<token>; Path=/; HttpOnly; Secure; SameSite=Lax`","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}}}},"components":{"schemas":{"LoginWithSignatureRequest":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["wallet_address","signature","message","nonce","chain_type","timestamp"],"properties":{"wallet_address":{"type":"string","description":"EOA wallet address","pattern":"^0x[a-fA-F0-9]{40}$"},"signature":{"type":"string","description":"EIP-712 CreateProxy signature. Format: 0x<r><s><v> (132 hex chars), low-s normalized.","pattern":"^0x[a-fA-F0-9]{130}$"},"message":{"type":"string","description":"Auth message"},"nonce":{"type":"string","description":"Unique nonce (SDK uses nanosecond timestamp)"},"chain_type":{"type":"string","description":"ENV-specific. Use the value for your chosen environment from the Environment configuration table.\nTestnet: base-sepolia\nMainnet: base (not base-mainnet)\n","enum":["base-sepolia","base"]},"timestamp":{"type":"integer","description":"Unix timestamp in seconds"},"username":{"type":"string","description":"Username (optional)"},"name":{"type":"string","description":"Name (optional)"},"profile_picture":{"type":"string","format":"uri","description":"Profile picture URL (optional)"}}}}},"LoginResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"access_token":{"type":"string","description":"JWT access token"},"refresh_token":{"type":"string","description":"Refresh token. Send as `X-Refresh-Token` header (or use the `refresh_token` cookie set by this endpoint) when calling `POST /api/v1/auth/refresh/token`."},"data":{"type":"object","properties":{"user_id":{"type":"string"},"is_new_user":{"type":"boolean"},"is_activated":{"type":"boolean"},"is_new_activated":{"type":"boolean"},"default_username":{"type":"string"},"profile_picture":{"type":"string"},"is_enabled_trading":{"type":"boolean","description":"Whether trading is enabled for the user's proxy wallet.\nIf `false` or missing: complete Safe approval, then **re-login** (MANDATORY).\n"},"wallet_address":{"type":"string"},"proxy_wallet_addr":{"type":"string"}}},"proxy_wallet_addr":{"type":"string","description":"Proxy (Safe) wallet address"},"wallet_address":{"type":"string"}}},"error":{"$ref":"#/components/schemas/Error"}}},"Error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"string"}}},"ErrorResponse":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/Error"},"message":{"type":"string"},"success":{"type":"boolean","default":false}}}},"responses":{"BadRequest":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Unauthorized":{"description":"Authentication required or failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}
````

## Refresh access token

> Refresh the access token using a refresh token. The refresh token can be sent via:\
> \
> 1\. \*\*Header\*\* (preferred): \`X-Refresh-Token: \<refresh\_token>\` — checked first\
> 2\. \*\*Cookie\*\* (fallback): \`refresh\_token\` cookie (set automatically by login endpoint)\
> \
> The refresh token from the login response body (\`refresh\_token\` field) can be sent as the \`X-Refresh-Token\` header.\
> \
> \*\*Token rotation:\*\* Each refresh returns a new refresh token (via \`Set-Cookie\`). The old refresh token is invalidated — using it again returns 401 \`REFRESH\_TOKEN\_ALREADY\_USED\`.\
> \
> \*\*Response includes:\*\* new \`access\_token\`, \`user\_id\`, \`proxy\_wallet\_address\`, \`is\_enabled\_trading\`, and user profile data.<br>

````json
{"openapi":"3.1.0","info":{"title":"PRED Trading Platform API","version":"1.0.0"},"tags":[{"name":"Authentication","description":"Required headers, token refresh, and EIP-712 CreateProxy signature for login. For overview, getting started, and environment configuration, see **Overview**.\n\n## Required headers\n\n- `Authorization: Bearer <token>`\n  (for authenticated endpoints)\n- `X-API-Key: <api_key>`\n  (required for login-with-signature only)\n- `X-Wallet-Address: <wallet_address>`\n  (for order and portfolio endpoints)\n- `X-Proxy-Address: <proxy_wallet_address>`\n  (for order and portfolio endpoints)\n\n**Token refresh:** Access tokens are automatically refreshed by the SDK whenever their remaining lifetime drops below the configured threshold. The default threshold is **5 minutes**, and can be overridden via the `RefreshThresholdSeconds` client option.\n\n## EIP-712 login signature — CreateProxy\n\nFormat: `0x<r><s><v>` (132 hex characters). Low-s normalized: `s <= curveOrderHalf`.\n\n**Domain (NO version field):** All values below are ENV-specific; use the row for your chosen environment (see Environment configuration in **Overview**).\n```\nEIP712Domain type: \"EIP712Domain(string name,uint256 chainId,address verifyingContract)\"\nname: \"Pred Contract Proxy Factory\"\nchainId:        <Chain ID from environment table — Testnet 84532, Mainnet 8453>\nverifyingContract: <Login Contract from environment table>\n```\n\n**Message:**\n```\nCreateProxy type: \"CreateProxy(address paymentToken,uint256 payment,address paymentReceiver)\"\npaymentToken: 0x0000000000000000000000000000000000000000\npayment: 0\npaymentReceiver: 0x0000000000000000000000000000000000000000\n```\n\n**Normalization constants:**\n- `curveOrder = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141`\n- `curveOrderHalf = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0`\n"}],"servers":[{"url":"https://testnet.pred.app","description":"Testnet (ENV-specific). Base Sepolia; chain ID 84532. Use with Testnet row in Environment configuration."},{"url":"https://www.pred.app","description":"Mainnet (ENV-specific). Base; chain ID 8453. Use with Mainnet row in Environment configuration."}],"security":[{"BearerAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT access token from login endpoint"}},"schemas":{"RefreshTokenResponse":{"type":"object","description":"Token refresh response. Includes new access token and user details.\nA new refresh token is also set via `Set-Cookie` header (token rotation).\n","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"access_token":{"type":"string","description":"New JWT access token"},"message":{"type":"string"},"user_id":{"type":"string"},"privy_wallet_address":{"type":"string"},"proxy_wallet_address":{"type":"string"},"is_activated":{"type":"boolean"},"default_username":{"type":"string"},"profile_picture":{"type":"string"},"is_enabled_trading":{"type":"boolean","description":"Whether trading is enabled (reflects current state after Safe approval)"},"data":{"type":"object","description":"Structured response for compatibility","properties":{"user_id":{"type":"string"},"is_activated":{"type":"boolean"},"default_username":{"type":"string"},"profile_picture":{"type":"string"},"is_enabled_trading":{"type":"boolean"}}}}},"error":{"$ref":"#/components/schemas/Error"}}},"Error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"string"}}},"ErrorResponse":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/Error"},"message":{"type":"string"},"success":{"type":"boolean","default":false}}}},"responses":{"Unauthorized":{"description":"Authentication required or failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"paths":{"/api/v1/auth/refresh/token":{"post":{"tags":["Authentication"],"summary":"Refresh access token","description":"Refresh the access token using a refresh token. The refresh token can be sent via:\n\n1. **Header** (preferred): `X-Refresh-Token: <refresh_token>` — checked first\n2. **Cookie** (fallback): `refresh_token` cookie (set automatically by login endpoint)\n\nThe refresh token from the login response body (`refresh_token` field) can be sent as the `X-Refresh-Token` header.\n\n**Token rotation:** Each refresh returns a new refresh token (via `Set-Cookie`). The old refresh token is invalidated — using it again returns 401 `REFRESH_TOKEN_ALREADY_USED`.\n\n**Response includes:** new `access_token`, `user_id`, `proxy_wallet_address`, `is_enabled_trading`, and user profile data.\n","operationId":"refreshToken","parameters":[{"name":"X-Refresh-Token","in":"header","required":false,"description":"Refresh token from login response body (`refresh_token` field). Takes priority over cookie.","schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Token refreshed","headers":{"Set-Cookie":{"description":"New refresh token cookie (rotated): `refresh_token=<new_token>; Path=/; HttpOnly; Secure; SameSite=Lax`","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshTokenResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}}}}
````
