Authentication

Kanvas has two distinct API keys that serve different purposes. Understanding the difference is critical.

Two Keys, Two Roles

FieldTypeDescription
X-Kanvas-KeyStringSuper admin key — full access, no login required. Use for server-to-server and agent operations.
X-Kanvas-AppStringApplication key — identifies your app. Requires a Bearer token from login/register for user context.
AuthorizationBearer tokenJWT token from login/register — only needed with X-Kanvas-App to identify the user.
Content-Typeapplication/jsonAlways required for GraphQL requests.

Option 1: Super Admin Key (X-Kanvas-Key)

The X-Kanvas-Key is the super admin key. It grants full access to the API without requiring a login or Bearer token. This is ideal for AI agents, server-to-server integrations, and automated systems that need to operate without a user session.

curl -X POST https://your-kanvas-api-url/graphql \
  -H "Content-Type: application/json" \
  -H "X-Kanvas-Key: your-super-admin-key" \
  -d '{"query": "{ me { id displayname email } }"}'

No Authorization header needed. The key itself authenticates and authorizes the request.

Option 2: App Key + Bearer Token (X-Kanvas-App)

The X-Kanvas-App is the application key. It identifies your app but does not grant access on its own. You need to pair it with a Bearer token from a user login or registration. This is ideal for frontend apps, user-facing interfaces, and multi-user systems where each request runs in a user's context.

curl -X POST https://your-kanvas-api-url/graphql \
  -H "Content-Type: application/json" \
  -H "X-Kanvas-App: your-app-key" \
  -H "Authorization: Bearer your-jwt-token" \
  -d '{"query": "{ me { id displayname email } }"}'

When to Use Which

Use CaseHeaderBearer Token
AI agent / automationX-Kanvas-KeyNot required
Server-to-server integrationX-Kanvas-KeyNot required
Frontend app (user-facing)X-Kanvas-AppRequired (from login)
Multi-user admin panelX-Kanvas-AppRequired (from login)

Register a User

Only needed when using X-Kanvas-App flow:

mutation {
  register(data: {
    displayname: "My Agent"
    email: "agent@example.com"
    password: "secure-password"
    password_confirmation: "secure-password"
  }) {
    token
    user {
      id
      uuid
      displayname
      email
      default_company
      default_company_branch
    }
  }
}

The token returned is your JWT Bearer token. Include it in subsequent requests as Authorization: Bearer <token>.

Login

mutation {
  login(data: {
    email: "agent@example.com"
    password: "secure-password"
  }) {
    token
    user {
      id
      displayname
      default_company
      default_company_branch
    }
  }
}

Refresh Token

mutation {
  refreshToken {
    token
  }
}

Verify Your Credentials

# Works with either key approach
query {
  me {
    id
    uuid
    displayname
    email
    default_company
    default_company_branch
    roles { name }
  }
}

Password Reset

# Request reset email
mutation {
  forgotPassword(data: { email: "agent@example.com" })
}

# Reset with token from email
mutation {
  resetPassword(data: {
    token: "reset-token-from-email"
    email: "agent@example.com"
    password: "new-password"
    password_confirmation: "new-password"
  })
}