ASK-Ai API v1

Public API surface for agents, integrations, and partner tools — backed by Authentik OAuth2 + RS256 JWT.

What lives here

git.askapi.ca/v1/*

GitDrive — repositories, files, packages, search, sharing. Forgejo-backed git protocol on the same host paths under /{owner}/{repo}.git.

mail.askapi.ca/v1/*

SmartMail — mailboxes, messages, threads, contacts, ingest webhooks, search, AI assistance.

Internal product UIs (git.askmail.ca, mail.askmail.ca) call their own backends same-origin under /v1/* with cookie auth — those endpoints are NOT for external consumption. The askapi.ca surfaces are stable, versioned, and bearer-authenticated.

Authentication — OAuth2 client_credentials

For server-to-server agents and headless tools. Get a JWT, send it as Authorization: Bearer … on every request.

  1. Register an OAuth2 application in Authentik at login.ask-ai.ca (admin-only). Capture client_id + client_secret.
  2. POST to the token endpoint with grant_type=client_credentials.
  3. Authentik returns an access_token (JWT, RS256-signed) valid for ~60min.
  4. Send Authorization: Bearer <access_token> on every API call.
  5. Refresh before expiry by repeating step 2.

Get a token

curl -X POST https://login.ask-ai.ca/application/o/token/ \
  -d grant_type=client_credentials \
  -d client_id=YOUR_CLIENT_ID \
  -d client_secret=YOUR_CLIENT_SECRET \
  -d scope=openid

# Response: {"access_token":"eyJhbGc...","token_type":"bearer","expires_in":3600}

Call the API

curl -H "Authorization: Bearer $TOKEN" https://git.askapi.ca/v1/me
curl -H "Authorization: Bearer $TOKEN" https://mail.askapi.ca/v1/mailboxes

Python (requests)

import requests
tok = requests.post(
    "https://login.ask-ai.ca/application/o/token/",
    data={"grant_type": "client_credentials",
          "client_id": "YOUR_ID", "client_secret": "YOUR_SECRET",
          "scope": "openid"}
).json()["access_token"]

r = requests.get("https://git.askapi.ca/v1/me",
                 headers={"Authorization": f"Bearer {tok}"})
print(r.json())

Browser SPAs (PKCE)

For browser apps that aren't same-origin with the API, use OAuth2 Authorization Code with PKCE. The mig-auth.js v2 SDK implements this — see MIGAuth.initOIDC() + MIGAuth.apiFetch().

Token claims

Tokens are RS256-signed JWTs. Validation: signature against https://login.ask-ai.ca/application/o/<app-slug>/jwks/; issuer matches; audience matches your client_id; expiry valid.

{
  "iss": "https://login.ask-ai.ca/application/o/<app>/",
  "sub": "<user-or-service-uid>",
  "aud": "<client_id>",
  "email": "...",
  "preferred_username": "...",
  "groups": ["..."],
  "exp": 1777254387,
  "iat": 1777250787
}

Errors

CodeMeaning
401Missing, malformed, expired, or signature-invalid token.
403Token valid but missing required scope or group.
404Resource not found. Path-typo or you don't own it.
429Rate-limited. Back off.