> ## Documentation Index
> Fetch the complete documentation index at: https://docs.memoclaw.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Session Auth

> POST /auth/session — Exchange a wallet signature for a JWT session token.

<Note>
  This endpoint is free and does not require x402 payment.
</Note>

Session auth lets you sign once with your wallet and use a JWT token for subsequent requests. This avoids signing every request individually and is used by the MemoClaw dashboard.

## Request Body

<ParamField body="address" type="string" required>
  Your EVM wallet address.
</ParamField>

<ParamField body="timestamp" type="number" required>
  Current Unix timestamp (seconds). Must be within 5 minutes of server time.
</ParamField>

<ParamField body="signature" type="string" required>
  Signature of the message `memoclaw-auth:{timestamp}` signed with your wallet's private key.
</ParamField>

## Response (200)

<ResponseField name="token" type="string">
  JWT session token. Valid for 7 days. Include as `Authorization: Bearer {token}` in subsequent requests.
</ResponseField>

<ResponseField name="wallet" type="string">
  Your wallet address.
</ResponseField>

<ResponseField name="expires_at" type="string">
  ISO 8601 expiry timestamp for the token.
</ResponseField>

## Example

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://api.memoclaw.com/auth/session \
    -H "Content-Type: application/json" \
    -d '{
      "address": "0x1234567890abcdef1234567890abcdef12345678",
      "timestamp": 1707800000,
      "signature": "0x..."
    }'
  ```

  ```javascript JavaScript theme={null}
  import { privateKeyToAccount } from "viem/accounts";

  const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
  const timestamp = Math.floor(Date.now() / 1000);
  const message = `memoclaw-auth:${timestamp}`;
  const signature = await account.signMessage({ message });

  const response = await fetch("https://api.memoclaw.com/auth/session", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      address: account.address,
      timestamp,
      signature,
    }),
  });

  const { token } = await response.json();

  // Use the token for subsequent requests
  const memories = await fetch("https://api.memoclaw.com/v1/memories", {
    headers: { Authorization: `Bearer ${token}` },
  });
  ```

  ```python Python theme={null}
  from eth_account import Account
  from eth_account.messages import encode_defunct
  import time, requests

  account = Account.from_key("0x...")
  timestamp = int(time.time())
  message = f"memoclaw-auth:{timestamp}"
  signed = account.sign_message(encode_defunct(text=message))

  response = requests.post("https://api.memoclaw.com/auth/session", json={
      "address": account.address,
      "timestamp": timestamp,
      "signature": signed.signature.hex(),
  })

  token = response.json()["token"]

  # Use the token for subsequent requests
  memories = requests.get("https://api.memoclaw.com/v1/memories",
      headers={"Authorization": f"Bearer {token}"})
  ```

  ```typescript TypeScript theme={null}
  import { privateKeyToAccount } from "viem/accounts";

  const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
  const timestamp = Math.floor(Date.now() / 1000);
  const signature = await account.signMessage({
    message: `memoclaw-auth:${timestamp}`,
  });

  const { token } = await fetch("https://api.memoclaw.com/auth/session", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ address: account.address, timestamp, signature }),
  }).then(r => r.json());

  // Use: Authorization: Bearer {token}
  ```
</CodeGroup>

```json Response theme={null}
{
  "token": "eyJhbGciOiJIUzI1NiIs...",
  "wallet": "0x1234567890abcdef1234567890abcdef12345678",
  "expires_at": "2026-02-20T17:00:00Z"
}
```

## Errors

| Status | Description                                              |
| ------ | -------------------------------------------------------- |
| 401    | Invalid signature or expired timestamp.                  |
| 422    | Missing required fields (address, timestamp, signature). |

<Tip>
  Session tokens are ideal for frontend applications like the dashboard where you don't want to sign every request. For server-to-server usage, the free tier `x-wallet-auth` header or x402 payment is more straightforward.
</Tip>
