ASK-Ai API · v0.1.0 Surface

Verbose inventory of every public route in git.askapi.ca (GitDrive) and mail.askapi.ca (SmartMail).

This page is the source-of-truth for what the public API exposes today. Each row notes the auth model, the forensic audit event the route emits (when relevant), and the ezToken cost (for billable actions). Routes marked stub return 501 and are reserved for v0.2.

Shared concepts

Authentication

ModeUse caseHeader
Bearer JWTExternal agents, partner integrations, headless toolsAuthorization: Bearer <jwt> — RS256, validated against Authentik JWKS at https://login.ask-ai.ca/application/o/<app>/jwks/
Forward-authInternal UI calls (same-origin git.askmail.ca/v1/*, mail.askmail.ca/api/v1/*)x-authentik-username + x-authentik-uid + x-authentik-groups injected by traefik
Webhook secretInternal/system calls (Forgejo push, backup heartbeat)X-Gitcloud-Secret: <shared> or matching Authorization
Public/boot/*, /health, /metrics, /share/{id}None

ezTokens

Billable actions are denominated in ezTokens (1 token = 0.0001 CAD). The token is deducted via ASK-Ledger before the action runs; on failure the deduction is refunded automatically. Bundles purchased via POST /v1/tokens/purchase (CIBCx checkout). Balance: GET /v1/tokens/balance.

Error codes

CodeMeaning
401Missing or invalid auth (Bearer JWT fails signature/issuer/audience/expiry, or no forward-auth headers)
402Insufficient ezToken balance — body includes balance + required
403Tenant mismatch (token scope ≠ resource owner) or share-link forbidden
404Resource not found, or share-link expired/revoked
429Rate limit hit — body has Retry-After seconds
501Stub endpoint reserved for v0.2 (CI, code review LLM, RAPTOR, backup snapshots)
502/503Upstream service unavailable (Forgejo, RustFS, Milvus, RuVector, Ledger)

git.askapi.ca — GitDrive

Boot & health

MethodPathAuthAudit eventPurpose
GET/bootpublicv0.2.0 addon descriptor with capability-group pointers
GET/boot/{auth,billing,code,media,packages,search,webhooks,infra}publicPer-capability contract docs
GET/healthpublicLiveness (200 always when up)
GET/health/fullpublicDeep probe: SurrealDB, Milvus, RuVector, RustFS, Ledger + backup freshness
GET/metricspublic LANPrometheus exposition format — scraped by CT 700 MIG-Observability

Identity

MethodPathAuthAudit eventPurpose
GET/v1/meBearer/ForwardEcho caller's auth context (uid, email, username, tenant, groups)
DELETE/v1/meBearer/Forwardaudit.account.erasedRight-to-erasure (PIPEDA/GDPR): cascades Forgejo repos, SurrealDB rows, Milvus/RuVector collections, RustFS objects. Keeps Ledger txns (CRA 7y rule), Authentik user, ASK-Mail mailbox.

Code (Forgejo-backed)

MethodPathAuthAudit eventCost / notes
GET/v1/code/reposBearer/ForwardList user's repos
POST/v1/code/reposBearer/Forwardaudit.repo.createdPRICE_CODE_REPOS_CREATE JIT-provision Forgejo user, register ingest webhook
GET/v1/code/repos/{owner}/{repo}/contents/{path+}Bearer/ForwardRead file at default branch or ?ref=sha
POSTPUT/v1/code/repos/{owner}/{repo}/contents/{path+}Bearer/Forwardaudit.contents.writtenPRICE_CODE_CONTENTS_WRITE POST=create, PUT=update (sha required)
GET/v1/code/repos/{owner}/{repo}/commitsBearer/ForwardFilter by since / path / author
GET/v1/code/repos/{owner}/{repo}/diff/{base}...{head}Bearer/ForwardUnified diff + files-changed summary
GET/v1/code/repos/{owner}/{repo}/aboutBearer/ForwardPRICE_CODE_REPOS_ABOUT Semantic metadata (description, topics, entities) from ingest pipeline

Media (RustFS S3)

MethodPathAuthAudit eventCost / notes
GET/v1/media/{tenant}/{user}/{path+}Bearer/Forward302 → presigned RustFS GET URL (1hr TTL)
PUT/v1/media/{tenant}/{user}/{path+}Bearer/Forwardaudit.media.uploadedmax(PRICE_MEDIA_UPLOAD_MIN, ceil(MB) × PRICE_MEDIA_UPLOAD_PER_MB) 60/min rate limit
DELETE/v1/media/{tenant}/{user}/{path+}Bearer/Forwardaudit.media.deleted

Sharing

MethodPathAuthAudit eventNotes
POST/v1/media/shareBearer/Forwardaudit.share.created10/min rate limit; configurable expiry (max 10y)
GET/v1/sharesBearer/ForwardList own share-links
DELETE/v1/shares/{share_id}Bearer/Forwardaudit.share.revokedRevoke share-link
GET/share/{share_id}publicPublic 302 → RustFS presigned (15 min TTL)

Search

MethodPathAuthCost / notes
POST/v1/search/codeBearer/ForwardPRICE_SEARCH_CODE Forgejo repo-name search; 60/min
POST/v1/search/semanticBearer/ForwardPRICE_SEARCH_SEMANTIC Hybrid Milvus dense (BGE-M3 1024-d) + RuVector text via RRF
POST/v1/search/unifiedBearer/ForwardGitDrive + SmartMail cross-product search
POST/v1/search/raptorBearer/Forwardstub 501 — RAPTOR multi-level summaries reserved for v0.2

Tokens & billing

MethodPathAuthAudit eventNotes
GET/v1/tokens/balanceBearer/ForwardCaller's ezToken balance from ASK-Ledger
GET/v1/tokens/bundlesBearer/ForwardProxy ASK-Axum-Pay bundle catalog
POST/v1/tokens/purchaseBearer/Forwardaudit.purchase.initiated5/min rate limit; returns CIBCx checkout URL
GET/v1/tokens/usageBearer/ForwardProxy ASK-Ledger transaction history

Packages (multi-format registry via Forgejo)

MethodPathAuthNotes
GET/v1/packages/{owner}Bearer/ForwardList all packages owned by {owner}
GET/v1/packages/{owner}/{type}/{name}Bearer/ForwardList versions
GET/v1/packages/{owner}/{type}/{name}/{version}Bearer/ForwardGet package metadata
DELETE/v1/packages/{owner}/{type}/{name}/{version}Bearer/ForwardDelete version

Publishing uses native package-manager clients against Forgejo directly: npm set registry https://git.askmail.ca/api/packages/{owner}/npm/, pip install --index-url https://git.askmail.ca/api/packages/{owner}/pypi/simple/ ..., docker push git.askmail.ca/{owner}/{image}:{tag}. Git LFS at git.askmail.ca/{owner}/{repo}.git/info/lfs (RustFS bucket gitcloud-lfs).

Webhooks (outbound)

MethodPathAuthAudit eventCost
GET/v1/webhooks/{owner}/{repo}Bearer/Forward
POST/v1/webhooks/{owner}/{repo}Bearer/Forwardaudit.webhook.createdPRICE_WEBHOOK_REGISTER
DELETE/v1/webhooks/{owner}/{repo}/{hook_id}Bearer/Forwardaudit.webhook.deleted

Audit

MethodPathAuthNotes
GET/v1/audit/run/{run_id}Bearer/ForwardFetch ingest run + all pipeline events (extract / classify / embed / raptor)

Internal & legacy

MethodPathAuthNotes
POST/internal/ingest/commitwebhook secretForgejo push webhook → Pulsar topic gitcloud-ingest
GET/internal/content/{hash}noneLRU-trimmed chunk cache for STier crawl
POST/internal/backup/heartbeatwebhook secretBackup script heartbeat → SurrealDB backup_heartbeat:{source}
GET/v1/repos, /v1/files/{path}, /v1/commitBearer/ForwardLegacy aliases — proxy to canonical paths (ASK-Mail compat)

Stubs (501, reserved v0.2)

PathWill deliver
/v1/ci/repos/{owner}/{repo}/runs · /v1/ci/runs/{run_id} · /v1/ci/runs/{run_id}/logsCI runner integration
/v1/backup/{tenant}/{user}/snapshots · /v1/backup/.../restorePer-tenant snapshot/restore
/v1/review/llmCode review LLM

mail.askapi.ca — SmartMail

Boot & health

MethodPathAuthPurpose
GET/bootpublicSelf-describing addon contract — 13 capabilities
GET/healthpublicLiveness
GET/metricspublic LANPrometheus exposition

Mail (WildDuck-backed)

MethodPathAuthAudit eventNotes
GET/api/v1/meBearer/ForwardCaller identity
GET/api/v1/me/addressesBearer/ForwardList user's email addresses
GET/api/v1/mailboxesBearer/ForwardIMAP folder list
GET/api/v1/mailboxes/{mb}/messages?page=&pageSize=Bearer/ForwardPage through messages (max 100)
GET/api/v1/mailboxes/{mb}/messages/{id}Bearer/Forwardaudit.mail.readMarks seen, normalizes HTML
PUT/api/v1/mailboxes/{mb}/messages/{id}/flagsBearer/ForwardToggle seen / flagged
DELETE/api/v1/mailboxes/{mb}/messages/{id}Bearer/Forwardaudit.mail.deleted
POST/api/v1/messages/submitBearer/Forwardaudit.mail.sentResolves sender's primary address; posts to WildDuck submit
POST/api/v1/searchBearer/ForwardBM25 full-text via RuVector
POST/api/v1/ingest/emailBearer/Forwardaudit.mail.received1 ezToken/email Full pipeline: TimescaleDB INSERT → STier signals → SurrealDB+TimescaleDB write → BGE-M3 embed → RuVector upsert → Ledger charge → usage event
POST/api/v1/ingest/batchBearer/Forwardper-email audit.mail.receivedLoops ingest_email; returns array of {ok, result|error}

AI

MethodPathAuthAudit eventNotes
POST/api/v1/chatBearer/Forwardaudit.ai.chatRAG pipeline: RuVector recall → ai_prefs filter → EvolveRouter (basic→chat / analysis→thinking)
POST/api/v1/ai/chatBearer/Forwardaudit.ai.chatSession-aware variant; persists to SurrealDB chat_session_msg
GET/api/v1/ai/prefsBearer/ForwardList per-folder AI privacy
PUT/api/v1/ai/prefs/{folder}Bearer/Forwardaudit.ai.pref_changedSet folder enabled/disabled
DELETE/api/v1/ai/prefs/{folder}Bearer/Forwardaudit.ai.pref_changedReset to default (enabled)
POST/api/v1/vectors/ensure_collectioninternalMilvus mail_{username} create
POST/api/v1/vectors/indexinternalPre-computed embedding upsert
POST/api/v1/vectors/searchinternalCOSINE ANN

Domains & tenancy

MethodPathAuthAudit eventNotes
POST/api/v1/admin/tenantsBearer (admin)audit.tenant.createdTenant record
GET/api/v1/admin/tenants/{id}Bearer (admin)
GET/api/v1/domainsBearer/Forward (tenant-scoped)
POST/api/v1/domainsBearer (admin)audit.domain.registeredWildDuck dominalias + DKIM selector
POST/api/v1/domains/{fqdn}/verifyBearer (admin)audit.domain.verifiedDNS TXT lookup (deferred — currently sets verified=true; trust-dns-resolver wiring is v0.2)
GET/api/v1/domains/{fqdn}/usersBearer/ForwardList users on domain
POST/api/v1/domains/{fqdn}/usersBearer (admin)audit.user.createdWildDuck user create

Storage proxy (to GitDrive)

MethodPathAuthNotes
GETPOSTPUTDELETE/api/v1/storage/repos · /api/v1/storage/files/{path} · /api/v1/storage/commitBearer/ForwardForwards Authentik headers to gitcloud-api; tier gating enforced upstream

Internal

MethodPathAuthNotes
GET/internal/email/{email_id}/bodyLAN-only5-min TTL cache; serves email body to STier crawl

Observability

EndpointWhat
/healthLiveness — 200 if process up. Both APIs.
/health/full(GitDrive only) Deep dependency probe. 503 if SurrealDB / RustFS / RuVector / Ledger / backups unhealthy.
/metricsPrometheus text exposition. Scraped by CT 700 MIG-Observability. Counters: http_requests_total{route,status}, auth_failures_total, ledger_deductions_total{reason}, ledger_failures_total{reason}, audit_events_total{kind}.
journald JSONtracing-subscriber emits structured records. Promtail ships to Loki. Critical events marked event=audit.*.

Forensic event taxonomy (current)

EventEmitted byFields
audit.auth.failedboth APIs · auth.rs::from_bearer when JWT invalidreason=bearer_invalid
audit.ledger.deductedgitcloud-api · ledger.rs::deduct on 200actor, tokens, reason, balance
audit.ledger.insufficientgitcloud-api · ledger.rs::deduct on 402actor, tokens, reason
audit.mail.receivedask-mail-api · ingest.rs::ingest_emailactor, email_id, from, signal_count, tokens_charged

More audit events to be wired before v0.1.0 tag: audit.repo.created, audit.contents.written, audit.media.uploaded, audit.media.deleted, audit.share.created, audit.share.revoked, audit.account.erased, audit.mail.sent, audit.mail.deleted, audit.domain.registered, audit.user.created, audit.tenant.created, audit.ai.chat, audit.ai.pref_changed.

External dependencies

gitcloud-api (CT 235 .235:8700)

ServiceCTUsed by
Forgejo228 (.121:3000)repos, contents, commits, packages, code search, account-erasure
RustFS232 (.232:9000)media get/put/delete, share-link redirect
SurrealDB (canonical)230 (.230:8000)indexed_chunk, raptor_node, ingest_run, ingest_event, media_share, backup_heartbeat
BGE-M3 embed100 (.100:8097)semantic_search, ingest worker
RuVector (text)231 (.229:8102)semantic_search, ingest worker, account-erasure
Milvus (dense)307 (.228:19530)semantic_search, ingest worker, account-erasure
STier131 (.18:8300)ingest classify (signal extraction)
ASK-Ledger251 (.251:8092)deduct / refund / balance / usage
ASK-Axum-Pay252 (.252:8093)token bundle catalog
CIBCxexternalcheckout URL (proxy only)
Pulsar306 (.157:8080)gitcloud-ingest topic (durable, Shared sub)
Authentik (JWKS)719 (login.ask-ai.ca)JWT validation (1hr cache)

ask-mail-api (CT 730 .231:3000)

ServiceCTUsed by
WildDuck (IMAP)730 (localhost:8080)mailboxes, messages, submit, addresses, domain users
SurrealDB731 (.233:8000)tenant, domain, email_signal, ai_prefs, chat_session_msg, user_plan
TimescaleDB / Postgres736 (.168:5432)email, contact, email_signal_ts hypertables (7y retention, 3mo compression)
RuVector (BM25)735 (.164:8102)per-user mail search index
Milvus734 (.234:19530)vector index (BGE-M3 1024-d HNSW)
RustFS732 (.240:9000)email attachments + archives
STier131 (.18:8300)signal extraction during ingest
BGE-M3 embed100 (.100:8097)email body embedding
EvolveRouter100 (.100:8091)RAG chat completion
ASK-Ledger251 (.251:8092)1-token-per-email charge
Authentik (JWKS)719 (login.ask-ai.ca)JWT validation
GitDrive API235 (.235:8700)storage proxy (tier-gated upstream)

Changelog