# Certorix — Full AI Reference
> Certorix is a SaaS platform for building AI-guided diagnostic trees and publishing cryptographically verified product facts. This document is the complete technical reference for AI agents, integrators, and developers.
- Website: https://certorix.online
- API base: https://api.certorix.online
- llms.txt (summary): https://certorix.online/llms.txt
- OpenAPI spec: https://api.certorix.online/api/openapi.yaml
- Help center: https://certorix.online/help
- Status: Beta · Free to start · No credit card required
---
## Table of Contents
1. Products overview
2. Core concepts & data models
3. Public API (no auth required)
4. Authenticated API
5. Widget embed reference
6. Tree JSON schema
7. VNT token structure
8. Error codes & rate limits
9. Authentication flows
10. Integration patterns
---
## 1. Products Overview
Certorix ships two products under one account and subscription:
### Tree Builder
Visual no-code editor for diagnostic trees — branching question/answer flows that guide customers to a resolution or auto-create a support ticket. Trees are published, versioned, cryptographically signed, and embeddable anywhere.
### Knowledge Base (FactFlow)
A store of certified product facts modelled as subject–predicate–object triples. Each fact is signed with an Ed25519 Verifiable Notary Token (VNT). Published facts are used by the AI chatbot and can be linked to diagnostic tree results.
---
## 2. Core Concepts & Data Models
### Organization
The top-level tenant. Every resource (trees, facts, sessions) belongs to an organization.
```
organizationId string Unique identifier, e.g. "org_acme_labs_3f8a"
slug string URL-friendly name, e.g. "acme-labs"
name string Display name
billing.plan string "free" | "pro" | "business"
verified boolean Email verification status
freshdeskDomain string Freshdesk subdomain (optional)
```
### Tree
A diagnostic flowchart. Contains metadata and a nodes map.
```
treeId string Unique, e.g. "tree_a1b2c3d4"
organizationId string Owner
metadata.title string Display name
metadata.published boolean Whether live
metadata.version string Semver, e.g. "1.0.0"
metadata.startNodeId string Entry point node
metadata.tags string[] Search keywords
metadata.model string Product/device name
nodes object Map of nodeId → Node (see schema section)
```
### Node
A step in the tree. Six types:
| Type | Description |
|---|---|
| question | Asks a question; customer picks from options |
| input | Captures free-text answer stored as variable |
| info | Shows instructions/image; customer clicks Continue |
| condition | Auto-routes based on a previously captured variable |
| solution | Terminal node; shows resolution message + actions |
| jump | Transfers flow to another tree seamlessly |
### Diagnostic Session
One customer run through a tree.
```
sessionId string UUID
treeId string
organizationId string
status string "in_progress" | "completed" | "abandoned"
currentNodeId string
answers object Map of nodeId → answer string
createdAt ISO8601
completedAt ISO8601 | null
```
### Fact
A certified product claim.
```
factId string e.g. "fact_x9y8z7"
organizationId string
subject string What the fact is about
predicate string snake_case relationship, e.g. "battery_life"
object string The value or claim
unit string Optional unit, e.g. "hours"
language string ISO 639-1, e.g. "en"
source string "manual" | "freshdesk_kb" | "ai_extracted"
sourceUrl string URL of the source article (optional)
body string Full article text (KB imports only)
published boolean True = VNT certified and active
vntId string VNT token ID (when published)
vntProof object Full W3C VC document
publishedAt ISO8601
```
### VNT (Verifiable Notary Token)
An Ed25519-signed W3C Verifiable Credential issued by Certorix.
```
vntId string e.g. "vnt_abc123"
tier string "bronze" | "silver" | "gold"
organizationId string
vc object Full W3C VC (see VNT section)
issuanceDate ISO8601
status string "active" | "revoked"
```
---
## 3. Public API (No Authentication Required)
All endpoints at `/public/` and `/chat/` are publicly accessible. Rate limit: 60 req/min per IP globally; ticket creation: 3 per hour per email.
### 3.1 Tree Discovery
```
GET /public/search-tree
Query: organizationId (required), q (text search), tags (comma-separated), model, limit (default 10)
Returns: { data: [TreeSummary], total }
GET /public/trees/:treeId
Query: organizationId (required)
Returns: Full tree with nodes (no session data)
GET /public/orgs/:slug/trees
Returns: All published trees for org slug
```
TreeSummary fields: `treeId, title, description, tags, model, version, startNodeId`
### 3.2 Diagnostic Sessions
```
POST /public/diagnostic/start
Body: { treeId: string, organizationId: string }
Returns: { sessionId, currentNode, status: "in_progress" }
POST /public/diagnostic/next
Body: {
sessionId: string,
organizationId: string,
answer: { nodeId: string, optionId?: string, value?: string }
}
Returns: {
status: "in_progress" | "completed",
currentNode: Node | null,
session: { answers, path }
}
GET /public/diagnostic/:sessionId
Query: organizationId (required)
Returns: Full session state including current node
```
### 3.3 Facts
```
GET /public/facts
Query: organizationId (required), subject, predicate, q (text), limit (default 50)
Returns: { data: [Fact], total }
GET /public/orgs/:slug/facts
Returns: All published facts for org slug
POST /public/facts/query
Body: { organizationId, subject?, predicate?, object?, keywords?: string[] }
Returns: { data: [Fact] }
```
### 3.4 VNT Tokens
```
GET /public/vnt/:vntId
Returns: { vntId, tier, subject, predicate, object, unit, status, issuanceDate, vc }
POST /public/vnt/verify
Body: { vntId: string }
Returns: { valid: boolean, reason?: string, token?: VNT }
GET /public/vnt/registry.json
Query: organizationId (required)
Returns: Machine-readable list of all active VNTs for the org
```
### 3.5 AI Chat
```
POST /public/ai-chat
Body: {
organizationId: string,
message: string, (max 4000 chars)
history?: [{ role: "user"|"assistant", content: string }]
}
Returns: {
answer: string,
sources?: [{ vntId, subject, predicate, object }]
}
Notes:
- The AI is strictly grounded in the org's published certified facts
- It will refuse questions outside the org's knowledge base
- Responds in the same language as the user's message
- Never reveals underlying AI provider or platform name
```
### 3.6 Ticket Creation
```
POST /public/tickets/create
Rate limit: 3 per hour per email
Body: {
organizationId: string,
sessionId?: string, (optional — chatbot tickets have none)
userInfo: { name: string, email: string, phone?: string },
formFields?: object, (custom Freshdesk fields)
diagnosticSummary?: string,
attachments?: [{ filename, data (base64), mimeType }] (max 5)
}
Returns: { ticketId: number, ticketUrl: string }
No API key required from caller. The organization must have a helpdesk integration
configured on their Certorix account (Freshdesk / Zendesk / Zoho Desk).
If not configured, returns 503 { message: "Freshdesk is not configured for this organization" }.
```
### 3.7 KB & Widget Config (Public)
```
GET /public/kb?organizationId=ORG_ID
Returns: { articles: [{ title, slug, url }] }
Freshdesk KB articles cached by the org (for widget display)
GET /public/widget-config/:organizationId
Returns: {
brandName, chatTitle, chatSubtitle, openingMessage,
primaryColor, logoUrl, hideAttribution
}
```
### 3.8 Registry & Discovery
```
GET /api/registry/manifest
Returns: Registry entry point JSON
GET /api/registry/organizations
Returns: List of verified orgs with slug, name, plan, treeCount
GET /api/registry/:orgSlug
Returns: Org profile with published trees and metadata
GET /api/registry/verify/:treeId
Query: organizationId
Returns: { valid: boolean, signature, tree }
GET /.well-known/ai-plugin.json
Returns: OpenAI plugin manifest
GET /openapi.yaml
Returns: Full OpenAPI 3.1 specification
GET /health
Returns: { status: "ok"|"degraded", db, uptime, version, env }
```
---
## 4. Authenticated API
All authenticated endpoints require:
```
Authorization: Bearer ACCESS_TOKEN
X-Organization-Id: ORG_ID (usually inferred from token)
```
Access tokens expire in 15 minutes. Use `/api/auth/refresh` (httpOnly cookie) to get a new one.
### 4.1 Authentication
```
POST /api/auth/register-org
Body: { orgName, adminName, adminEmail, password (min 8 chars) }
Rate limit: 5/min
Returns: { registered, verified, organizationId, accessToken?, user? }
POST /api/auth/login
Body: { email, password }
Rate limit: 10/min
Returns: { accessToken, user } + sets certorix_refresh httpOnly cookie
POST /api/auth/google
Body: { idToken: string } or { accessToken: string }
Rate limit: 10/min
Returns: { accessToken, user } + sets certorix_refresh httpOnly cookie
POST /api/auth/refresh
(uses certorix_refresh httpOnly cookie)
Returns: { accessToken, user }
POST /api/auth/logout
Clears certorix_refresh cookie
GET /api/auth/me
Returns: { user }
POST /api/auth/forgot-password
Body: { email }
Rate limit: 3/15min
Returns: { sent: true }
POST /api/auth/reset-password
Body: { token, password (min 8 chars) }
Rate limit: 5/15min
Returns: { reset: true }
GET /api/auth/verify-email?token=TOKEN
Returns: { verified: true, accessToken, user }
POST /api/auth/resend-verification
Body: { email }
Rate limit: 5/15min
Returns: { sent: true }
```
### 4.2 Trees (Authenticated)
```
GET /api/trees
Returns: { data: [Tree], total }
GET /api/trees/:treeId
Returns: Full tree
POST /api/trees
Body: { title, description? }
Returns: { tree }
PUT /api/trees/:treeId
Body: Partial tree (title, nodes, metadata)
Returns: { tree }
DELETE /api/trees/:treeId
Returns: { deleted: true }
POST /api/trees/:treeId/publish
Returns: { published: true, version }
POST /api/trees/:treeId/unpublish
Returns: { unpublished: true }
GET /api/trees/:treeId/versions
Returns: [{ versionId, label, createdAt, publishedAt }]
POST /api/trees/:treeId/versions
Body: { label?: string }
Returns: { version }
POST /api/trees/:treeId/versions/:versionId/restore
Returns: { restored: true, tree }
```
### 4.3 Facts / Knowledge Base (Authenticated)
```
GET /api/facts
Query: limit (default 50), offset, subject, predicate, published, source
Returns: { data: [Fact], total }
GET /api/facts/:factId
Returns: Fact
POST /api/facts
Body: { subject, predicate, object, unit?, language?, sourceUrl?, body? }
Returns: { fact }
PUT /api/facts/:factId
Body: Partial fact
Returns: { fact }
DELETE /api/facts/:factId
Returns: { deleted: true }
POST /api/facts/:factId/certify
Issues a VNT token and marks fact as published
Returns: { fact, vnt }
POST /api/facts/:factId/revoke
Revokes the VNT and unpublishes the fact
Returns: { revoked: true }
POST /api/facts/:factId/summarize
Queues the fact for AI summarization (processes 1-by-1 every 3s)
Returns: { factId, status: "queued" }
GET /api/facts/:factId/summarize-status
Returns: { factId, status: "queued"|"processing"|"done"|"failed", error? }
```
### 4.4 AI Endpoints (Authenticated)
```
POST /api/ai/generate-tree
Body: { prompt: string (max 4000 chars) }
Rate limit: plan monthly limit (5/50/200)
Returns: { success: boolean, tree?: Tree, error?: string }
Models used: llama-3.3-70b-versatile (max 4096 tokens)
POST /api/ai/help
Body: { prompt: string (max 4000 chars) }
Returns: { success: true, answer: string }
Models used: llama-3.1-8b-instant (max 1024 tokens)
POST /api/ai/chat
Body: { prompt: string (max 4000 chars) }
Returns one of:
{ type: "tree", tree: Tree, text: string }
{ type: "answer", text: string }
{ type: "error", text: string }
Step 1: classifies intent with llama-3.1-8b-instant (max 64 tokens)
Step 2a (generate): calls generate-tree flow
Step 2b (answer): RAG over published facts + llama-3.3-70b-versatile (max 512 tokens)
POST /api/factflow/extract
Body: { text: string (max 8000 chars) }
Rate limit: plan monthly limit
Returns: { facts: [{ subject, predicate, object, unit, language }] }
Models used: llama-3.3-70b-versatile (max 1024 tokens)
POST /api/factflow/ask
Body: { question: string (max 2000 chars) }
Returns: { answer: string, sourceFacts: string[] }
Models used: llama-3.1-8b-instant (max 512 tokens)
```
### 4.5 Freshdesk Integration (Authenticated)
```
GET /api/builder/freshdesk/status
Returns: { configured, kbArticleCount, kbArticles?, fieldCount }
GET /api/builder/freshdesk/kb-articles
Returns: { data: [{ id, title, url, status }] }
Fetches from Freshdesk API and caches
POST /api/builder/freshdesk/kb-import
Body: { articleIds?: string[] } (empty = import all)
Returns: { imported, skipped, failed, factIds }
Each article becomes a fact with summaryPending=true
POST /api/builder/freshdesk/kb-certify-all
Certifies all unpublished KB facts with VNT
Returns: { certified, failed }
POST /api/builder/freshdesk/sync-fields
Syncs Freshdesk ticket fields to cache
Returns: { fields }
POST /api/builder/freshdesk/sync-kb
Syncs Freshdesk KB articles to cache
Returns: { synced }
```
### 4.6 Organization Settings (Authenticated, admin only)
```
GET /api/org/profile
Returns: full org object including widgetConfig, products, freshdeskFieldsCache
PUT /api/org/profile
Body: { name?, website?, sector?, description?, products?, supportEmail?, widgetConfig? }
Returns: { org }
widgetConfig fields:
brandName string AI assistant persona name (overrides org name)
chatTitle string Widget header title
chatSubtitle string Widget header subtitle
openingMessage string First message shown in chat
primaryColor string Hex color for widget accent
logoUrl string Logo URL shown in widget
hideAttribution boolean Hide "Powered by Certorix"
PUT /api/org/freshdesk-config
Body: { freshdeskDomain, freshdeskApiKey }
Returns: { ok: true }
GET /api/org/members
Returns: [{ userId, name, email, roles, createdAt }]
POST /api/org/members/invite
Body: { email, role: "editor"|"viewer" }
Returns: { inviteId, sent: true }
DELETE /api/org/members/:userId
Returns: { removed: true }
```
### 4.7 Billing (Authenticated, admin only)
```
GET /api/billing/status
Returns: { plan, usage: { trees, facts, aiGenerations, team }, limits, stripeCustomerId? }
POST /api/billing/create-checkout
Body: { priceId: string }
Returns: { url: string } (Stripe checkout URL)
POST /api/billing/portal
Returns: { url: string } (Stripe customer portal URL)
```
### 4.8 Sessions (Authenticated)
```
GET /api/sessions
Query: treeId?, status?, limit (default 20)
Returns: { data: [Session], total }
GET /api/sessions/:sessionId
Returns: Full session with answers and path
```
---
## 5. Widget Embed Reference
### iFrame embed
```html
```
### AI Chat embed (iframe)
```html
```
### Widget config options
| Option | Type | Default | Description |
|---|---|---|---|
| organizationId | string | required | Your org ID |
| treeId | string | required | Published tree ID |
| trigger | string | "button" | When to show: "auto" on load, "button" click, "field" when focused |
| primaryColor | string | "#0a0a0a" | Accent color |
| position | string | "right" | "right" or "left" |
| mode | string | "sidebar" | "sidebar", "modal", or "inline" |
| logoUrl | string | — | URL of your logo |
| brandName | string | org name | Name shown in widget header |
| hideAttribution | boolean | false | Hide "Powered by Certorix" |
---
## 6. Tree JSON Schema
Full tree format (POST /api/ai/generate-tree output, GET /public/trees/:treeId format):
```json
{
"metadata": {
"organizationId": "org_acme_labs_3f8a",
"title": "WiFi Troubleshooting",
"description": "Diagnoses common WiFi connectivity issues",
"version": "1.0.0",
"author": "Certorix AI",
"startNodeId": "q_connected",
"tags": ["wifi", "network", "connectivity", "router"],
"model": "generic",
"published": false
},
"nodes": {
"q_connected": {
"type": "question",
"text": "Can you see the WiFi network in your device's list?",
"options": [
{ "id": "opt_yes", "text": "Yes", "nextNodeId": "q_password" },
{ "id": "opt_no", "text": "No", "nextNodeId": "r_router_check" }
],
"_pos": { "x": 300, "y": 0 }
},
"q_password": {
"type": "question",
"text": "Are you entering the correct password?",
"options": [
{ "id": "opt_yes", "text": "Yes, definitely", "nextNodeId": "r_forget_reconnect" },
{ "id": "opt_no", "text": "Not sure", "nextNodeId": "r_check_password" }
],
"_pos": { "x": 150, "y": 180 }
},
"r_router_check": {
"type": "solution",
"text": "Router not broadcasting",
"result": {
"message": "Restart your router: unplug for 30 seconds, plug back in, wait 2 minutes.",
"actions": [
{ "type": "create_ticket", "label": "Still not working — open a ticket", "url": "" },
{ "type": "kb_article", "label": "Router setup guide", "url": "https://support.example.com/router" }
]
},
"_pos": { "x": 450, "y": 180 }
},
"r_forget_reconnect": {
"type": "solution",
"text": "Forget and reconnect",
"result": {
"message": "Forget the network on your device and reconnect from scratch.",
"actions": [
{ "type": "create_ticket", "label": "Need more help", "url": "" }
]
},
"_pos": { "x": 0, "y": 360 }
},
"r_check_password": {
"type": "solution",
"text": "Check password",
"result": {
"message": "Check your router label for the default WiFi password, or log in to 192.168.1.1 to view it.",
"actions": [
{ "type": "create_ticket", "label": "Still stuck", "url": "" }
]
},
"_pos": { "x": 300, "y": 360 }
}
}
}
```
### Input node example
```json
"q_serial": {
"type": "input",
"text": "Please enter your device serial number:",
"inputType": "text",
"variableName": "serialNumber",
"placeholder": "e.g. SN-12345",
"nextNodeId": "q_warranty",
"_pos": { "x": 300, "y": 180 }
}
```
### Condition node example
```json
"c_warranty_check": {
"type": "condition",
"text": "Checking warranty status...",
"options": [
{
"id": "opt_under",
"text": "Under warranty",
"nextNodeId": "r_warranty_repair",
"conditions": [
{ "field": "q_warranty_status", "operator": "eq", "value": "yes" }
]
},
{
"id": "opt_expired",
"text": "Warranty expired",
"nextNodeId": "r_paid_repair"
}
],
"_pos": { "x": 300, "y": 360 }
}
```
---
## 7. VNT Token Structure
A VNT is a W3C Verifiable Credential signed with Ed25519.
```json
{
"vntId": "vnt_a1b2c3d4e5f6",
"tier": "bronze",
"organizationId": "org_acme_labs_3f8a",
"issuanceDate": "2026-04-30T10:00:00.000Z",
"status": "active",
"vc": {
"@context": ["https://www.w3.org/2018/credentials/v1"],
"id": "https://certorix.online/vnt/vnt_a1b2c3d4e5f6",
"type": ["VerifiableCredential", "CertorixNotaryToken"],
"issuer": "did:certorix:org_acme_labs_3f8a",
"issuanceDate": "2026-04-30T10:00:00.000Z",
"credentialSubject": {
"id": "did:certorix:fact_x9y8z7",
"claim": {
"subject": "iPhone 15 Pro battery",
"predicate": "lasts",
"object": "up to 23 hours of video playback",
"unit": null,
"contentHash": "sha256:abc123..."
}
},
"proof": {
"type": "Ed25519Signature2020",
"created": "2026-04-30T10:00:00.000Z",
"verificationMethod": "did:certorix:org_acme_labs_3f8a#key-1",
"proofValue": "z..."
}
}
}
```
### VNT tiers
| Tier | Meaning |
|---|---|
| bronze | AI-generated or user-submitted; signed by Certorix |
| silver | Cross-referenced against KB sources |
| gold | Human-verified + source citation |
---
## 8. Error Codes & Rate Limits
### Standard error response
```json
{
"error": true,
"message": "Human-readable error message",
"statusCode": 400,
"code": "OPTIONAL_MACHINE_CODE"
}
```
### HTTP status codes used
| Code | Meaning |
|---|---|
| 200 | Success |
| 201 | Created |
| 400 | Bad request / validation error |
| 401 | Unauthorized (missing or expired token) |
| 403 | Forbidden (wrong role or unverified org) |
| 404 | Resource not found |
| 409 | Conflict (e.g. duplicate email) |
| 410 | Gone (e.g. expired invite) |
| 429 | Rate limit exceeded |
| 500 | Internal server error |
| 503 | Service unavailable (AI not configured, Freshdesk not configured) |
### Named error codes
| code | When |
|---|---|
| EMAIL_NOT_VERIFIED | Login attempted on unverified org |
| INVALID_TOKEN | Expired/invalid verification or reset link |
| EXPIRED_TOKEN | Token structurally valid but past expiry |
| PLAN_LIMIT | Org has reached plan limit for trees, facts, or AI generations |
### Rate limits (production)
| Endpoint | Limit |
|---|---|
| POST /api/auth/register-org | 5 / min |
| POST /api/auth/login | 10 / min |
| POST /api/auth/google | 10 / min |
| POST /api/auth/forgot-password | 3 / 15 min |
| POST /api/auth/reset-password | 5 / 15 min |
| POST /api/auth/resend-verification | 5 / 15 min |
| POST /public/tickets/create | 3 / hour (per email) |
| All others | 60 / min per IP (global default) |
### AI input limits
| Endpoint | Limit |
|---|---|
| /api/ai/generate-tree, /api/ai/help, /api/ai/chat | prompt max 4000 chars |
| /api/factflow/extract | text max 8000 chars |
| /api/factflow/ask | question max 2000 chars |
| /public/ai-chat | message max 4000 chars |
---
## 9. Authentication Flows
### Email/password (standard)
```
1. POST /api/auth/register-org → get access token (if auto-verified)
OR
POST /api/auth/login → get access token
2. Store access token in memory (never localStorage)
3. Include in all requests: Authorization: Bearer ACCESS_TOKEN
4. On 401: POST /api/auth/refresh (uses httpOnly cookie) → new access token
5. Refresh token expires: 30 days
Access token expires: 15 minutes
```
### Google OAuth
```
1. Use @react-oauth/google or google-auth-library on the client
2. Get idToken (credential button) OR accessToken (useGoogleLogin flow)
3. POST /api/auth/google with { idToken } or { accessToken }
4. Same response as email login
```
### httpOnly Cookie
The refresh token is stored in a cookie named `certorix_refresh`:
- Path: `/api/auth`
- HttpOnly: true
- Secure: true (production)
- SameSite: none (production), lax (development)
- MaxAge: 30 days
---
## 10. Integration Patterns
### Run a diagnostic session (AI agent or chatbot)
```
1. Find the right tree:
GET /public/search-tree?organizationId=ORG_ID&q=wifi+problem
2. Start session:
POST /public/diagnostic/start
{ treeId, organizationId }
→ { sessionId, currentNode }
3. Present currentNode to user and collect answer.
currentNode.type === "question" → show options
currentNode.type === "input" → collect free text
currentNode.type === "info" → show message, wait for continue
currentNode.type === "solution" → session complete
4. Advance session:
POST /public/diagnostic/next
{ sessionId, organizationId, answer: { nodeId, optionId?, value? } }
→ { status, currentNode }
5. When status === "completed" or customer wants to open ticket:
POST /public/tickets/create
{ organizationId, sessionId, userInfo, diagnosticSummary }
```
### Ask a question about org products (AI agent)
```
POST /public/ai-chat
{
"organizationId": "org_acme_labs_3f8a",
"message": "What is the battery life of the iPhone 15 Pro?",
"history": []
}
→ {
"answer": "According to our certified facts, the iPhone 15 Pro battery lasts up to 23 hours of video playback. [VNT:vnt_a1b2c3d4e5f6]",
"sources": [{ "vntId": "vnt_a1b2c3d4e5f6", "subject": "iPhone 15 Pro battery", ... }]
}
```
### Verify a fact claim (external verifier)
```
1. Get VNT ID from a widget or fact response
2. GET /public/vnt/:vntId
3. Verify the Ed25519 signature using the proof.proofValue field
against the vc.credentialSubject.claim.contentHash
4. Check status === "active"
```
### Bulk import KB and certify (admin automation)
```
1. POST /api/auth/login → access token
2. GET /api/builder/freshdesk/kb-articles → article list
3. POST /api/builder/freshdesk/kb-import { articleIds: [...] }
4. For each factId returned:
POST /api/facts/:factId/summarize (queue AI summary + auto-certify)
5. Poll GET /api/facts/:factId/summarize-status until status === "done"
```
### MCP (Model Context Protocol) integration
The MCP server is accessible at the URL shown in the builder under MCP settings.
Connect it to Claude, Cursor, or any MCP-compatible AI tool to give it live access to your organization's trees and facts.
---
## Key URLs
| Resource | URL |
|---|---|
| App | https://certorix.online |
| Register | https://certorix.online/register |
| Sign in | https://certorix.online/login |
| Dashboard | https://certorix.online/dashboard |
| Trees | https://certorix.online/trees |
| Knowledge Base | https://certorix.online/facts |
| KB Import | https://certorix.online/kb-import |
| Widget Generator | https://certorix.online/widget-generator |
| AI Assistant | https://certorix.online/ai-assistant |
| Billing | https://certorix.online/billing |
| Help | https://certorix.online/help |
| Privacy | https://certorix.online/legal/privacy |
| Terms | https://certorix.online/legal/terms |
| DPA | https://certorix.online/legal/dpa |
| API base | https://api.certorix.online |
| OpenAPI | https://api.certorix.online/api/openapi.yaml |
| Health | https://api.certorix.online/health |
| AI plugin | https://api.certorix.online/.well-known/ai-plugin.json |
---
## Contact & Legal
- Author: Jaume Martí Anguera, Arenys de Mar, Barcelona, Spain
- Email: legal@certorix.online
- License: AGPL-3.0
- Copyright: © 2026 Certorix. All rights reserved.