AI GO System Integration Guide
This document comprehensively explains how third-party applications (Integrations) can connect to the AI GO system via "References" and APIs, covering all referencable API Endpoints, Tables, Custom Tables (dynamic data tables), Schemas, and field definitions.
1. System Overview and Architecture
1.1 System Positioning
AI GO is an enterprise-grade PaaS ERP platform offering comprehensive modules for Accounting, Sales, Procurement, Inventory, CRM, HR, MRP, Project Management, etc. Through the Integration mechanism, third-party developers can build Self-Built Apps to securely access enterprise data within AI GO.
1.2 Three Application Access Modes
| Feature | Internal | External | Self-Built |
|---|---|---|---|
| Use Case | Internal organizational tools | Customer/Supplier facing apps | Independent third-party system integrations |
| Authentication | Supabase Auth JWT | Custom App Auth | API Key |
| Code Hosting | AI GO Builder | AI GO Builder | Third-party self-hosted |
| Data Access | Internal Proxy | External Proxy | Open Proxy |
| Reference requires publishing | No (immediate effect) | No (immediate effect) | Yes (requires publishing snapshot) |
access_mode | internal | external | self_built |
This document focuses on the Self-Built mode, which is the core use case for third-party integrations.
1.3 Overall Architecture Flow
sequenceDiagram
participant Dev as Developer (Admin)
participant AIGO as AI GO API
participant App as Third-Party App
Note over Dev,App: === Stage 1: Create Integration ===
Dev->>AIGO: POST /integrations (Create Self-Built App)
AIGO-->>Dev: Returns app_id, slug
Dev->>AIGO: POST /integrations/{app_id}/api-keys (Generate API Key)
AIGO-->>Dev: Returns sk_live_xxx... (Once only)
Note over Dev,App: === Stage 2A: Configure System Table References ===
Dev->>AIGO: GET /refs/available-tables (Check available tables)
Dev->>AIGO: GET /refs/tables/{name}/columns (Check fields)
Dev->>AIGO: POST /refs/apps/{app_id} (Create reference + set permissions)
Note over Dev,App: === Stage 2B: Create Custom Table ===
Dev->>AIGO: Create Custom Table and fields via AI GO Admin UI
Note over Dev,App: === Stage 3: Publish ===
Dev->>AIGO: POST /integrations/{app_id}/publish (Publish reference config)
AIGO-->>Dev: Snapshots columns + permissions as published version
Note over Dev,App: === Stage 4: Access Data ===
App->>AIGO: GET /open/proxy/{table} (System tables)
AIGO-->>App: Returns data for authorized fields (tenant isolated)
App->>AIGO: GET /open/data/objects/{slug}/records (Custom Table)
AIGO-->>App: Returns Custom Table records (tenant isolated)
2. Authentication Mechanisms
2.1 API Key Server-to-Server Authentication
Ideal for backend-to-backend communication for Self-Built applications.
API Key Format: sk_live_ + 64-character hexadecimal random string
Usage: Include it in the Header of every HTTP request:
X-API-Key: sk_live_a1b2c3d4e5f6...
Validation Flow:
The system automatically validates the API Key and its associated application, extracting the app_id and tenant_id without requiring them to be passed manually. Invalid or revoked keys return 401 Unauthorized.
Security Recommendations:
- The API Key is only returned as plaintext once upon creation. Keep it secure.
- Store the Key in environment variables or a secret management service; do not hardcode it.
- Rotate Keys regularly (revoke old Key ??create new Key).
- A single integration can have multiple Keys (e.g., separating Production and Staging).
2.2 Custom App User Authentication
The AI GO platform provides a complete, independent user authentication system for self-built integrations, including:
- Email + Password: Registration / Login
- OAuth Third-Party Login: LINE, Google, Facebook, etc. (See 禮2.4)
- JWT Access Token + Refresh Token Rotation
- Builder-side User Management: Enable / Disable / Delete
Important: In Independent mode, third-party developers do not need to build their own authentication system. AI GO provides ready-to-use Auth APIs; developers simply call these endpoints to achieve complete user registration and login functionalities for their apps.
2.3.1 Authentication Flow Overview
sequenceDiagram
participant User as End User
participant App as Third-Party Frontend
participant AIGO as AI GO API
alt Email + Password
User->>App: Fill registration / login form
App->>AIGO: POST /custom-app-auth/{slug}/register or login
AIGO-->>App: { access_token, refresh_token, user }
else OAuth Login (e.g., LINE)
User->>App: Click LINE login
App->>AIGO: GET /custom-app-oauth/{slug}/line/authorize
AIGO-->>User: 302 Redirect to LINE authorization page
User->>AIGO: Authorization callback
AIGO-->>App: 302 redirect?oauth_token=<base64 encoded tokens>
end
Note over App: Store access_token + refresh_token
App->>AIGO: GET /custom-app-auth/{slug}/me (Bearer Token)
AIGO-->>App: { user info }
Note over App: When Token is about to expire
App->>AIGO: POST /custom-app-auth/{slug}/refresh
AIGO-->>App: { new access_token, new refresh_token }
Path Note: All Custom App User authentication endpoints use
app_slug(notapp_id) as the path parameter. Theslugcan be found next to the title on the integration details page (a 12-character hex string). The system also supports usingsubdomaininstead ofslug.
2.3.2 Register
POST /api/v1/custom-app-auth/{app_slug}/register
Auth: No Auth Required (Public Endpoint)
Request Body:
{
"email": "user@example.com",
"password": "my_secure_password",
"display_name": "John Doe"
}
| Field | Type | Required | Validation Rules |
|---|---|---|---|
email | string | ?? | Valid email format, 1~255 chars, auto-converted to lowercase |
password | string | ?? | 6~128 chars |
display_name | string | ?? | 1~100 chars |
Response 201 Created:
{
"access_token": "eyJhbGciOiJIUzI1NiI...",
"refresh_token": "a1b2c3d4e5f6...",
"expires_in": 900,
"token_type": "Bearer",
"user": {
"id": "uuid",
"custom_app_id": "uuid",
"tenant_id": "uuid",
"email": "user@example.com",
"display_name": "John Doe",
"avatar_url": null,
"extra_data": {},
"is_active": true,
"last_login_at": null,
"created_at": "2026-04-01T00:00:00Z",
"updated_at": null
}
}
Error Codes:
| HTTP Code | Detail | Reason |
|---|---|---|
409 | Email already registered | Emails must be unique within the same App |
403 | Origin not in whitelist | Origin is not in the allowed_origins whitelist |
404 | App not found | Invalid slug |
403 | App does not support user authentication | access_mode is not external or self_built |
2.3.3 Login
POST /api/v1/custom-app-auth/{app_slug}/login
Auth: No Auth Required (Public Endpoint)
Request Body:
{
"email": "user@example.com",
"password": "my_secure_password"
}
Response 200 OK: Same format as the Response for 禮2.3.2 Register
Error Codes:
| HTTP Code | Detail | Reason |
|---|---|---|
401 | Incorrect email or password | Email not found or password mismatch |
403 | Account disabled | User has been disabled by Builder |
2.3.4 Get Current User (Me)
GET /api/v1/custom-app-auth/{app_slug}/me
Auth: Bearer Token (Access Token)
Authorization: Bearer eyJhbGciOiJIUzI1NiI...
Response 200 OK:
{
"id": "uuid",
"custom_app_id": "uuid",
"tenant_id": "uuid",
"email": "user@example.com",
"display_name": "John Doe",
"avatar_url": "https://...",
"extra_data": {},
"is_active": true,
"last_login_at": "2026-04-01T12:00:00Z",
"created_at": "2026-04-01T00:00:00Z",
"updated_at": null
}
Error Codes:
| HTTP Code | Detail | Reason |
|---|---|---|
401 | Missing authentication token | Missing Authorization header |
401 | Invalid or expired token | Access Token expired or improperly formatted |
403 | Account disabled | User has been disabled |
2.3.5 Refresh Token
POST /api/v1/custom-app-auth/{app_slug}/refresh
Auth: No Bearer Token Required (Public endpoint, requires refresh_token in Body)
Request Body:
{
"refresh_token": "a1b2c3d4e5f6..."
}
Response 200 OK: Same format as the Response for 禮2.3.2 Register (Contains new access_token and refresh_token)
?? Token Rotation: Upon successful refresh, the old Refresh Token is immediately invalidated (revoked). You must store and use the newly returned
refresh_token.
Error Codes:
| HTTP Code | Detail | Reason |
|---|---|---|
401 | Invalid Refresh Token | Token does not exist or has been revoked |
401 | Refresh Token expired | Exceeds 7-day validity |
401 | User not found or disabled | User account deleted or disabled |
2.3.6 Logout
POST /api/v1/custom-app-auth/{app_slug}/logout
Auth: Bearer Token (Access Token)
Request Body:
{
"refresh_token": "a1b2c3d4e5f6..."
}
Response 200 OK:
{
"message": "Logged out"
}
2.3.7 ext/ Endpoints: Custom App User API
The following endpoints require Custom App User Token (Bearer) authentication and are used for Independent mode frontends directly accessing data:
| Endpoint Prefix | Description | Notes |
|---|---|---|
/api/v1/ext/proxy/ | Access System Tables | Same engine as Open Proxy, different auth method |
/api/v1/ext/data/ | Access Custom Tables | Corresponds to /open/data/ |
/api/v1/ext/compile/ | Fetch/Execute VFS Frontend Code | For AI GO hosted frontends |
/api/v1/ext/actions/ | Execute Server-Side Actions | Execute backend automation scripts |
/api/v1/ext/storage/ | Access Supabase Storage Files | Upload/Download app-related files |
Usage:
# Access system tables using Custom App User Token
curl -H "Authorization: Bearer <access_token>" \
https://api.ai-go.app/api/v1/ext/proxy/customers
# Access Custom Tables using Custom App User Token
curl -H "Authorization: Bearer <access_token>" \
https://api.ai-go.app/api/v1/ext/data/objects/group_tour/records
Difference from Open Proxy:
/ext/*endpoints use Bearer Tokens (Custom App User Token).tenant_idandcustom_app_idare automatically parsed from the Token payload./open/*endpoints use API Keys (X-API-Key). Suitable for backend Server-to-Server calls.- Both share the same reference whitelists and data filtering engines.
2.3.8 Domain Whitelist (Origin Check)
Once allowed_origins is configured, Custom App Auth endpoints (register / login, etc.) check the HTTP Origin header:
| Scenario | Behavior |
|---|---|
| Whitelist is empty | Allows all origins (not yet configured) |
| No Origin header (Backend call / curl) | Allowed |
| Origin is in whitelist | Allowed |
| Origin is not in whitelist | Returns 403 Origin not in whitelist |
?? Port Note: The Port is part of the Origin (RFC 6454), e.g.,
http://localhost:3000??http://localhost:8000. Ensure the whitelist includes the completescheme://host:port.
2.3.9 Builder-side User Management API
The following endpoints allow integration administrators (Builders) to manage Custom App users via the AI GO Management UI. They require main site JWT authentication (builder.access permission):
| Endpoint | Description |
|---|---|
GET /api/v1/custom-app-auth/manage/{app_id}/users | List all users for the App |
PATCH /api/v1/custom-app-auth/manage/{app_id}/users/{user_id} | Enable/Disable user (Body: { "is_active": false }) |
DELETE /api/v1/custom-app-auth/manage/{app_id}/users/{user_id} | Delete user (also deletes all Sessions) |
Upon disabling or deleting a user, their authentication cache is cleared immediately. Any issued Access Tokens will become invalid after the cache TTL (60 seconds) expires.
2.3 OAuth Third-Party Login (LINE, etc.)
Self-built integrations can be additionally configured with OAuth Providers (e.g., LINE Login) allowing end users to log in directly via third-party accounts.
2.4.1 Prerequisites
The Builder must configure the OAuth Provider for the App within the AI GO Management Interface:
- Go to Integration Management ??Select App ??Settings Tab
- Enter the Provider's Client ID and Client Secret (Stored encrypted via AES-256)
- In the third-party platform (e.g., LINE Developers Console), configure the Callback URL as:
https://<YOUR_API_HOST>/api/v1/custom-app-oauth/{app_slug}/{provider}/callback
2.4.2 OAuth Endpoints List
| Endpoint | Auth | Description |
|---|---|---|
GET /api/v1/custom-app-oauth/{slug}/auth-providers | None | List enabled providers |
GET /api/v1/custom-app-oauth/{slug}/{provider}/authorize | None | 302 Redirect to third-party authorization page |
GET /api/v1/custom-app-oauth/{slug}/{provider}/callback | None | Third-party callback handling (System internal) |
POST /api/v1/custom-app-oauth/{slug}/oauth/complete-email | None | Fill missing email (Body: { "pending_token": "...", "email": "..." }) |
Currently supported
providervalues:line(LINE Login). Frameworks for Google, Facebook, GitHub, etc., are in place.
2.4.3 OAuth Login Flow
sequenceDiagram
participant User as End User
participant App as Third-Party Frontend
participant AIGO as AI GO API
participant LINE as LINE Login
App->>AIGO: GET /{slug}/auth-providers
AIGO-->>App: [{ "provider": "line" }]
User->>App: Click LINE Login Button
App->>AIGO: GET /{slug}/line/authorize
AIGO-->>User: 302 ??LINE Authorization Page
User->>LINE: Agree to authorize
LINE-->>AIGO: callback?code=xxx&state=yyy
alt Has email
AIGO-->>App: 302 ??{app_url}?oauth_token=<base64>
Note over App: base64 decode yields<br/>{ access_token, refresh_token, user }
else No email
AIGO-->>App: 302 ??{app_url}?oauth_pending=<token>
App->>User: Display form to supply email
User->>App: Enter email
App->>AIGO: POST /{slug}/oauth/complete-email
AIGO-->>App: { access_token, refresh_token, user }
end
2.4.4 OAuth Token Transmission Method
Upon successful OAuth login, the system returns tokens to the App's live_url via query parameters:
| Query Parameter | Description |
|---|---|
oauth_token | Base64 URL-safe encoded JSON string containing complete tokens and user info |
oauth_pending | Temporary token (valid 30 mins) when email is missing. Frontend must display a form to fill email. |
oauth_error | Error description string if an error occurs during OAuth |
Frontend Decoding Example:
// Decode token upon successful OAuth login
const params = new URLSearchParams(window.location.search);
const encoded = params.get('oauth_token');
if (encoded) {
const decoded = JSON.parse(atob(encoded));
// decoded = { access_token, refresh_token, expires_in, user }
localStorage.setItem('access_token', decoded.access_token);
localStorage.setItem('refresh_token', decoded.refresh_token);
}
2.4.5 OAuth Account Binding Behavior
| Scenario | System Behavior |
|---|---|
| OAuth identity already exists (Bound) | Direct login, update profile |
| Email provided and account with same email exists | Auto-bind OAuth identity to existing account |
| Email provided but no existing account | Auto-register new account + create identity |
| No email | Returns oauth_pending token, awaits email input |
?? OAuth users have a
nullpassword_hashand cannot log in using Email + Password. If password login is required, the user must set a password separately.
2.4 Token Technical Specifications
Token mechanism used for Custom App User authentication:
| Item | Specification |
|---|---|
| Issuance Function | create_custom_app_user_token() |
| JWT Algorithm | HS256 |
Payload scope | app_runtime |
Payload auth_type | custom_app_user |
Payload sub | Custom App User UUID |
| Access Token TTL | 15 minutes (900 seconds) |
| Refresh Mechanism | Refresh Token Rotation (Old token revoked immediately) |
| Refresh Token TTL | 7 days |
| Refresh Token Format | 64-character hex random string |
| Refresh Token Storage | Written to DB after SHA-256 hash |
| Password Hashing | bcrypt (auto-salt) |
Access Token JWT Payload Example
{
"sub": "550e8400-e29b-41d4-a716-446655440000",
"custom_app_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"tenant_id": "11111111-2222-3333-4444-555555555555",
"auth_type": "custom_app_user",
"scope": "app_runtime",
"iat": 1711929600,
"exp": 1711930500
}
Key Distinction: The
auth_typefield is fixed to"custom_app_user", which/ext/*endpoints use to verify identity.
2.4.1 Quick Start: Complete Integration in 30 Minutes
Here are the minimal steps for end-to-end integration:
Step 1 ??Create Integration and Get API Key:
# Create a new integration in the AI GO Admin Interface
# Obtain the app_slug (e.g., e9abbb866184) and API Key (e.g., sk_live_xxx)
Step 2 ??Configure Domain Whitelist:
Add the frontend Origin (e.g., https://myapp.example.com) to the whitelist in the Settings Tab.
Step 3 ??Frontend Integration Example (JavaScript):
const API_BASE = 'https://api.ai-go.app/api/v1';
const APP_SLUG = 'e9abbb866184';
// ?? 1. User Registration ??
async function register(email, password, displayName) {
const res = await fetch(`${API_BASE}/custom-app-auth/${APP_SLUG}/register`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password, display_name: displayName }),
});
const data = await res.json();
if (!res.ok) throw new Error(data.detail);
// Store tokens
localStorage.setItem('access_token', data.access_token);
localStorage.setItem('refresh_token', data.refresh_token);
return data.user;
}
// ?? 2. User Login ??
async function login(email, password) {
const res = await fetch(`${API_BASE}/custom-app-auth/${APP_SLUG}/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password }),
});
const data = await res.json();
if (!res.ok) throw new Error(data.detail);
localStorage.setItem('access_token', data.access_token);
localStorage.setItem('refresh_token', data.refresh_token);
return data.user;
}
// ?? 3. Fetch Data using Token ??
async function fetchCustomers() {
const token = localStorage.getItem('access_token');
const res = await fetch(`${API_BASE}/ext/proxy/customers`, {
headers: { 'Authorization': `Bearer ${token}` },
});
return res.json();
}
// ?? 4. Refresh Tokens ??
async function refreshTokens() {
const refreshToken = localStorage.getItem('refresh_token');
const res = await fetch(`${API_BASE}/custom-app-auth/${APP_SLUG}/refresh`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ refresh_token: refreshToken }),
});
const data = await res.json();
if (!res.ok) throw new Error(data.detail);
// ?? Must update both tokens (Token Rotation)
localStorage.setItem('access_token', data.access_token);
localStorage.setItem('refresh_token', data.refresh_token);
return data;
}
Step 4 ??Backend Server-to-Server Data Access (Python):
import requests
API_KEY = 'sk_live_a1b2c3d4...'
API_BASE = 'https://api.ai-go.app/api/v1'
# Access data directly using API Key (does not involve user authentication)
resp = requests.get(
f'{API_BASE}/open/proxy/customers',
headers={'X-API-Key': API_KEY},
)
print(resp.json())
3. Integration Management API
Prefix:
/api/v1/integrationsAuth: Main Site JWT (requiresbuilder.accesspermission)
3.1 List All Integrations
GET /api/v1/integrations
Response 200 OK:
[
{
"id": "uuid",
"tenant_id": "uuid",
"name": "My ERP Integration",
"slug": "e9abbb866184",
"subdomain": "my-erp",
"live_url": "https://my-erp.example.com",
"allowed_origins": ["https://my-erp.example.com"],
"api_key_count": 2,
"created_at": "2026-03-01T00:00:00Z",
"updated_at": "2026-03-20T00:00:00Z"
}
]
3.2 Create New Integration
POST /api/v1/integrations
| Field | Type | Required | Description |
|---|---|---|---|
name | string | ?? | Integration name (1-100 chars) |
subdomain | string | ?? | Custom subdomain (2-63 chars, globally unique) |
Response 201 Created: IntegrationDetail object
3.3 Get Integration Details
GET /api/v1/integrations/{app_id}
Response 200 OK:
{
"id": "uuid",
"tenant_id": "uuid",
"name": "...",
"slug": "...",
"subdomain": null,
"live_url": null,
"allowed_origins": [],
"access_mode": "self_built",
"created_at": "...",
"updated_at": "..."
}
3.4 Rename
PATCH /api/v1/integrations/{app_id}/name
| Field | Type | Required | Description |
|---|---|---|---|
name | string | ?? | New name (1-100 chars) |
3.5 Update Settings
PATCH /api/v1/integrations/{app_id}/settings
| Field | Type | Required | Description |
|---|---|---|---|
live_url | string | ?? | Live URL (max 500 chars) |
allowed_origins | string[] | ?? | Domain whitelist (CORS restriction) |
3.6 Delete Integration
DELETE /api/v1/integrations/{app_id}
Response 204 No Content (also deletes all associated API Keys)
3.7 API Key Management
List API Keys
GET /api/v1/integrations/{app_id}/api-keys
Response 200 OK:
[
{
"id": "uuid",
"app_id": "uuid",
"key_prefix": "sk_live_a1b2",
"name": "Production Key",
"is_active": true,
"last_used_at": "2026-03-20T12:00:00Z",
"expires_at": null,
"created_at": "2026-03-01T00:00:00Z"
}
]
Create API Key
POST /api/v1/integrations/{app_id}/api-keys
| Field | Type | Required | Description |
|---|---|---|---|
name | string | ?? | Key name (1-100 chars), e.g., "Production Key" |
Response 201 Created:
{
"id": "uuid",
"app_id": "uuid",
"key_prefix": "sk_live_a1b2",
"name": "Production Key",
"api_key": "sk_live_a1b2c3d4e5f6g7h8...",
"created_at": "..."
}
?? The
api_keyfield is only returned once upon creation; please save it securely immediately.
Revoke API Key
DELETE /api/v1/integrations/{app_id}/api-keys/{key_id}
Response 204 No Content
3.8 Publish Approval Workflow
After modifying reference configurations, they must be "Published" before taking effect in the Open Proxy.
Publish Integration
POST /api/v1/integrations/{app_id}/publish
| Query | Type | Description |
|---|---|---|
note | string | Publish note |
Behavior:
- With
builder.publishpermission ??Publishes directly (auto-approved) - Without
builder.publishpermission ??Creates a pending request awaiting review
List Publish Requests
GET /api/v1/integrations/{app_id}/publish-requests
Approve / Reject / Cancel Publish Request
POST /api/v1/integrations/{app_id}/publish-requests/{req_id}/approve
POST /api/v1/integrations/{app_id}/publish-requests/{req_id}/reject
POST /api/v1/integrations/{app_id}/publish-requests/{req_id}/cancel
approve: Requiresbuilder.publishpermissionreject: Requiresbuilder.publishpermission, Body:{ "reject_reason": "..." }cancel: Only the requester can cancel
Get Publish Status
GET /api/v1/integrations/{app_id}/publish-status
Response:
{
"can_publish": true,
"is_locked": false,
"pending_request": null,
"published_at": "2026-03-20T00:00:00Z"
}
4. Reference System API
Prefix:
/api/v1/refsAuth: Main Site JWT (requiresbuilder.accesspermission)
A Reference is the core data authorization mechanism in AI GO. Every integration must first establish references specifying which tables and fields it intends to access, and what operational permissions it holds.
4.1 List Referencable Tables
GET /api/v1/refs/available-tables
Response 200 OK:
[
{ "name": "customers", "comment": "Customer" },
{ "name": "sale_orders", "comment": "Sales Order" },
{ "name": "product_products", "comment": "" }
]
4.2 Get Table Field Information
GET /api/v1/refs/tables/{table_name}/columns
Response 200 OK:
[
{
"name": "name",
"type": "VARCHAR",
"nullable": false,
"is_system": false
},
{
"name": "email",
"type": "VARCHAR",
"nullable": true,
"is_system": false
},
{
"name": "customer_id",
"type": "UUID",
"nullable": true,
"is_system": false,
"is_fk": true,
"fk_target": "customers.id"
}
]
4.3 Reference CRUD
List All References for an App
GET /api/v1/refs/apps/{app_id}
Create Reference
POST /api/v1/refs/apps/{app_id}
| Field | Type | Required | Description |
|---|---|---|---|
table_name | string | ?? | Name of the table to reference, e.g., "customers" |
columns | string[] | ?? | List of authorized fields, e.g., ["name", "email", "phone"] |
permissions | string[] | ?? | List of permissions, e.g., ["read", "create"] |
Update Reference
PATCH /api/v1/refs/{ref_id}
| Field | Type | Description |
|---|---|---|
columns | string[] | New list of authorized fields |
permissions | string[] | New list of permissions |
Delete Reference
DELETE /api/v1/refs/{ref_id}
4.4 Permission Values Explanation
| Permission | Corresponding Proxy Operation | Description |
|---|---|---|
read | GET / POST query | Query data |
create | POST insert | Insert record |
update | PATCH | Update record |
delete | DELETE | Delete record |
4.5 Unreferencable Tables
System core tables (e.g., authentication, tenant management, permission settings, audit logs, etc.) can never be referenced due to security reasons. Attempting to reference these tables will return a 403 Table is not referencable error via the API.
Please use the GET /api/v1/refs/available-tables API to query the list of tables that can be referenced.
4.6 System Fields
The following fields are automatically managed by the system and will be automatically excluded when writing:
| Field | Type | Description |
|---|---|---|
id | UUID | Primary key, auto-generated |
created_at | timestamptz | Creation time, automatically set |
updated_at | timestamptz | Update time, automatically updated |
tenant_id | UUID | Tenant ID, auto-injected (row-level isolation) |
4.7 Shared Business Field: custom_data (JSONB)
All functional data tables contain a custom_data field, designed specifically for third-party applications to store custom data specific to their business operations.
| Feature | Description |
|---|---|
| Type | JSONB (PostgreSQL native JSON binary format) |
| Default Value | '{}'::jsonb (Empty JSON object) |
| Nullable | Yes (Can be set to null) |
| Access Method | Only via Proxy API (Internal / External / Open) |
| Data Isolation | Follows existing tenant_id row-level isolation mechanics |
Usage: Include custom_data in the columns list when creating the reference:
{
"table_name": "customers",
"columns": ["id", "name", "email", "custom_data"],
"permissions": ["read", "create", "update"]
}
?? If
custom_datais not included in the referencedcolumns, the App will not see this field when reading, and it will be automatically ignored when writing.
5. Data Proxy API (Open Proxy)
Prefix:
/api/v1/open/proxyAuth: API Key (X-API-KeyHeader) Data Isolation: Automatic row-level filtering based on thetenant_idassociated with the Key Reference Version: Uses the published reference snapshot
5.0 Three Proxy Endpoints Comparison
The system provides three sets of Proxy endpoints that share the same core query engine. The differences lie solely in authentication methods and reference versions:
| Feature | Internal Proxy | External Proxy | Open Proxy (Self-Built App) |
|---|---|---|---|
| URL Prefix | /api/v1/proxy/{app_id}/ | /api/v1/ext/proxy/ | /api/v1/open/proxy/ |
| Auth Method | Supabase Auth JWT | Custom App Token | API Key (X-API-Key) |
Path requires app_id | ?? | ??(Provided by Token) | ??(Provided by Key) |
| Reference Version | columns + permissions (real-time) | published_columns + published_permissions (requires publishing) | published_columns + published_permissions (requires publishing) |
Simple query limit max | 500 | 1000 | 1000 |
| Advanced Query Support | ?? | ?? | ??(Full support for filter / search / order_by) |
Important: Self-Built Apps accessing via the Open Proxy also fully support advanced query functionalities (filters, search, order_by, select, count_only, etc.), not just
limit/offset. Simply usePOST /{table_name}/query.
External Proxy Auth Note: The External Proxy (
/ext/proxy/) requires Custom App User Token (Bearer) authentication, suitable for Independent mode frontends directly accessing data. See 禮2.3 Custom App User Authentication for obtaining tokens.
5.1 Simple Query
GET /api/v1/open/proxy/{table_name}?limit=100&offset=0
| Query | Type | Default | Description |
|---|---|---|---|
limit | int | 100 | Records per page (Max 1000) |
offset | int | 0 | Offset amount |
Response 200 OK:
[
{
"id": "uuid",
"name": "Customer A",
"email": "a@example.com",
"phone": "0912345678"
}
]
5.2 Advanced Query
POST /api/v1/open/proxy/{table_name}/query
Request Body:
{
"filters": [
{ "column": "status", "op": "eq", "value": "active" },
{ "column": "amount_total", "op": "gte", "value": 1000 }
],
"order_by": [
{ "column": "created_at", "direction": "desc" }
],
"search": "keyword",
"search_columns": ["name", "email"],
"select_columns": ["id", "name", "email"],
"limit": 50,
"offset": 0,
"count_only": false
}
Filter Operators
| Operator | SQL Equivalent | Description | Value Type |
|---|---|---|---|
eq | = | Equals | any |
ne | != | Not equals | any |
gt | > | Greater than | number/string |
gte | >= | Greater than or equal | number/string |
lt | < | Less than | number/string |
lte | <= | Less than or equal | number/string |
like | LIKE | Fuzzy match (case-sensitive) | string |
ilike | ILIKE | Fuzzy match (case-insensitive) | string |
is_null | IS NULL | Is null | None |
is_not_null | IS NOT NULL | Is not null | None |
in | IN (...) | In list | array |
Filter Combination Logic
- Multiple filters are combined using AND.
- OR combinations are not supported (Exception: The
searchfeature applies OR across multiple search columns). - Nested grouped conditions are not supported (e.g.,
(A AND B) OR (C AND D)). - For a BETWEEN effect, combine
gte+ltefilters.
Example ??Query sales orders with amount >= 1000 AND state is active:
{
"filters": [
{ "column": "amount_total", "op": "gte", "value": 1000 },
{ "column": "state", "op": "eq", "value": "sale" }
]
}
Search Full-Text Behavior
searchexecutesILIKE '%keyword%'onsearch_columns(or all authorized non-id fields).- Multiple search columns are combined using OR (matches if any field hits).
- Combining
searchwithfiltersapplies an AND operation (both must be satisfied). - Field values are cast to the
texttype during search, meaning numeric or UUID fields can also be searched.
count_only Mode
When setting "count_only": true, the endpoint only returns the total record count matching the conditions (both filters and search apply):
{ "total": 42 }
5.3 Insert Record
[!WARNING] Proxy API Operations Do Not Trigger Business Document Auto-Generation (Workflow Triggers) Inserting or updating business data via the Proxy API (e.g., changing an order
statetosale) will not automatically generate subsequent documents (like auto-generating delivery orders or invoices). The Proxy API acts purely as a "data-layer proxy." Third-party applications must explicitlyINSERTall related documents, though the system will automatically maintain specific fields (like invoiced quantity, payment status, etc.). Refer to Chapter 8 for the "Auto-Trigger Workflows (Triggers)" of each table.
POST /api/v1/open/proxy/{table_name}
Request Body:
{
"name": "New Customer",
"email": "new@example.com",
"phone": "0912345678",
"custom_data": {
"passport_no": "A123456789",
"travel_pref": ["eco", "window_seat"]
}
}
custom_dataaccepts any JSON structure (objects, arrays, nested).
Response 201 Created:
{
"id": "uuid",
"created_at": "2026-03-24T00:00:00Z",
"data": {
"name": "New Customer",
"email": "new@example.com",
"custom_data": "{\"passport_no\": \"A123456789\"}"
}
}
tenant_idis automatically injected by the system and is not required manually.
5.4 Update Record
PATCH /api/v1/open/proxy/{table_name}/{row_id}
Request Body:
{
"name": "Updated Name",
"phone": "0987654321"
}
Response 200 OK:
{ "id": "uuid", "updated": true }
5.5 Delete Record
DELETE /api/v1/open/proxy/{table_name}/{row_id}
Response 204 No Content
5.6 Automatic Type Conversion
The Proxy automatically casts strings into their corresponding PostgreSQL types:
| Input Format | Conversion Result | Example |
|---|---|---|
YYYY-MM-DD (Exactly 10 chars) | date | "2026-03-24" |
ISO string containing T | datetime | "2026-03-24T12:00:00Z" |
dict / list (JSON object/array) | jsonb (CAST AS jsonb) | {"key": "value"} |
UUID format string (for fields ending in _id) | uuid | "a24bc8fe-5942-4937-ad2f-28812caa5425" |
Empty string "" (for fields ending in _id) | NULL | "" ??writes NULL |
?? UUID Field Notes:
- All fields ending in
_id(e.g.,product_id,order_id) will automatically attempt to cast to the UUID type upon writing.- If the value is an empty string
"", the system automatically casts it toNULL(avoiding PostgreSQL type errors).- If the value is not a valid UUID format (e.g., LINE ID
U1234567890), the original string is preserved.
5.7 AI GO Approval Workflow Integration
? Applies to:
POST,PATCH,DELETE, or any Proxy operation that modifies data.
AI GO provides a flexible approval workflow engine. When system administrators configure an approval workflow for specific tables (e.g., sale_orders) in the backend, your Proxy API calls will automatically be intercepted and reviewed by the approval system.
Interception and API Bypass Mechanism
- Standard Case (Interception): When an approval flow is triggered, the API operation does not take effect directly. Instead, the system will:
- For POST (Insert-then-flag): Insert the unvalidated record first, ensuring an ID is generated for referencing.
- For PATCH / DELETE (Pre-guard): Completely pause the actual database mutation, encapsulating the changed content into an "Approval Request" pending a decision.
- Your API call will receive a response indicating
approval_status: "pending".
- API Bypass: If administrators enable the "Allow API Bypass" option for the corresponding workflow in the backend, third-party APIs can ignore approval rules and forcefully write data. The system only records a Bypass Audit Log in the background for future auditing.
Response Format When Intercepted
When bypass is not enabled and the operation triggers an approval condition, the API does not return the standard success format, but rather:
Example of an Intercepted Update Operation:
{
"id": "e305d21a-e75b-42e1-886d-a1112345abcd",
"updated": false,
"approval_status": "pending",
"approval_request_id": "123e4567-e89b-12d3-a456-426614174000",
"approval_message": "This update requires approval (2 levels). Request created."
}
Developer Note: When integrating with Tables that possess potential approval rules (e.g., Purchase Orders, Sales Orders, Leave Requests), you must catch the
approval_status === "pending"property in your API Response to prevent treating a Pending state as an actual successful modification.
6. Custom Table API
Prefix:
/api/v1/open/dataAuth: API Key (X-API-KeyHeader) Data Isolation: Automatic row-level filtering based on thetenant_idassociated with the Key Reference Whitelist: Not applicable (Custom Tables belong to the App itself, not the reference mechanism)
6.0 Differences Between Custom Tables and System Tables
AI GO provides two distinct data storage mechanisms, using different API endpoints:
| Feature | System Tables (Open Proxy) | Custom Tables (Open Custom Data) |
|---|---|---|
| Endpoint Prefix | /api/v1/open/proxy/{table} | /api/v1/open/data/ |
| Data Source | Built-in system modules (customers, sale_orders, etc.) | Dynamic data tables built by the App |
| Schema Definition | Fixed PostgreSQL table structures | Dynamic JSONB (custom field definitions) |
| Reference Whitelist | ??Requires creating reference + publishing | ??Not required (App's own data) |
| Data Identification | table_name (e.g., customers) | object_id or api_slug |
| Management | Built-in, cannot add/delete tables | Self-created in AI GO Admin UI |
?? Common Error: Do not use the
/open/proxy/endpoint to access Custom Tables. Custom Tables are not physical PostgreSQL tables and do not exist within the reference system. Accessing them via Proxy endpoints will return a403 App is not authorized to access tableerror.
6.1 Custom Table Concepts
Custom Tables represent AI GO's dynamic database system, allowing each App to define its own data table structures:
- CustomObject (Table Definition): Logically equates to a "table", possessing a name and an
api_slug(API identifier). - CustomField (Field Definition): Each Object can define multiple fields (name, type, required status, etc.).
- CustomRecord (Data Record): The actual data is stored within a
datafield in JSONB format.
erDiagram
CustomObject ||--o{ CustomField : "has fields"
CustomObject ||--o{ CustomRecord : "has records"
CustomObject {
UUID id PK
UUID app_id FK
string name
string api_slug
}
CustomField {
UUID id PK
UUID object_id FK
string name
string field_key
string field_type
boolean is_required
int sequence
}
CustomRecord {
UUID id PK
UUID object_id FK
JSONB data
}
6.2 List the App's Custom Tables
GET /api/v1/open/data/objects
Response 200 OK:
[
{
"id": "uuid",
"tenant_id": "uuid",
"app_id": "uuid",
"name": "Group Tour",
"api_slug": "group_tour",
"created_at": "2026-03-20T00:00:00Z",
"updated_at": "2026-03-20T00:00:00Z",
"fields": [
{
"id": "uuid",
"object_id": "uuid",
"name": "Tour Name",
"field_key": "tour_name",
"field_type": "text",
"is_required": true,
"sequence": 10
},
{
"id": "uuid",
"object_id": "uuid",
"name": "Amount",
"field_key": "amount",
"field_type": "number",
"is_required": false,
"sequence": 20
}
]
}
]
The returned
fieldsarray contains comprehensive field definitions, useful for dynamically generating forms or tables.
6.3 List Custom Table Records
GET /api/v1/open/data/objects/{obj_id}/records
Path Parameters:
| Parameter | Description |
|---|---|
obj_id | Custom Table UUID or api_slug (e.g., group_tour) |
Response 200 OK:
[
{
"id": "uuid",
"tenant_id": "uuid",
"object_id": "uuid",
"data": {
"tour_name": "Tokyo 5-Day Tour",
"amount": 35000,
"departure_date": "2026-05-01"
},
"created_at": "2026-03-20T00:00:00Z",
"updated_at": "2026-03-20T00:00:00Z"
},
{
"id": "uuid",
"tenant_id": "uuid",
"object_id": "uuid",
"data": {
"tour_name": "Seoul 3-Day Tour",
"amount": 18000,
"departure_date": "2026-06-15"
},
"created_at": "2026-03-21T00:00:00Z",
"updated_at": "2026-03-21T00:00:00Z"
}
]
The
datafield is JSONB; its structure is determined by the Custom Table'sfieldsdefinitions.
6.4 Insert Record
POST /api/v1/open/data/objects/{obj_id}/records
Path Parameters: obj_id supports UUID or api_slug
Request Body:
{
"data": {
"tour_name": "Bangkok 4-Day Tour",
"amount": 22000,
"departure_date": "2026-07-20",
"max_people": 30,
"itinerary": ["Grand Palace", "Floating Market", "Pattaya"]
}
}
dataaccepts any JSON structure, including objects, arrays, and nested formats.field_keycorresponds to the Custom Table's field definitions.
Response 201 Created:
{
"id": "uuid",
"tenant_id": "uuid",
"object_id": "uuid",
"data": {
"tour_name": "Bangkok 4-Day Tour",
"amount": 22000,
"departure_date": "2026-07-20",
"max_people": 30,
"itinerary": ["Grand Palace", "Floating Market", "Pattaya"]
},
"created_at": "2026-03-29T00:00:00Z",
"updated_at": null
}
tenant_idis automatically injected by the system based on the API Key and does not need to be provided.
6.5 Update Record
PATCH /api/v1/open/data/records/{record_id}
Path Parameters:
| Parameter | Description |
|---|---|
record_id | Record's UUID |
Request Body:
{
"data": {
"amount": 25000,
"status": "confirmed"
}
}
Updates operate in Merge Mode: Only the supplied fields are overwritten; omitted fields remain unchanged. For example, the above request only updates
amountand addsstatus, leaving other fields (liketour_name) unaffected.
Response 200 OK:
{
"id": "uuid",
"tenant_id": "uuid",
"object_id": "uuid",
"data": {
"tour_name": "Bangkok 4-Day Tour",
"amount": 25000,
"departure_date": "2026-07-20",
"max_people": 30,
"itinerary": ["Grand Palace", "Floating Market", "Pattaya"],
"status": "confirmed"
},
"created_at": "2026-03-29T00:00:00Z",
"updated_at": "2026-03-29T01:00:00Z"
}
6.6 Delete Record
DELETE /api/v1/open/data/records/{record_id}
Response 200 OK:
{
"message": "Deleted",
"id": "uuid"
}
6.7 Field Types Explanation
| Type | Description | Example Value in data |
|---|---|---|
text | Text | "Tokyo 5-Day Tour" |
number | Number | 35000, 99.5 |
date | Date (ISO format string) | "2026-05-01" |
relation | UUID relating to another record | "550e8400-e29b-41d4-a716-446655440000" |
Because
datais a JSONB field, it can actually store arbitrary JSON structures (arrays, nested objects, etc.). Thefield_typeis primarily used for UI form rendering and frontend validation.
6.8 Custom Table Complete Usage Example
Below demonstrates the full flow for a third-party travel agency ERP integrating with Custom Tables:
# ?? Step 1: Obtain API Key, then list the App's Custom Tables ??
curl -H "X-API-Key: sk_live_a1b2c3d4e5f6..." \
https://api.ai-go.app/api/v1/open/data/objects
# Example Response:
# [
# {
# "id": "...", "name": "Group Tour", "api_slug": "group_tour",
# "fields": [{"field_key": "tour_name", "field_type": "text"}, ...]
# },
# {
# "id": "...", "name": "Booking Record", "api_slug": "booking",
# "fields": [{"field_key": "customer_name", ...}, ...]
# }
# ]
# ?? Step 2: Use api_slug to list all records in "Group Tour" ??
curl -H "X-API-Key: sk_live_a1b2c3d4e5f6..." \
https://api.ai-go.app/api/v1/open/data/objects/group_tour/records
# ?? Step 3: Insert a new tour record ??
curl -X POST \
-H "X-API-Key: sk_live_a1b2c3d4e5f6..." \
-H "Content-Type: application/json" \
-d '{
"data": {
"tour_name": "Okinawa 4-Day Tour",
"amount": 28000,
"departure_date": "2026-08-10",
"max_people": 25
}
}' \
https://api.ai-go.app/api/v1/open/data/objects/group_tour/records
# ?? Step 4: Update record (Merge mode, only updates specified fields) ??
curl -X PATCH \
-H "X-API-Key: sk_live_a1b2c3d4e5f6..." \
-H "Content-Type: application/json" \
-d '{"data": {"amount": 32000, "status": "full"}}' \
https://api.ai-go.app/api/v1/open/data/records/{record_id}
# ?? Step 5: Delete record ??
curl -X DELETE \
-H "X-API-Key: sk_live_a1b2c3d4e5f6..." \
https://api.ai-go.app/api/v1/open/data/records/{record_id}
6.9 Endpoint Comparison with Open Proxy
If you need to access both system tables (like customers) and Custom Tables concurrently, ensure you use the correct API endpoints:
# ?? Accessing System Tables (e.g., customers) ??Use Open Proxy ??
curl -H "X-API-Key: sk_live_xxx" \
https://api.ai-go.app/api/v1/open/proxy/customers
# ?? Accessing Custom Tables (e.g., group_tour) ??Use Open Custom Data ??
curl -H "X-API-Key: sk_live_xxx" \
https://api.ai-go.app/api/v1/open/data/objects/group_tour/records
| Data to Access | Correct Endpoint | Incorrect Endpoint (Will return 403) |
|---|---|---|
| Built-in system tables (customers, sale_orders, etc.) | /open/proxy/{table} | /open/data/objects/{table}/records |
| Custom Tables (App's dynamic tables) | /open/data/objects/{slug}/records | /open/proxy/{slug} (??403) |
7. Complete List of Referencable Tables and Schemas
The following lists all referencable data tables (applicable only to Open Proxy; for Custom Tables see 禮6). Every table includes four system fields:
id(UUID),created_at(timestamptz),updated_at(timestamptz),tenant_id(UUID), as well as acustom_data(JSONB) custom data field (See 禮4.7), which are not repeated below.
7.1 Customer Module
customers ??Customers
| Field | Type | Nullable | FK | Description |
|---|---|---|---|---|
| name | VARCHAR | ?? | Customer Name | |
| customer_type | VARCHAR | ?? | company / individual | |
| birthday | VARCHAR | ?? | Birthday | |
| id_number | VARCHAR | ?? | ID / VAT Number | |
| registered_address | VARCHAR | ?? | Registered Address | |
| contact_address | VARCHAR | ?? | Contact Address | |
| phone | VARCHAR | ?? | Phone | |
| VARCHAR | ?? | |||
| line_id | VARCHAR | ?? | LINE ID | |
| fax | VARCHAR | ?? | Fax | |
| note | TEXT | ?? | Note | |
| id_file_url | VARCHAR | ?? | ID File URL | |
| contact_person | VARCHAR | ?? | Contact Person | |
| vat | VARCHAR | ?? | VAT | |
| currency_id | UUID | ?? | currencies.id | Currency |
| payment_term | VARCHAR | ?? | Payment Term | |
| credit_limit | FLOAT | ?? | Credit Limit | |
| is_company | BOOLEAN | ?? | Is Company | |
| country_id | UUID | ?? | countries.id | Country |
| state_id | UUID | ?? | country_states.id | State/Province |
| city | VARCHAR | ?? | City | |
| zip_code | VARCHAR | ?? | Zip Code | |
| lang | VARCHAR | ?? | Language Preference | |
| ref | VARCHAR | ?? | Customer Reference | |
| website_url | VARCHAR | ?? | Website | |
| active | BOOLEAN | ?? | Active Status | |
| short_name | VARCHAR | ?? | Short Name | |
| status | VARCHAR | ?? | active / suspended | |
| level_id | UUID | ?? | customer_levels.id | Customer Level |
| salesperson_id | UUID | ?? | users.id | Salesperson |
customer_levels ??Customer Levels
| Field | Type | Nullable | Description |
|---|---|---|---|
| name | VARCHAR | ?? | Level Name |
| discount_rate | NUMERIC(5,4) | ?? | Discount Rate (1.0=Full price) |
| description | TEXT | ?? | Description |
customer_tags ??Customer Tags
| Field | Type | Nullable | Description |
|---|---|---|---|
| name | VARCHAR | ?? | Tag Name |
| color | VARCHAR | ?? | Display Color |
customer_tag_rel ??Customer-Tag Relations
| Field | Type | FK | Description |
|---|---|---|---|
| customer_id | UUID | customers.id | Customer |
| tag_id | UUID | customer_tags.id | Tag |
customer_tag_prices ??Tag Exclusive Prices
| Field | Type | FK | Description |
|---|---|---|---|
| tag_id | UUID | customer_tags.id | Tag |
| product_id | UUID | product_products.id | Product |
| special_price | NUMERIC(16,2) | Exclusive Price |
7.2 Supplier Module
suppliers ??Suppliers
| Field | Type | Nullable | FK | Description |
|---|---|---|---|---|
| name | VARCHAR | ?? | Name | |
| supplier_type | VARCHAR | ?? | company / individual | |
| ref | VARCHAR | ?? | Supplier Reference | |
| vat | VARCHAR | ?? | VAT | |
| contact_person | VARCHAR | ?? | Contact Person | |
| phone | VARCHAR | ?? | Phone | |
| VARCHAR | ?? | |||
| fax | VARCHAR | ?? | Fax | |
| registered_address | VARCHAR | ?? | Registered Address | |
| contact_address | VARCHAR | ?? | Contact Address | |
| city | VARCHAR | ?? | City | |
| zip_code | VARCHAR | ?? | Zip Code | |
| country_id | UUID | ?? | countries.id | Country |
| state_id | UUID | ?? | country_states.id | State/Province |
| payment_term | VARCHAR | ?? | Payment Term | |
| credit_limit | FLOAT | ?? | Credit Limit | |
| currency_id | UUID | ?? | currencies.id | Currency |
| website_url | VARCHAR | ?? | Website | |
| note | TEXT | ?? | Note | |
| active | BOOLEAN | ?? | Active | |
| status | VARCHAR | ?? | active / suspended |
7.3 Product Module
product_categories ??Product Categories
| Field | Type | Nullable | FK | Description |
|---|---|---|---|---|
| name | VARCHAR | ?? | Name | |
| complete_name | VARCHAR | ?? | Complete Path Name | |
| parent_id | UUID | ?? | product_categories.id | Parent Category |
| code | VARCHAR | ?? | Category Code | |
| property_valuation | VARCHAR | ?? | periodic / real_time | |
| property_cost_method | VARCHAR | ?? | standard / fifo / average | |
| property_account_income_id | UUID | ?? | account_accounts.id | Income Account |
| property_account_expense_id | UUID | ?? | account_accounts.id | Expense Account |
| default_warehouse_id | UUID | ?? | stock_warehouses.id | Default Warehouse |
product_templates ??Product Templates
| Field | Type | Nullable | FK | Description |
|---|---|---|---|---|
| name | VARCHAR | ?? | Name | |
| type | VARCHAR | ?? | consu / service / combo | |
| categ_id | UUID | ?? | product_categories.id | Category |
| list_price | NUMERIC(16,2) | ?? | Sales Price | |
| standard_price | NUMERIC(16,2) | ?? | Cost Price | |
| description | TEXT | ?? | Description | |
| default_code | VARCHAR | ?? | SKU | |
| barcode | VARCHAR | ?? | Barcode | |
| active | BOOLEAN | ?? | Active | |
| sale_ok | BOOLEAN | ?? | Can be Sold | |
| purchase_ok | BOOLEAN | ?? | Can be Purchased | |
| uom_id | UUID | ?? | uom_uom.id | Unit of Measure |
| uom_po_id | UUID | ?? | uom_uom.id | Purchase UoM |
| invoice_policy | VARCHAR | ?? | order / delivery |
product_products ??Product Variants
| Field | Type | FK | Description |
|---|---|---|---|
| product_tmpl_id | UUID | product_templates.id | Template |
| default_code | VARCHAR | SKU | |
| barcode | VARCHAR | Barcode | |
| active | BOOLEAN | Active | |
| lst_price_extra | NUMERIC(16,2) | Extra Price | |
| standard_price | NUMERIC(16,2) | Cost Price |
product_price_tiers ??Tiered Pricing
| Field | Type | FK | Description |
|---|---|---|---|
| product_tmpl_id | UUID | product_templates.id | Product Template |
| price_type | VARCHAR | fixed / market | |
| min_qty | NUMERIC(16,4) | Minimum Quantity | |
| max_qty | NUMERIC(16,4) | Maximum Quantity | |
| price | NUMERIC(16,2) | Unit Price | |
| guide_price | NUMERIC(16,2) | Guide Price |
product_supplierinfo ??Supplier Pricing
| Field | Type | FK | Description |
|---|---|---|---|
| supplier_id | UUID | suppliers.id | Supplier |
| product_tmpl_id | UUID | product_templates.id | Product Template |
| product_id | UUID | product_products.id | Product Variant |
| product_name | VARCHAR | Supplier Product Name | |
| product_code | VARCHAR | Supplier Product Code | |
| min_qty | NUMERIC(16,4) | Min Order Quantity | |
| price | NUMERIC(16,2) | Price | |
| currency_id | UUID | currencies.id | Currency |
| date_start | DATE | Start Date | |
| date_end | DATE | End Date | |
| delay | INTEGER | Lead Time (days) |
7.4 Sales Module
sale_orders ??Sales Orders
?? Auto-Trigger Workflows (Triggers)
- When inserting or updating this table (and
sale_order_lines), the system automatically compares delivered versus invoiced quantities to recalculate and update the order'sinvoice_status(no,to_invoice,invoiced).
| Field | Type | Nullable | FK | Description |
|---|---|---|---|---|
| name | VARCHAR | ?? | Order Number | |
| state | VARCHAR | ?? | draft/sent/sale/done/cancel | |
| date_order | DATE | ?? | Order Date | |
| validity_date | DATE | ?? | Validity Date | |
| note | TEXT | ?? | Note | |
| amount_untaxed | NUMERIC(16,2) | ?? | Untaxed Amount | |
| amount_tax | NUMERIC(16,2) | ?? | Tax Amount | |
| amount_total | NUMERIC(16,2) | ?? | Total Amount | |
| margin | NUMERIC(16,2) | ?? | Margin | |
| invoice_status | VARCHAR | ?? | no/to_invoice/invoiced | |
| customer_id | UUID | ?? | customers.id | Customer |
| currency_id | UUID | ?? | currencies.id | Currency |
| user_id | UUID | ?? | users.id | Salesperson |
| department_id | UUID | ?? | hr_departments.id | Department |
sale_order_lines ??Sales Order Lines
| Field | Type | FK | Description |
|---|---|---|---|
| order_id | UUID | sale_orders.id | Order |
| name | TEXT | Description | |
| product_id | UUID | product_products.id | Product |
| product_uom_qty | NUMERIC(16,4) | Quantity | |
| qty_delivered | NUMERIC(16,4) | Delivered Quantity | |
| qty_invoiced | NUMERIC(16,4) | Invoiced Quantity | |
| price_unit | NUMERIC(16,2) | Unit Price | |
| discount | NUMERIC(5,2) | Discount % | |
| price_subtotal | NUMERIC(16,2) | Subtotal | |
| price_total | NUMERIC(16,2) | Total w/ Tax | |
| tax_id | UUID | account_taxes.id | Tax |
| delivery_date | DATE | Expected Delivery Date |
7.5 Procurement Module
purchase_orders ??Purchase Orders
?? Auto-Trigger Workflows (Triggers)
- When inserting or updating this table (and
purchase_order_lines), the system automatically recalculates and updates the invoice status for this order.
| Field | Type | FK | Description |
|---|---|---|---|
| name | VARCHAR | Order Number | |
| state | VARCHAR | draft/sent/purchase/done/cancel | |
| date_order | DATE | Order Date | |
| date_planned | DATE | Expected Delivery Date | |
| amount_untaxed | NUMERIC(16,2) | Untaxed Amount | |
| amount_tax | NUMERIC(16,2) | Tax Amount | |
| amount_total | NUMERIC(16,2) | Total Amount | |
| supplier_id | UUID | suppliers.id | Supplier |
| currency_id | UUID | currencies.id | Currency |
| user_id | UUID | users.id | Responsible |
| notes | TEXT | Notes | |
| origin | VARCHAR | Source Document |
purchase_order_lines ??Purchase Order Lines
| Field | Type | FK | Description |
|---|---|---|---|
| order_id | UUID | purchase_orders.id | Order |
| product_id | UUID | product_products.id | Product |
| product_qty | NUMERIC(16,4) | Quantity | |
| qty_received | NUMERIC(16,4) | Received Quantity | |
| price_unit | NUMERIC(16,2) | Unit Price | |
| price_subtotal | NUMERIC(16,2) | Subtotal | |
| price_total | NUMERIC(16,2) | Total | |
| tax_id | UUID | account_taxes.id | Tax |
7.6 Accounting Module
?? Core Accounting Logic and Dedicated API Warning Note: If you directly use the
Open Proxy APItoINSERTintoaccount_movesandaccount_move_lines, the system will not trigger accounting fail-safes and automated processing (e.g., auto-numbering, auto-balancing entries, etc.). This can lead to unbalanced debits and credits generating dirty data.If you are developing an independent accounting/invoicing integration, it is strongly recommended that you exclusively use AI GO's dedicated Accounting Business APIs:
POST /api/v1/accounting/vouchers(Create Voucher: auto-configures entry and mappings)POST /api/v1/accounting/vouchers/{id}/post(Post Voucher: automatically inserts an "auto-balance entry" based on settlement gaps and generates a Voucher Number)In these dedicated APIs, if a
Debit ??Creditmismatch is detected, the system automatically injects an "auto-balance entry" to forcibly balance the total amounts, ensuring accounting constraints do not collapse! For detailed Endpoint specs, please see the system's/docsSwagger page.
account_moves ??Journal Entries / Invoices
?? Auto-Trigger Workflows (Triggers)
- When updating this invoice or its lines, along with associated payment reconciliation (
account_payments), the system automatically recalculates the invoice'spayment_state(e.g.,paid,partial,not_paid).
| Field | Type | FK | Description |
|---|---|---|---|
| name | VARCHAR | Number | |
| move_type | VARCHAR | entry/out_invoice/in_invoice/out_refund/in_refund/out_receipt/in_receipt | |
| state | VARCHAR | draft/posted/cancel | |
| date | DATE | Accounting Date | |
| invoice_date | DATE | Invoice Date | |
| invoice_date_due | DATE | Due Date | |
| customer_id | UUID | customers.id | Customer |
| supplier_id | UUID | suppliers.id | Supplier |
| currency_id | UUID | currencies.id | Currency |
| journal_id | UUID | account_journals.id | Journal |
| amount_untaxed | NUMERIC(16,2) | Untaxed Amount | |
| amount_tax | NUMERIC(16,2) | Tax Amount | |
| amount_total | NUMERIC(16,2) | Total Amount | |
| amount_residual | NUMERIC(16,2) | Amount Due | |
| payment_state | VARCHAR | not_paid/partial/paid/reversed/invoicing_legacy/in_payment | |
| voucher_number | VARCHAR | Voucher Number |
account_move_lines ??Journal Entry Lines
| Field | Type | FK | Description |
|---|---|---|---|
| move_id | UUID | account_moves.id | Entry |
| name | VARCHAR | Label | |
| quantity | NUMERIC(16,4) | Quantity | |
| price_unit | NUMERIC(16,2) | Unit Price | |
| debit | NUMERIC(16,2) | Debit | |
| credit | NUMERIC(16,2) | Credit | |
| balance | NUMERIC(16,2) | Balance | |
| account_id | UUID | account_accounts.id | Account |
| tax_rate | NUMERIC(5,2) | Tax Rate % | |
| tax_amount | NUMERIC(16,2) | Tax Amount |
The Accounting Module also includes
account_accounts,account_journals,account_taxes,account_payment_terms,account_fiscal_positions,account_payments,account_bank_statements,account_move_templates, etc. For their structures, query theGET /refs/tables/{table_name}/columnsAPI in real-time.
7.7 Inventory Module
stock_warehouses ??Warehouses
| Field | Type | Description |
|---|---|---|
| name | VARCHAR | Warehouse Name |
| code | VARCHAR(5) | Short Code |
| active | BOOLEAN | Active |
| reception_steps | VARCHAR | one_step/two_steps/three_steps |
| delivery_steps | VARCHAR | ship_only/pick_ship/pick_pack_ship |
stock_locations ??Locations
| Field | Type | FK | Description |
|---|---|---|---|
| name | VARCHAR | Name | |
| usage | VARCHAR | supplier/view/internal/customer/inventory/transit/production | |
| active | BOOLEAN | Active | |
| barcode | VARCHAR | Barcode | |
| location_id | UUID | stock_locations.id | Parent Location |
stock_pickings ??Pickings/Transfers
| Field | Type | FK | Description |
|---|---|---|---|
| name | VARCHAR | Order Number | |
| state | VARCHAR | draft/waiting/confirmed/assigned/done/cancel | |
| origin | VARCHAR | Source Document | |
| picking_type_id | UUID | stock_picking_types.id | Picking Type |
| location_id | UUID | stock_locations.id | Source Location |
| location_dest_id | UUID | stock_locations.id | Dest Location |
| customer_id | UUID | customers.id | Customer |
| supplier_id | UUID | suppliers.id | Supplier |
| sale_id | UUID | sale_orders.id | Sales Order |
| purchase_id | UUID | purchase_orders.id | Purchase Order |
stock_moves ??Stock Moves
?? Auto-Trigger Workflows (Triggers)
- When updating the status of this table, the system automatically recalculates the partial incoming/outgoing completion status of the associated picking (
stock_pickings).
| Field | Type | FK | Description |
|---|---|---|---|
| name | TEXT | Description | |
| state | VARCHAR | draft/waiting/confirmed/partially_available/assigned/done/cancel | |
| product_id | UUID | product_products.id | Product |
| product_uom_qty | NUMERIC(16,4) | Demand Quantity | |
| quantity | NUMERIC(16,4) | Done Quantity | |
| location_id | UUID | stock_locations.id | Source |
| location_dest_id | UUID | stock_locations.id | Destination |
| picking_id | UUID | stock_pickings.id | Picking |
stock_quants ??Stock Quantities
| Field | Type | FK | Description |
|---|---|---|---|
| product_id | UUID | product_products.id | Product |
| location_id | UUID | stock_locations.id | Location |
| lot_id | UUID | stock_lots.id | Lot |
| quantity | NUMERIC(16,4) | On Hand Quantity | |
| reserved_quantity | NUMERIC(16,4) | Reserved Quantity |
?? Regarding Stock Quantity Maintenance (Triggers): When inserting or updating
stock_move_lines(stock move details), the system automatically calculates and updates the reserved quantity (stock_quants.reserved_quantity) for the corresponding items in their respective locations.
The Inventory Module also includes
stock_lots,stock_picking_types,stock_move_lines,stock_routes,stock_rules,stock_packages,stock_scraps,stock_warehouse_orderpoints,stock_landed_costs,stock_picking_batches,delivery_carriers,inventory_check_batches,inventory_check_items,inventory_converts,freight_groups,freight_group_tiers, etc.
7.8 CRM Module
crm_leads ??Leads / Opportunities
| Field | Type | FK | Description |
|---|---|---|---|
| name | VARCHAR | Name | |
| type | VARCHAR | lead / opportunity | |
| active | BOOLEAN | Active | |
| priority | VARCHAR | 0/1/2/3 (Stars) | |
| stage_id | UUID | crm_stages.id | Stage |
| probability | FLOAT | Probability % | |
| expected_revenue | NUMERIC(16,2) | Expected Revenue | |
| customer_id | UUID | customers.id | Customer |
| contact_name | VARCHAR | Contact Name | |
| email_from | VARCHAR | ||
| phone | VARCHAR | Phone | |
| user_id | UUID | users.id | Responsible |
| team_id | UUID | crm_teams.id | Sales Team |
| date_deadline | DATE | Expected Closing Date | |
| description | TEXT | Description |
Also includes
crm_stages,crm_teams,crm_team_members,crm_lost_reasons,crm_tags,crm_recurring_plans,crm_activities, etc.
7.9 HR Human Resources Module
hr_employees ??Employees
?? Auto-Trigger Workflows (Triggers)
- Attendance (
hr_attendances): Creating or updating an attendance record automatically updates the employee's current attendance state.- Leaves (
hr_leaves): When a leave request state is updated tovalidate(approved), it automatically deducts from the employee's available leave allocations (hr_leave_allocations).- Timesheets (
hr_timesheets): Filling out timesheets automatically accumulatesproject_tasks.effective_hours(task actual hours) and updates project task progress percentages.
| Field | Type | FK | Description |
|---|---|---|---|
| name | VARCHAR | Name | |
| active | BOOLEAN | Active | |
| employee_type | VARCHAR | employee/student/trainee/contractor/freelance | |
| job_title | VARCHAR | Job Title | |
| work_phone | VARCHAR | Work Phone | |
| work_email | VARCHAR | Work Email | |
| mobile_phone | VARCHAR | Mobile Phone | |
| gender | VARCHAR | male/female/other | |
| birthday | DATE | Birthday | |
| department_id | UUID | hr_departments.id | Department |
| job_id | UUID | hr_jobs.id | Job Position |
| parent_id | UUID | hr_employees.id | Direct Manager |
| user_id | UUID | users.id | Associated User |
| member_id | UUID | members.id | System Account |
Also includes
hr_departments,hr_jobs,hr_work_locations,hr_attendances,hr_leave_types,hr_leaves,hr_leave_allocations,hr_expense_sheets,hr_expenses,hr_skill_types,hr_skills,hr_timesheets,hr_work_entry_types,hr_work_entries, etc.
7.10 MRP Manufacturing Module
mrp_productions ??Manufacturing Orders
?? Auto-Trigger Workflows (Triggers)
- When updating the state of associated work orders (
mrp_workorders), the system automatically calculates and refreshes the completion progress of this manufacturing order.
| Field | Type | FK | Description |
|---|---|---|---|
| name | VARCHAR | Order Number | |
| product_id | UUID | product_products.id | Product |
| product_qty | FLOAT | Planned Quantity | |
| qty_produced | FLOAT | Produced Quantity | |
| state | VARCHAR | draft/confirmed/progress/to_close/done/cancel | |
| bom_id | UUID | mrp_boms.id | Bill of Materials |
| date_start | TIMESTAMPTZ | Start Date | |
| date_finished | TIMESTAMPTZ | Finished Date | |
| user_id | UUID | users.id | Responsible |
| is_subcontract | BOOLEAN | Subcontracted |
Also includes
mrp_workcenters,mrp_boms,mrp_bom_lines,mrp_bom_byproducts,mrp_routing_workcenters,mrp_workorders,mrp_unbuilds, etc.
7.11 Project Management Module
project_projects ??Projects
?? Auto-Trigger Workflows (Triggers)
- When creating or deleting associated tasks (
project_tasks), the system automatically maintains and updates the total task count (task_count) of this project master record.
| Field | Type | FK | Description |
|---|---|---|---|
| name | VARCHAR | Project Name | |
| active | BOOLEAN | Active | |
| description | TEXT | Description | |
| date_start | DATE | Start Date | |
| date | DATE | Deadline Date | |
| stage_id | UUID | project_project_stages.id | Stage |
| customer_id | UUID | customers.id | Customer |
| user_id | UUID | users.id | PM |
| task_count | INTEGER | Task Count |
project_tasks ??Tasks
| Field | Type | FK | Description |
|---|---|---|---|
| name | VARCHAR | Name | |
| state | VARCHAR | 01_in_progress/1_done/1_canceled/04_waiting_normal/03_approved/02_changes_requested | |
| priority | VARCHAR | 0 (Normal)/1 (Urgent) | |
| description | TEXT | Description | |
| date_deadline | DATE | Deadline | |
| project_id | UUID | project_projects.id | Project |
| stage_id | UUID | project_task_types.id | Kanban Stage |
| parent_id | UUID | project_tasks.id | Parent Task |
| planned_hours | FLOAT | Planned Hours | |
| effective_hours | FLOAT | Effective Hours | |
| progress | FLOAT | Progress % |
Also includes
project_project_stages,project_task_types,project_milestones,project_tags,project_roles,project_collaborators,project_task_recurrences,project_updates, etc.
7.12 Core Reference Tables
countries ??Countries
| Field | Type | Description |
|---|---|---|
| name | VARCHAR | Name |
| code | VARCHAR(2) | ISO 3166-1 alpha-2 |
| phone_code | INTEGER | International Phone Code |
| currency_id | UUID | Default Currency |
currencies ??Currencies
| Field | Type | Description |
|---|---|---|
| name | VARCHAR(3) | ISO 4217 (TWD, USD) |
| full_name | VARCHAR | Full Name |
| symbol | VARCHAR(10) | Symbol (NT$, $) |
| decimal_places | INTEGER | Decimal Places |
uom_uom ??Units of Measure
| Field | Type | FK | Description |
|---|---|---|---|
| name | VARCHAR | Name | |
| category_id | UUID | uom_categories.id | Category |
| uom_type | VARCHAR | reference/bigger/smaller | |
| factor | FLOAT | Conversion Factor |
Also includes
country_states,currency_rates,languages,uom_categories,ir_sequences, etc.
7.13 Other Modules
| Table Name | Description |
|---|---|
analytic_accounts | Analytic Accounts |
analytic_lines | Analytic Lines |
utm_sources | UTM Sources |
utm_mediums | UTM Mediums |
utm_campaigns | UTM Campaigns |
announcements | Announcements |
file_nodes | File Nodes |
purchase_stock_links | Purchase-Stock Links |
sale_stock_links | Sale-Stock Links |
sale_purchase_links | Sale-Purchase Links |
The complete fields of all tables can be queried dynamically via
GET /api/v1/refs/tables/{table_name}/columns.
8. Error Codes and Limits
8.1 HTTP Status Codes
| Status Code | Description |
|---|---|
200 | Success |
201 | Created successfully |
204 | Deleted successfully (No Content) |
400 | Bad Request (e.g., invalid permission values, illegal filter columns) |
401 | Unauthorized (API Key invalid or missing) |
403 | Forbidden (Unreferencable table, unauthorized action, unpublished reference) |
404 | Resource Not Found |
409 | Conflict (e.g., subdomain in use, pending publish request exists) |
422 | Unprocessable Entity (Validation failed) |
429 | Too Many Requests (Rate limit exceeded) |
500 | Internal Server Error |
8.2 Common Error Messages
| Message | Cause | Possible Solution |
|---|---|---|
"App is not authorized to access table '{table}'" | Reference for this table not created | If system table, create a reference; if Custom Table, switch to /open/data/ endpoint |
"Reference for table '{table}' is not published" | Reference created but not published (Open Proxy requires published version) | Publish reference configuration in Integration Management |
"App is not authorized to perform '{op}' on table '{table}'" | Referenced permissions do not include this action | Update reference to include the required permission |
"Unauthorized filter column: {col}" | Query uses a field not authorized in columns | Add the field to the reference |
"This table is not referencable" | The table is on the blacklist | System core tables cannot be accessed |
"API Key invalid or revoked" | Key does not exist or has been disabled | Create a new API Key |
"Data object does not exist" | Custom Table's object_id or api_slug is incorrect | Call GET /open/data/objects first to verify available Custom Tables |
"Record does not exist" | Custom Table's record_id is incorrect or deleted | Verify the record_id is correct and belongs to this App |
8.3 Rate Limiting
The system implements Per-App rate limiting on all API requests. Exceeding the limit returns 429 Too Many Requests.
8.4 Security Considerations
- All data queries automatically enforce row-level isolation using
tenant_id, preventing cross-tenant access. tenant_idis automatically determined by the API Key and cannot be forged.- During write operations, system fields (
id,created_at,updated_at,tenant_id) are automatically excluded. - Field names are regex validated (
^[a-zA-Z_][a-zA-Z0-9_]*$) to prevent SQL injection. - Only whitelisted operators are permitted; arbitrary SQL is not accepted.
9. Proxy Query Security Mechanisms and Functional Limits
9.1 Security Validation Flow
Every Proxy call sequentially executes the following validations:
??AppDataReference Whitelist Validation
??Checks if the App has a reference to the target table (Open Proxy requires a published snapshot)
??CRUD Permission Check
??The referenced permissions must include the requested action (read / create / update / delete)
??Blacklist Table Check
??The 14 system core tables are permanently inaccessible
??Field Whitelist Validation
??Fields in filter / select / insert / update must be in the authorized columns list
??Field Name Regex Validation
??Only allows ^[a-zA-Z_][a-zA-Z0-9_]*$ to prevent SQL injection
??Operator Whitelist Validation
??Only accepts 11 defined operators (eq, ne, gt, gte, lt, lte, like, ilike, in, is_null, is_not_null)
??Tenant Isolation Injection
??Automatically appends WHERE tenant_id = :tid to all queries (cross-tenant access impossible)
??System Field Protection
??Automatically excludes id, created_at, updated_at, tenant_id during INSERT / UPDATE
9.2 Open Proxy Access Methods Comparison
| Call Method | Simple Query | Advanced Query (inc. filters) | Description |
|---|---|---|---|
GET /open/proxy/{table} | ?? | ?? | Only limit / offset |
POST /open/proxy/{table}/query | ?? | ?? | Full filter / search / order_by / select / count_only |
9.3 Known Query Functional Limitations
| Limitation | Description | Alternative |
|---|---|---|
| No OR conditions | Filters can only be ANDed | Use search for multi-column OR searches, or split into multiple queries |
| No nested conditions | Cannot express (A AND B) OR C | Split into multiple queries and merge at the application layer |
| No JOINs | Can only query a single table | Query two tables separately and associate them at the application layer |
| No aggregation functions | No SUM / AVG / GROUP BY | Query raw data and compute at the application layer |
| No BETWEEN | No between operator | Combine gte + lte filters |
| No NOT IN | Only in, no not_in | Query all and filter at the application layer |
| No NOT LIKE | Only like / ilike | Query all and filter at the application layer |
| Single query limit | limit max is 500 (GET) or 1000 (Open Proxy GET) | Iterate pagination using offset |
| No cursor pagination | Only limit + offset | For massive data, pair with order_by and increment offset |
| No cross-tenant query | tenant_id is forcibly injected | This is a security design; no alternative exists |
9.4 Filter Field Validation Rules Summary
| Validation Item | Check Logic | Failure Return |
|---|---|---|
| Field Name Format | Must match ^[a-zA-Z_][a-zA-Z0-9_]*$ | 400 Illegal field name |
| Field Authorization | Must be in allowed_columns list (id is always allowed) | 400 Unauthorized filter column |
| Operator Legality | Must be one of the 11 whitelisted operators | 400 Unsupported operator |
in Operator Type | value must be an array | 400 Value for 'in' operator must be an array |
select_columns Auth | Selected fields must be in allowed_columns | 400 Unauthorized column |
| Order By Fields | Fields not in the whitelist are silently ignored | Falls back to default sorting created_at DESC |
Tip: The latest field structures for all tables can be dynamically fetched via
GET /api/v1/refs/tables/{table_name}/columns, including data types, Nullable status, and foreign key targets. It is highly recommended to pair your development with this API.
10. Enum Values Quick Reference
The complete list of VARCHAR fields that only accept fixed enum values.
- [DB]: Has a PostgreSQL
CHECK CONSTRAINT; writing an illegal value directly triggers a400/500error.- [Suggested]: No database constraint; functions as a system suggestion. Frontend and backend interfaces rely on these, and while the API will not reject other values, they may cause UI display anomalies.
10.1 Customer Module
| Table | Field | Constraint | Accepted Values | Description |
|---|---|---|---|---|
customers | customer_type | [DB] | company, individual | Company / Individual |
customers | status | [DB] | active, suspended | Active / Suspended |
10.2 Supplier Module
| Table | Field | Constraint | Accepted Values | Description |
|---|---|---|---|---|
suppliers | supplier_type | [DB] | company, individual | Company / Individual |
suppliers | status | [DB] | active, suspended | Active / Suspended |
10.3 Product Module
| Table | Field | Constraint | Accepted Values | Description |
|---|---|---|---|---|
product_categories | property_valuation | [Suggested] | periodic, real_time | Periodic / Real-time (Perpetual Inventory) |
product_categories | property_cost_method | [Suggested] | standard, fifo, average | Standard Cost / FIFO / Weighted Average |
product_templates | type | [DB] | consu, service, combo | Consumable / Service / Combo Product |
product_templates | invoice_policy | [DB] | order, delivery | Invoice on Order / Invoice on Delivery |
product_templates | service_type | [DB] | manual, timesheet | Manual / Based on Timesheet |
product_templates | expense_policy | [DB] | no, cost, sales_price | Non-reimbursable / At Cost / At Sales Price |
product_price_tiers | price_type | [DB] | fixed, market | Fixed Pricing / Market Pricing |
10.4 Sales Module
| Table | Field | Constraint | Accepted Values | Description |
|---|---|---|---|---|
sale_orders | state | [DB] | draft, sent, sale, done, cancel | Draft ??Quotation Sent ??Sales Order ??Done ??Cancelled |
sale_orders | invoice_status | [DB] | no, to_invoice, invoiced | Nothing to Invoice / To Invoice / Invoiced |
sale_orders | tax_type | [Suggested] | tax_included, tax_excluded, tax_exempt, zero_rate | Tax Included / Tax Excluded / Tax Exempt / Zero Rate |
sale_orders | invoice_format | [Suggested] | duplicate, triplicate, none | Duplicate / Triplicate / None |
sale_orders | carrier_type | [Suggested] | barcode, citizen_digital, mobile, none | Barcode Carrier / Citizen Digital Cert / Mobile Barcode / None |
sale_orders | delivery_method | [Suggested] | pickup, delivery, mail, freight | Pickup / Delivery / Mail / Freight |
sale_order_lines | invoice_status | [DB] | no, to_invoice, invoiced | Nothing to Invoice / To Invoice / Invoiced |
sale_order_lines | display_type | [DB] | line_section, line_note | Section Header / Note Line |
sale_order_template_lines | display_type | [Suggested] | line_section, line_note | Section Header / Note Line |
10.5 Procurement Module
| Table | Field | Constraint | Accepted Values | Description |
|---|---|---|---|---|
purchase_orders | state | [DB] | draft, sent, purchase, done, cancel | Draft ??RFQ Sent ??Purchase Order ??Done ??Cancelled |
purchase_orders | invoice_status | [DB] | no, to_invoice, invoiced | Nothing to Invoice / To Invoice / Invoiced |
purchase_orders | tax_type | [Suggested] | tax_included, tax_excluded, tax_exempt, zero_rate | Tax Included / Tax Excluded / Tax Exempt / Zero Rate |
purchase_requisitions | state | [DB] | draft, ongoing, in_progress, open, done, cancel | Draft ??Ongoing ??In Progress ??Open ??Done ??Cancelled |
purchase_requisitions | requisition_type | [DB] | purchase, blanket_order | Purchase Agreement / Blanket Order |
10.6 Accounting Module
| Table | Field | Constraint | Accepted Values | Description |
|---|---|---|---|---|
account_moves | move_type | [DB] | entry, out_invoice, out_refund, in_invoice, in_refund, out_receipt, in_receipt | Journal Entry / Customer Invoice / Customer Credit Note / Vendor Bill / Vendor Refund / Sales Receipt / Purchase Receipt |
account_moves | state | [DB] | draft, posted, cancel | Draft / Posted / Cancelled |
account_moves | payment_state | [DB] | not_paid, partial, paid, reversed, invoicing_legacy, in_payment | Not Paid / Partial / Paid / Reversed / Legacy / In Payment |
account_moves | journal_type | [Suggested] | sale, purchase, cash, bank, general | Sales / Purchase / Cash / Bank / General |
account_moves | voucher_type | [Suggested] | general, cash, transfer, bank | General / Cash / Transfer / Bank Voucher |
account_moves | settlement_status | [Suggested] | receivable, payable, provisional_receipt, provisional_payment, settled | Receivable / Payable / Prov. Receipt / Prov. Payment / Settled |
account_fiscal_years | state | [DB] | open, closed | Open / Closed |
account_periods | state | [DB] | open, closed | Open / Closed |
account_lock_dates | lock_date_field | [DB] | fiscalyear_lock_date, tax_lock_date, sale_lock_date, purchase_lock_date | Global Lock / Tax Lock / Sales Lock / Purchase Lock |
account_lock_dates | state | [DB] | active, revoked, expired | Active / Revoked / Expired |
account_reports | report_type | [DB] | general_ledger, balance_sheet, profit_loss, cash_flow, aged_receivable, aged_payable, tax_report, partner_ledger, trial_balance | General Ledger / Balance Sheet / P&L / Cash Flow / Aged Receivable / Aged Payable / Tax Report / Partner Ledger / Trial Balance |
account_report_lines | expression_engine | [DB] | domain, account_codes, aggregation, tax_tags, custom | Domain Filter / Account Codes / Aggregation / Tax Tags / Custom |
account_payments | payment_type | [Suggested] | inbound, outbound | Inbound / Outbound |
account_payments | partner_type | [Suggested] | customer, supplier | Customer / Supplier |
10.7 Inventory Module
| Table | Field | Constraint | Accepted Values | Description |
|---|---|---|---|---|
stock_warehouses | reception_steps | [DB] | one_step, two_steps, three_steps | 1 Step / 2 Steps / 3 Steps (Receipt) |
stock_warehouses | delivery_steps | [DB] | ship_only, pick_ship, pick_pack_ship | Ship Only / Pick+Ship / Pick+Pack+Ship |
stock_locations | usage | [DB] | supplier, view, internal, customer, inventory, production, transit | Supplier / View / Internal / Customer / Inventory / Production / Transit |
stock_picking_types | code | [DB] | incoming, outgoing, internal, mrp_operation | Receipt / Delivery / Internal Transfer / Manufacturing |
stock_pickings | state | [DB] | draft, waiting, confirmed, assigned, done, cancel | Draft / Waiting / Confirmed / Assigned / Done / Cancelled |
stock_pickings | priority | [DB] | 0, 1 | Normal / Urgent |
stock_moves | state | [DB] | draft, waiting, confirmed, partially_available, assigned, done, cancel | Draft / Waiting / Confirmed / Partially Available / Assigned / Done / Cancelled |
stock_moves | procure_method | [DB] | make_to_stock, make_to_order | Make to Stock / Make to Order (MTO) |
stock_move_lines | state | [Suggested] | draft, assigned, done, cancel | Draft / Assigned / Done / Cancelled |
stock_rules | action | [DB] | pull, push, pull_push, buy, manufacture | Pull / Push / Pull & Push / Buy / Manufacture |
stock_rules | procure_method | [DB] | make_to_stock, make_to_order | Make to Stock / Make to Order |
stock_scraps | state | [DB] | draft, done | Draft / Done |
stock_scraps | scrap_reason | [Suggested] | damaged, expired, quality, other | Damaged / Expired / Quality / Other |
stock_storage_categories | allow_new_product | [DB] | empty, same, mixed | Empty Only / Same Product / Mixed |
stock_landed_costs | state | [DB] | draft, done, cancel | Draft / Done / Cancelled |
stock_landed_cost_lines | split_method | [DB] | equal, by_quantity, by_current_cost_price, by_weight, by_volume | Equal / By Quantity / By Cost / By Weight / By Volume |
stock_picking_batches | state | [DB] | draft, in_progress, done, cancel | Draft / In Progress / Done / Cancelled |
delivery_carriers | delivery_type | [DB] | fixed, base_on_rule | Fixed Price / Rule Based |
inventory_check_batches | state | [DB] | draft, done | Draft / Done |
inventory_converts | state | [DB] | draft, done | Draft / Done |
freight_groups | mode | [DB] | fixed, tiered, free | Fixed / Tiered / Free Shipping |
10.8 CRM Module
| Table | Field | Constraint | Accepted Values | Description |
|---|---|---|---|---|
crm_leads | type | [DB] | lead, opportunity | Lead / Opportunity |
crm_leads | priority | [DB] | 0, 1, 2, 3 | Normal / 1 Star / 2 Stars / 3 Stars |
crm_activities | activity_type | [DB] | email, call, meeting, todo | Email / Call / Meeting / To-Do |
crm_activities | state | [DB] | planned, done, overdue, cancelled | Planned / Done / Overdue / Cancelled |
10.9 HR Human Resources Module
| Table | Field | Constraint | Accepted Values | Description |
|---|---|---|---|---|
hr_employees | employee_type | [Suggested] | employee, student, trainee, contractor, freelance | Employee / Student / Trainee / Contractor / Freelance |
hr_employees | gender | [Suggested] | male, female, other | Male / Female / Other |
hr_employees | marital | [Suggested] | single, married, cohabitant, widower, divorced | Single / Married / Cohabitant / Widower / Divorced |
hr_employees | hr_presence_state | [Suggested] | present, absent, to_define | Present / Absent / To Define |
hr_work_locations | location_type | [DB] | home, office, other | Home / Office / Other |
hr_leave_types | requires_allocation | [Suggested] | yes, no | Requires Allocation / Does Not Require |
hr_leave_types | leave_validation_type | [Suggested] | no_validation, hr, manager, both | No Validation / HR / Manager / Both |
hr_leave_types | time_type | [Suggested] | leave, other | Time Off / Other |
hr_leave_types | request_unit | [Suggested] | day, half_day, hour | Day / Half Day / Hour |
hr_leaves | state | [DB] | draft, confirm, refuse, validate1, validate, cancel | Draft / Confirmed / Refused / Approved (L1) / Approved / Cancelled |
hr_leaves | holiday_type | [Suggested] | employee, company, department, category | Employee / Company / Department / Category |
hr_leave_allocations | state | [Suggested] | draft, confirm, validate1, validate, refuse | Draft / Confirmed / Approved (L1) / Approved / Refused |
hr_leave_allocations | allocation_type | [Suggested] | regular, accrual | Regular / Accrual |
hr_expense_sheets | state | [DB] | draft, submit, approve, post, done, cancel | Draft / Submitted / Approved / Posted / Done / Cancelled |
hr_expense_sheets | payment_state | [Suggested] | not_paid, in_payment, paid | Not Paid / In Payment / Paid |
hr_expenses | state | [DB] | draft, reported, approved, done, refused | Draft / Reported / Approved / Done / Refused |
hr_expenses | payment_mode | [Suggested] | own_account, company_account | Employee (to reimburse) / Company Account |
hr_work_entries | state | [DB] | draft, validated, conflict, cancelled | Draft / Validated / Conflict / Cancelled |
10.10 MRP Manufacturing Module
| Table | Field | Constraint | Accepted Values | Description |
|---|---|---|---|---|
mrp_boms | type | [DB] | normal, phantom, subcontracting | Normal / Phantom / Subcontracting |
mrp_boms | ready_to_produce | [DB] | all_available, asap | When all components available / ASAP |
mrp_routing_workcenters | time_mode | [DB] | auto, manual | Auto / Manual |
mrp_productions | state | [DB] | draft, confirmed, progress, to_close, done, cancel | Draft / Confirmed / In Progress / To Close / Done / Cancelled |
mrp_productions | priority | [DB] | 0, 1 | Normal / Urgent |
mrp_workorders | state | [DB] | pending, waiting, ready, progress, done, cancel | Pending / Waiting / Ready / In Progress / Done / Cancelled |
mrp_unbuilds | state | [DB] | draft, done | Draft / Done |
10.11 Project Management Module
| Table | Field | Constraint | Accepted Values | Description |
|---|---|---|---|---|
project_projects | privacy_visibility | [DB] | portal, employees, followers | Portal / Employees / Followers Only |
project_tasks | state | [DB] | 01_in_progress, 1_done, 1_canceled, 04_waiting_normal, 03_approved, 02_changes_requested | In Progress / Done / Cancelled / Waiting / Approved / Changes Requested |
project_tasks | kanban_state | [DB] | normal, done, blocked | Normal / Ready / Blocked |
project_tasks | priority | [DB] | 0, 1 | Normal / Urgent |
project_task_recurrences | repeat_unit | [DB] | day, week, month, year | Day / Week / Month / Year |
project_task_recurrences | repeat_type | [DB] | forever, until, after | Forever / Until Date / After count |
project_updates | status | [DB] | on_track, at_risk, off_track, on_hold, done | On Track / At Risk / Off Track / On Hold / Done |
10.12 Announcement Module
| Table | Field | Constraint | Accepted Values | Description |
|---|---|---|---|---|
announcements | priority | [Suggested] | normal, high, urgent | Normal / High / Urgent |
announcements | announcement_type | [Suggested] | bulletin, push | Bulletin / Push Notification |
announcements | send_mode | [Suggested] | immediate, scheduled | Immediate / Scheduled |
announcements | send_status | [Suggested] | draft, pending, sent, failed | Draft / Pending / Sent / Failed |
announcements | target_type | [Suggested] | all, tag, level | All / Tag / Level |
announcements | validity_type | [Suggested] | permanent, limited | Permanent / Limited Time |
10.13 Fixed Asset Module
| Table | Field | Constraint | Accepted Values | Description |
|---|---|---|---|---|
fixed_assets | state | [DB] | draft, running, fully_depreciated, disposed, closed | Draft / Running / Fully Depreciated / Disposed / Closed |
fixed_assets | depreciation_method | [DB] | straight_line, declining_balance, sum_of_years | Straight Line / Declining Balance / Sum of Years |
fixed_asset_depreciations | status | [DB] | draft, posted | Draft / Posted |
10.14 Finance/Bank Module
| Table | Field | Constraint | Accepted Values | Description |
|---|---|---|---|---|
partner_banks | account_type | [DB] | bank, iban | Bank / IBAN |
partner_banks | partner_type | [DB] | customer, supplier, member, tenant | Customer / Supplier / Member / Tenant |
10.15 Core Reference Tables
| Table | Field | Constraint | Accepted Values | Description |
|---|---|---|---|---|
uom_uom | uom_type | [DB] | reference, bigger, smaller | Reference / Bigger / Smaller |
countries | name_position | [Suggested] | before, after | Name Before / Name After |
currencies | position | [Suggested] | before, after | Symbol Before / Symbol After |
languages | direction | [Suggested] | ltr, rtl | Left-to-Right / Right-to-Left |
ir_sequences | implementation | [DB] | standard, no_gap | Standard (allows gaps) / No Gap |
10.16 System Management Module
| Table | Field | Constraint | Accepted Values | Description |
|---|---|---|---|---|
custom_apps | access_mode | [Suggested] | internal, external, self_built | Internal / External / Self-Built |
Usage Tips:
- When querying via filters, use the
eqoperator for precise matching on enum fields, e.g.,{"column": "state", "op": "eq", "value": "draft"}.- To query multiple enum values, use the
inoperator, e.g.,{"column": "state", "op": "in", "value": ["draft", "sent"]}.- When inserting or updating records, enum fields with [DB] constraints must use the values strictly from the list; otherwise, a
400/500error will be returned.
11. Third-Party Application Best Practices & Gotchas
[!TIP] A summary of common pain points for third-party developers, covering data isolation mechanisms, query safeguards, migration scripts, and CI/CD caveats.
11.1 Best Practices for Multi-App Tenants
[!IMPORTANT] Why is this important? In the AI GO system, a single Tenant might run multiple Custom Apps simultaneously (e.g., a "Booking Platform" and an "E-Commerce Store"). Without data isolation, users on the E-Commerce Store might see "Luxury Ocean View Room" listed as a retail product.
Recommended Strategies:
- Data Domain Separation (App Domain): Strictly enforce that all Custom Apps utilizing shared tables (like
product_templates,sale_orders) must inject a domain identifier tag when creating data (e.g.,custom_data: { "app_domain": "ec-platform" }). - Proxy Layer Interception: If you implement an API Request Interceptor on your frontend or write your own API Proxy layer, it is recommended to automatically append the
app_domainfilter or default field increateandlistoperations to achieve transparent, site-wide isolation.
11.2 Formatting Traps with PostgreSQL JSONB Queries (Gotchas)
[!WARNING] Trap Warning! Whitespace characteristics during JSON serialization can cause intuitive
ilikequeries to fail.
Recommended Strategies:
- String Query Characteristics: AI GO stores
custom_datain JSONB format within the database. When using the Open Proxy API (like the/queryendpoint) to performilikefilters, using a precise{"app_domain":"ec-platform"}as the condition will often fail to match any data. - Solution: When PostgreSQL serializes a JSONB object into text for comparison, it often automatically adds a space after the JSON colon (e.g.,
{"app_domain": "ec-platform"}). Therefore, you should use loose string matching:- ??Incorrect:
custom_data::text ilike '%"app_domain":"ec-platform"%' - ??Correct:
custom_data::text ilike '%app_domain%ec-platform%'
- ??Incorrect:
11.3 API Proxy Secure Access Control (Access & Auth Models)
[!CAUTION] Certain core system tables (like
sale_order_lines) possess low-level strict permission protections, denying arbitrary inserts or deletes.
Recommended Strategies:
- Distinguishing Open Proxy vs. Ext Proxy: Clarify which scenarios (like public catalog reading) can use API Keys, and which scenarios (like consumers checking themselves out) strictly require Bearer Tokens (Custom App User Tokens).
- Capability Matrix Limitations: For specific tables, even if you hold the
Deletereference permission, if you trigger an underlying safeguard (e.g., unable to delete lines from a paid order), the API will return a403 Forbiddenerror. You should guide the user to the "AI GO Admin Interface" for GUI-based operations or authorized refunds instead.
11.4 Data Migration Script Example (Data Migration Boilerplate)
[!TIP] As an application evolves to its next stage (e.g., introducing data isolation networks late in development), you inevitably need to batch-update the
custom_dataof historical records.
Node.js Migration Script Example: To ensure backward compatibility, you can prepare a batch script locally to automate the updates:
const axios = require('axios');
const API_URL = 'https://api.ai-go.app/api/v1/open/proxy/product_templates/query';
const API_KEY = 'sk_live_xxxxxx';
async function migrate() {
let offset = 0;
while (true) {
// Query records that do not have the tag yet (illustrative; adapt as needed)
const resp = await axios.post(API_URL, {
limit: 100,
offset: offset
}, { headers: { 'X-API-Key': API_KEY } });
const products = resp.data.data || [];
if (products.length === 0) break;
for (const p of products) {
// Check and PATCH each old record to inject app_domain
if (!p.custom_data || !p.custom_data.app_domain) {
await axios.patch(`https://api.ai-go.app/api/v1/open/proxy/product_templates/${p.id}`, {
custom_data: { ...(p.custom_data || {}), app_domain: 'ec-platform' }
}, { headers: { 'X-API-Key': API_KEY } });
}
}
offset += 100;
console.log(`Migrated batch offset ${offset}`);
}
}
migrate();
11.5 End-to-End Deployment and CI/CD (E2E Deployment)
Recommended Strategies:
- Environment Variable Sync Protocols: Before pushing your frontend application to Vercel or GitHub Actions for building, triple-check that
VITE_API_BASE,VITE_APP_SLUG, andAIGO_API_KEYin.env.productionor your CI/CD Secrets dashboard are correctly configured with their corresponding Production values. - Repository Visibility Reminder: If you use Vercel's automated git-pull deployments (Git Integration), you must grant the Vercel app permissions to read that Private GitHub Repository. If module missing errors occur during the build, verify repository permissions or consider setting the source repository to Public.