Skip to content

Quickstart

This guide covers wallet sign-in, an authenticated API call, and sending a message, using curl. You need an Ethereum wallet capable of personal_sign and a running API server.

http://localhost:3001

Bring the stack up with Docker — see Run the stack locally. Verify the API is up:

Health check
curl http://localhost:3001/health

All current endpoints live under the /api/v1/ prefix. The examples below use the local base URL.

Zentalk authenticates by wallet signature, then issues JWTs:

  1. The client constructs a login message that includes a millisecond timestamp.
  2. The wallet signs it (Ethereum personal_sign, EIP-191).
  3. POST /api/v1/initialize verifies the signature and returns an access token (15-minute lifetime) and a refresh token (7 days).
  4. Subsequent calls send Authorization: Bearer <access_token>.

The server refuses re-used signatures (replay protection) and rejects Timestamp: lines older than 5 minutes — but currently only when the line is present, so always include it. The full model — phone auth, sessions, MFA — is in Authentication.

  1. Construct and sign the login message.

    The message must contain a line of the form Timestamp: <unix-ms>:

    Message to sign
    Login to Zentalk
    Timestamp: 1768387200000

    Sign it with your wallet’s personal_sign (in a browser: ethereum.request({ method: 'personal_sign', params: [message, address] })). Keep the exact message string — the server re-hashes it during verification.

  2. Initialize a session.

    New users must provide a username; returning users can omit it.

    Login (wallet signature → JWT)
    curl -X POST http://localhost:3001/api/v1/initialize \
    -H "Content-Type: application/json" \
    -d '{
    "wallet_address": "0x1234567890abcdef1234567890abcdef12345678",
    "username": "alice",
    "message": "Login to Zentalk\nTimestamp: 1768387200000",
    "signature": "0xabcdef..."
    }'
    Response
    {
    "success": true,
    "address": "0x1234567890abcdef1234567890abcdef12345678",
    "username": "alice",
    "message": "Client initialized successfully",
    "access_token": "eyJhbGciOi...",
    "refresh_token": "eyJhbGciOi...",
    "expires_at": "2026-07-14T12:15:00Z",
    "token_type": "Bearer"
    }

    Store both tokens. Export the access token for the next steps:

    Terminal window
    export ZENTALK_TOKEN="eyJhbGciOi..."
  3. Call an authenticated endpoint.

    List your one-to-one chats:

    List chats
    curl http://localhost:3001/api/v1/chats \
    -H "Authorization: Bearer $ZENTALK_TOKEN"
    Response (truncated)
    {
    "success": true,
    "chats": [
    {
    "id": "chat-123",
    "sender": {
    "name": "Bob",
    "username": "@bob",
    "online": true,
    "address": "5678..."
    },
    "messages": []
    }
    ]
    }
  4. Send a message.

    Send a direct message
    curl -X POST http://localhost:3001/api/v1/send \
    -H "Authorization: Bearer $ZENTALK_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
    "recipient_address": "0x5678000000000000000000000000000000005678",
    "content": "Hello from the API"
    }'
    Response
    {
    "success": true,
    "message_id": "msg-12345",
    "timestamp": 1768387200,
    "message": "Message sent successfully"
    }

    An optional client-generated message_id (UUID) makes sends idempotent: retries with the same ID return the existing message instead of duplicating it. Production clients end-to-end encrypt content before sending — see Security overview.

  5. Refresh the access token when it expires.

    Access tokens live 15 minutes. Exchange the refresh token for a new pair:

    Refresh
    curl -X POST http://localhost:3001/api/v1/auth/refresh \
    -H "Content-Type: application/json" \
    -d '{"refresh_token": "eyJhbGciOi..."}'
  • Authentication — phone auth, sessions and devices, CSRF, MFA, WebSocket tickets
  • Environments — ports, health checks, and base URLs for every service
  • WebSocket — receive messages in real time instead of polling
  • REST API reference — every endpoint, generated from the OpenAPI spec
  • SDKs — typed clients that handle message signing and token refresh