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

FeatureInternalExternalSelf-Built
Use CaseInternal organizational toolsCustomer/Supplier facing appsIndependent third-party system integrations
AuthenticationSupabase Auth JWTCustom App AuthAPI Key
Code HostingAI GO BuilderAI GO BuilderThird-party self-hosted
Data AccessInternal ProxyExternal ProxyOpen Proxy
Reference requires publishingNo (immediate effect)No (immediate effect)Yes (requires publishing snapshot)
access_modeinternalexternalself_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 (not app_id) as the path parameter. The slug can be found next to the title on the integration details page (a 12-character hex string). The system also supports using subdomain instead of slug.


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"
}
FieldTypeRequiredValidation Rules
emailstring??Valid email format, 1~255 chars, auto-converted to lowercase
passwordstring??6~128 chars
display_namestring??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 CodeDetailReason
409Email already registeredEmails must be unique within the same App
403Origin not in whitelistOrigin is not in the allowed_origins whitelist
404App not foundInvalid slug
403App does not support user authenticationaccess_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 CodeDetailReason
401Incorrect email or passwordEmail not found or password mismatch
403Account disabledUser 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 CodeDetailReason
401Missing authentication tokenMissing Authorization header
401Invalid or expired tokenAccess Token expired or improperly formatted
403Account disabledUser 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 CodeDetailReason
401Invalid Refresh TokenToken does not exist or has been revoked
401Refresh Token expiredExceeds 7-day validity
401User not found or disabledUser 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 PrefixDescriptionNotes
/api/v1/ext/proxy/Access System TablesSame engine as Open Proxy, different auth method
/api/v1/ext/data/Access Custom TablesCorresponds to /open/data/
/api/v1/ext/compile/Fetch/Execute VFS Frontend CodeFor AI GO hosted frontends
/api/v1/ext/actions/Execute Server-Side ActionsExecute backend automation scripts
/api/v1/ext/storage/Access Supabase Storage FilesUpload/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_id and custom_app_id are 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:

ScenarioBehavior
Whitelist is emptyAllows all origins (not yet configured)
No Origin header (Backend call / curl)Allowed
Origin is in whitelistAllowed
Origin is not in whitelistReturns 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 complete scheme://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):

EndpointDescription
GET /api/v1/custom-app-auth/manage/{app_id}/usersList 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:

  1. Go to Integration Management ??Select App ??Settings Tab
  2. Enter the Provider's Client ID and Client Secret (Stored encrypted via AES-256)
  3. 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

EndpointAuthDescription
GET /api/v1/custom-app-oauth/{slug}/auth-providersNoneList enabled providers
GET /api/v1/custom-app-oauth/{slug}/{provider}/authorizeNone302 Redirect to third-party authorization page
GET /api/v1/custom-app-oauth/{slug}/{provider}/callbackNoneThird-party callback handling (System internal)
POST /api/v1/custom-app-oauth/{slug}/oauth/complete-emailNoneFill missing email (Body: { "pending_token": "...", "email": "..." })

Currently supported provider values: 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 ParameterDescription
oauth_tokenBase64 URL-safe encoded JSON string containing complete tokens and user info
oauth_pendingTemporary token (valid 30 mins) when email is missing. Frontend must display a form to fill email.
oauth_errorError 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

ScenarioSystem Behavior
OAuth identity already exists (Bound)Direct login, update profile
Email provided and account with same email existsAuto-bind OAuth identity to existing account
Email provided but no existing accountAuto-register new account + create identity
No emailReturns oauth_pending token, awaits email input

?? OAuth users have a null password_hash and 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:

ItemSpecification
Issuance Functioncreate_custom_app_user_token()
JWT AlgorithmHS256
Payload scopeapp_runtime
Payload auth_typecustom_app_user
Payload subCustom App User UUID
Access Token TTL15 minutes (900 seconds)
Refresh MechanismRefresh Token Rotation (Old token revoked immediately)
Refresh Token TTL7 days
Refresh Token Format64-character hex random string
Refresh Token StorageWritten to DB after SHA-256 hash
Password Hashingbcrypt (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_type field 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/integrations Auth: Main Site JWT (requires builder.access permission)

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
FieldTypeRequiredDescription
namestring??Integration name (1-100 chars)
subdomainstring??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
FieldTypeRequiredDescription
namestring??New name (1-100 chars)

3.5 Update Settings

PATCH /api/v1/integrations/{app_id}/settings
FieldTypeRequiredDescription
live_urlstring??Live URL (max 500 chars)
allowed_originsstring[]??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
FieldTypeRequiredDescription
namestring??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_key field 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
QueryTypeDescription
notestringPublish note

Behavior:

  • With builder.publish permission ??Publishes directly (auto-approved)
  • Without builder.publish permission ??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: Requires builder.publish permission
  • reject: Requires builder.publish permission, 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/refs Auth: Main Site JWT (requires builder.access permission)

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}
FieldTypeRequiredDescription
table_namestring??Name of the table to reference, e.g., "customers"
columnsstring[]??List of authorized fields, e.g., ["name", "email", "phone"]
permissionsstring[]??List of permissions, e.g., ["read", "create"]

Update Reference

PATCH /api/v1/refs/{ref_id}
FieldTypeDescription
columnsstring[]New list of authorized fields
permissionsstring[]New list of permissions

Delete Reference

DELETE /api/v1/refs/{ref_id}

4.4 Permission Values Explanation

PermissionCorresponding Proxy OperationDescription
readGET / POST queryQuery data
createPOST insertInsert record
updatePATCHUpdate record
deleteDELETEDelete 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:

FieldTypeDescription
idUUIDPrimary key, auto-generated
created_attimestamptzCreation time, automatically set
updated_attimestamptzUpdate time, automatically updated
tenant_idUUIDTenant 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.

FeatureDescription
TypeJSONB (PostgreSQL native JSON binary format)
Default Value'{}'::jsonb (Empty JSON object)
NullableYes (Can be set to null)
Access MethodOnly via Proxy API (Internal / External / Open)
Data IsolationFollows 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_data is not included in the referenced columns, 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/proxy Auth: API Key (X-API-Key Header) Data Isolation: Automatic row-level filtering based on the tenant_id associated 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:

FeatureInternal ProxyExternal ProxyOpen Proxy (Self-Built App)
URL Prefix/api/v1/proxy/{app_id}//api/v1/ext/proxy//api/v1/open/proxy/
Auth MethodSupabase Auth JWTCustom App TokenAPI Key (X-API-Key)
Path requires app_id????(Provided by Token)??(Provided by Key)
Reference Versioncolumns + permissions (real-time)published_columns + published_permissions (requires publishing)published_columns + published_permissions (requires publishing)
Simple query limit max50010001000
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 use POST /{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
QueryTypeDefaultDescription
limitint100Records per page (Max 1000)
offsetint0Offset 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

OperatorSQL EquivalentDescriptionValue Type
eq=Equalsany
ne!=Not equalsany
gt>Greater thannumber/string
gte>=Greater than or equalnumber/string
lt<Less thannumber/string
lte<=Less than or equalnumber/string
likeLIKEFuzzy match (case-sensitive)string
ilikeILIKEFuzzy match (case-insensitive)string
is_nullIS NULLIs nullNone
is_not_nullIS NOT NULLIs not nullNone
inIN (...)In listarray

Filter Combination Logic

  • Multiple filters are combined using AND.
  • OR combinations are not supported (Exception: The search feature 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 + lte filters.

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

  • search executes ILIKE '%keyword%' on search_columns (or all authorized non-id fields).
  • Multiple search columns are combined using OR (matches if any field hits).
  • Combining search with filters applies an AND operation (both must be satisfied).
  • Field values are cast to the text type 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 state to sale) 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 explicitly INSERT all 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_data accepts 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_id is 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 FormatConversion ResultExample
YYYY-MM-DD (Exactly 10 chars)date"2026-03-24"
ISO string containing Tdatetime"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 to NULL (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

  1. 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".
  2. 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/data Auth: API Key (X-API-Key Header) Data Isolation: Automatic row-level filtering based on the tenant_id associated 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:

FeatureSystem Tables (Open Proxy)Custom Tables (Open Custom Data)
Endpoint Prefix/api/v1/open/proxy/{table}/api/v1/open/data/
Data SourceBuilt-in system modules (customers, sale_orders, etc.)Dynamic data tables built by the App
Schema DefinitionFixed PostgreSQL table structuresDynamic JSONB (custom field definitions)
Reference Whitelist??Requires creating reference + publishing??Not required (App's own data)
Data Identificationtable_name (e.g., customers)object_id or api_slug
ManagementBuilt-in, cannot add/delete tablesSelf-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 a 403 App is not authorized to access table error.

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 data field 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 fields array 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:

ParameterDescription
obj_idCustom 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 data field is JSONB; its structure is determined by the Custom Table's fields definitions.

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"]
  }
}

data accepts any JSON structure, including objects, arrays, and nested formats. field_key corresponds 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_id is 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:

ParameterDescription
record_idRecord'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 amount and adds status, leaving other fields (like tour_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

TypeDescriptionExample Value in data
textText"Tokyo 5-Day Tour"
numberNumber35000, 99.5
dateDate (ISO format string)"2026-05-01"
relationUUID relating to another record"550e8400-e29b-41d4-a716-446655440000"

Because data is a JSONB field, it can actually store arbitrary JSON structures (arrays, nested objects, etc.). The field_type is 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 AccessCorrect EndpointIncorrect 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 a custom_data(JSONB) custom data field (See 禮4.7), which are not repeated below.


7.1 Customer Module

customers ??Customers

FieldTypeNullableFKDescription
nameVARCHAR??Customer Name
customer_typeVARCHAR??company / individual
birthdayVARCHAR??Birthday
id_numberVARCHAR??ID / VAT Number
registered_addressVARCHAR??Registered Address
contact_addressVARCHAR??Contact Address
phoneVARCHAR??Phone
emailVARCHAR??Email
line_idVARCHAR??LINE ID
faxVARCHAR??Fax
noteTEXT??Note
id_file_urlVARCHAR??ID File URL
contact_personVARCHAR??Contact Person
vatVARCHAR??VAT
currency_idUUID??currencies.idCurrency
payment_termVARCHAR??Payment Term
credit_limitFLOAT??Credit Limit
is_companyBOOLEAN??Is Company
country_idUUID??countries.idCountry
state_idUUID??country_states.idState/Province
cityVARCHAR??City
zip_codeVARCHAR??Zip Code
langVARCHAR??Language Preference
refVARCHAR??Customer Reference
website_urlVARCHAR??Website
activeBOOLEAN??Active Status
short_nameVARCHAR??Short Name
statusVARCHAR??active / suspended
level_idUUID??customer_levels.idCustomer Level
salesperson_idUUID??users.idSalesperson

customer_levels ??Customer Levels

FieldTypeNullableDescription
nameVARCHAR??Level Name
discount_rateNUMERIC(5,4)??Discount Rate (1.0=Full price)
descriptionTEXT??Description

customer_tags ??Customer Tags

FieldTypeNullableDescription
nameVARCHAR??Tag Name
colorVARCHAR??Display Color

customer_tag_rel ??Customer-Tag Relations

FieldTypeFKDescription
customer_idUUIDcustomers.idCustomer
tag_idUUIDcustomer_tags.idTag

customer_tag_prices ??Tag Exclusive Prices

FieldTypeFKDescription
tag_idUUIDcustomer_tags.idTag
product_idUUIDproduct_products.idProduct
special_priceNUMERIC(16,2)Exclusive Price

7.2 Supplier Module

suppliers ??Suppliers

FieldTypeNullableFKDescription
nameVARCHAR??Name
supplier_typeVARCHAR??company / individual
refVARCHAR??Supplier Reference
vatVARCHAR??VAT
contact_personVARCHAR??Contact Person
phoneVARCHAR??Phone
emailVARCHAR??Email
faxVARCHAR??Fax
registered_addressVARCHAR??Registered Address
contact_addressVARCHAR??Contact Address
cityVARCHAR??City
zip_codeVARCHAR??Zip Code
country_idUUID??countries.idCountry
state_idUUID??country_states.idState/Province
payment_termVARCHAR??Payment Term
credit_limitFLOAT??Credit Limit
currency_idUUID??currencies.idCurrency
website_urlVARCHAR??Website
noteTEXT??Note
activeBOOLEAN??Active
statusVARCHAR??active / suspended

7.3 Product Module

product_categories ??Product Categories

FieldTypeNullableFKDescription
nameVARCHAR??Name
complete_nameVARCHAR??Complete Path Name
parent_idUUID??product_categories.idParent Category
codeVARCHAR??Category Code
property_valuationVARCHAR??periodic / real_time
property_cost_methodVARCHAR??standard / fifo / average
property_account_income_idUUID??account_accounts.idIncome Account
property_account_expense_idUUID??account_accounts.idExpense Account
default_warehouse_idUUID??stock_warehouses.idDefault Warehouse

product_templates ??Product Templates

FieldTypeNullableFKDescription
nameVARCHAR??Name
typeVARCHAR??consu / service / combo
categ_idUUID??product_categories.idCategory
list_priceNUMERIC(16,2)??Sales Price
standard_priceNUMERIC(16,2)??Cost Price
descriptionTEXT??Description
default_codeVARCHAR??SKU
barcodeVARCHAR??Barcode
activeBOOLEAN??Active
sale_okBOOLEAN??Can be Sold
purchase_okBOOLEAN??Can be Purchased
uom_idUUID??uom_uom.idUnit of Measure
uom_po_idUUID??uom_uom.idPurchase UoM
invoice_policyVARCHAR??order / delivery

product_products ??Product Variants

FieldTypeFKDescription
product_tmpl_idUUIDproduct_templates.idTemplate
default_codeVARCHARSKU
barcodeVARCHARBarcode
activeBOOLEANActive
lst_price_extraNUMERIC(16,2)Extra Price
standard_priceNUMERIC(16,2)Cost Price

product_price_tiers ??Tiered Pricing

FieldTypeFKDescription
product_tmpl_idUUIDproduct_templates.idProduct Template
price_typeVARCHARfixed / market
min_qtyNUMERIC(16,4)Minimum Quantity
max_qtyNUMERIC(16,4)Maximum Quantity
priceNUMERIC(16,2)Unit Price
guide_priceNUMERIC(16,2)Guide Price

product_supplierinfo ??Supplier Pricing

FieldTypeFKDescription
supplier_idUUIDsuppliers.idSupplier
product_tmpl_idUUIDproduct_templates.idProduct Template
product_idUUIDproduct_products.idProduct Variant
product_nameVARCHARSupplier Product Name
product_codeVARCHARSupplier Product Code
min_qtyNUMERIC(16,4)Min Order Quantity
priceNUMERIC(16,2)Price
currency_idUUIDcurrencies.idCurrency
date_startDATEStart Date
date_endDATEEnd Date
delayINTEGERLead 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's invoice_status (no, to_invoice, invoiced).
FieldTypeNullableFKDescription
nameVARCHAR??Order Number
stateVARCHAR??draft/sent/sale/done/cancel
date_orderDATE??Order Date
validity_dateDATE??Validity Date
noteTEXT??Note
amount_untaxedNUMERIC(16,2)??Untaxed Amount
amount_taxNUMERIC(16,2)??Tax Amount
amount_totalNUMERIC(16,2)??Total Amount
marginNUMERIC(16,2)??Margin
invoice_statusVARCHAR??no/to_invoice/invoiced
customer_idUUID??customers.idCustomer
currency_idUUID??currencies.idCurrency
user_idUUID??users.idSalesperson
department_idUUID??hr_departments.idDepartment

sale_order_lines ??Sales Order Lines

FieldTypeFKDescription
order_idUUIDsale_orders.idOrder
nameTEXTDescription
product_idUUIDproduct_products.idProduct
product_uom_qtyNUMERIC(16,4)Quantity
qty_deliveredNUMERIC(16,4)Delivered Quantity
qty_invoicedNUMERIC(16,4)Invoiced Quantity
price_unitNUMERIC(16,2)Unit Price
discountNUMERIC(5,2)Discount %
price_subtotalNUMERIC(16,2)Subtotal
price_totalNUMERIC(16,2)Total w/ Tax
tax_idUUIDaccount_taxes.idTax
delivery_dateDATEExpected 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.
FieldTypeFKDescription
nameVARCHAROrder Number
stateVARCHARdraft/sent/purchase/done/cancel
date_orderDATEOrder Date
date_plannedDATEExpected Delivery Date
amount_untaxedNUMERIC(16,2)Untaxed Amount
amount_taxNUMERIC(16,2)Tax Amount
amount_totalNUMERIC(16,2)Total Amount
supplier_idUUIDsuppliers.idSupplier
currency_idUUIDcurrencies.idCurrency
user_idUUIDusers.idResponsible
notesTEXTNotes
originVARCHARSource Document

purchase_order_lines ??Purchase Order Lines

FieldTypeFKDescription
order_idUUIDpurchase_orders.idOrder
product_idUUIDproduct_products.idProduct
product_qtyNUMERIC(16,4)Quantity
qty_receivedNUMERIC(16,4)Received Quantity
price_unitNUMERIC(16,2)Unit Price
price_subtotalNUMERIC(16,2)Subtotal
price_totalNUMERIC(16,2)Total
tax_idUUIDaccount_taxes.idTax

7.6 Accounting Module

?? Core Accounting Logic and Dedicated API Warning Note: If you directly use the Open Proxy API to INSERT into account_moves and account_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:

  1. POST /api/v1/accounting/vouchers (Create Voucher: auto-configures entry and mappings)
  2. 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 ??Credit mismatch 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 /docs Swagger 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's payment_state (e.g., paid, partial, not_paid).
FieldTypeFKDescription
nameVARCHARNumber
move_typeVARCHARentry/out_invoice/in_invoice/out_refund/in_refund/out_receipt/in_receipt
stateVARCHARdraft/posted/cancel
dateDATEAccounting Date
invoice_dateDATEInvoice Date
invoice_date_dueDATEDue Date
customer_idUUIDcustomers.idCustomer
supplier_idUUIDsuppliers.idSupplier
currency_idUUIDcurrencies.idCurrency
journal_idUUIDaccount_journals.idJournal
amount_untaxedNUMERIC(16,2)Untaxed Amount
amount_taxNUMERIC(16,2)Tax Amount
amount_totalNUMERIC(16,2)Total Amount
amount_residualNUMERIC(16,2)Amount Due
payment_stateVARCHARnot_paid/partial/paid/reversed/invoicing_legacy/in_payment
voucher_numberVARCHARVoucher Number

account_move_lines ??Journal Entry Lines

FieldTypeFKDescription
move_idUUIDaccount_moves.idEntry
nameVARCHARLabel
quantityNUMERIC(16,4)Quantity
price_unitNUMERIC(16,2)Unit Price
debitNUMERIC(16,2)Debit
creditNUMERIC(16,2)Credit
balanceNUMERIC(16,2)Balance
account_idUUIDaccount_accounts.idAccount
tax_rateNUMERIC(5,2)Tax Rate %
tax_amountNUMERIC(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 the GET /refs/tables/{table_name}/columns API in real-time.


7.7 Inventory Module

stock_warehouses ??Warehouses

FieldTypeDescription
nameVARCHARWarehouse Name
codeVARCHAR(5)Short Code
activeBOOLEANActive
reception_stepsVARCHARone_step/two_steps/three_steps
delivery_stepsVARCHARship_only/pick_ship/pick_pack_ship

stock_locations ??Locations

FieldTypeFKDescription
nameVARCHARName
usageVARCHARsupplier/view/internal/customer/inventory/transit/production
activeBOOLEANActive
barcodeVARCHARBarcode
location_idUUIDstock_locations.idParent Location

stock_pickings ??Pickings/Transfers

FieldTypeFKDescription
nameVARCHAROrder Number
stateVARCHARdraft/waiting/confirmed/assigned/done/cancel
originVARCHARSource Document
picking_type_idUUIDstock_picking_types.idPicking Type
location_idUUIDstock_locations.idSource Location
location_dest_idUUIDstock_locations.idDest Location
customer_idUUIDcustomers.idCustomer
supplier_idUUIDsuppliers.idSupplier
sale_idUUIDsale_orders.idSales Order
purchase_idUUIDpurchase_orders.idPurchase 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).
FieldTypeFKDescription
nameTEXTDescription
stateVARCHARdraft/waiting/confirmed/partially_available/assigned/done/cancel
product_idUUIDproduct_products.idProduct
product_uom_qtyNUMERIC(16,4)Demand Quantity
quantityNUMERIC(16,4)Done Quantity
location_idUUIDstock_locations.idSource
location_dest_idUUIDstock_locations.idDestination
picking_idUUIDstock_pickings.idPicking

stock_quants ??Stock Quantities

FieldTypeFKDescription
product_idUUIDproduct_products.idProduct
location_idUUIDstock_locations.idLocation
lot_idUUIDstock_lots.idLot
quantityNUMERIC(16,4)On Hand Quantity
reserved_quantityNUMERIC(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

FieldTypeFKDescription
nameVARCHARName
typeVARCHARlead / opportunity
activeBOOLEANActive
priorityVARCHAR0/1/2/3 (Stars)
stage_idUUIDcrm_stages.idStage
probabilityFLOATProbability %
expected_revenueNUMERIC(16,2)Expected Revenue
customer_idUUIDcustomers.idCustomer
contact_nameVARCHARContact Name
email_fromVARCHAREmail
phoneVARCHARPhone
user_idUUIDusers.idResponsible
team_idUUIDcrm_teams.idSales Team
date_deadlineDATEExpected Closing Date
descriptionTEXTDescription

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 to validate (approved), it automatically deducts from the employee's available leave allocations (hr_leave_allocations).
  • Timesheets (hr_timesheets): Filling out timesheets automatically accumulates project_tasks.effective_hours (task actual hours) and updates project task progress percentages.
FieldTypeFKDescription
nameVARCHARName
activeBOOLEANActive
employee_typeVARCHARemployee/student/trainee/contractor/freelance
job_titleVARCHARJob Title
work_phoneVARCHARWork Phone
work_emailVARCHARWork Email
mobile_phoneVARCHARMobile Phone
genderVARCHARmale/female/other
birthdayDATEBirthday
department_idUUIDhr_departments.idDepartment
job_idUUIDhr_jobs.idJob Position
parent_idUUIDhr_employees.idDirect Manager
user_idUUIDusers.idAssociated User
member_idUUIDmembers.idSystem 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.
FieldTypeFKDescription
nameVARCHAROrder Number
product_idUUIDproduct_products.idProduct
product_qtyFLOATPlanned Quantity
qty_producedFLOATProduced Quantity
stateVARCHARdraft/confirmed/progress/to_close/done/cancel
bom_idUUIDmrp_boms.idBill of Materials
date_startTIMESTAMPTZStart Date
date_finishedTIMESTAMPTZFinished Date
user_idUUIDusers.idResponsible
is_subcontractBOOLEANSubcontracted

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.
FieldTypeFKDescription
nameVARCHARProject Name
activeBOOLEANActive
descriptionTEXTDescription
date_startDATEStart Date
dateDATEDeadline Date
stage_idUUIDproject_project_stages.idStage
customer_idUUIDcustomers.idCustomer
user_idUUIDusers.idPM
task_countINTEGERTask Count

project_tasks ??Tasks

FieldTypeFKDescription
nameVARCHARName
stateVARCHAR01_in_progress/1_done/1_canceled/04_waiting_normal/03_approved/02_changes_requested
priorityVARCHAR0 (Normal)/1 (Urgent)
descriptionTEXTDescription
date_deadlineDATEDeadline
project_idUUIDproject_projects.idProject
stage_idUUIDproject_task_types.idKanban Stage
parent_idUUIDproject_tasks.idParent Task
planned_hoursFLOATPlanned Hours
effective_hoursFLOATEffective Hours
progressFLOATProgress %

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

FieldTypeDescription
nameVARCHARName
codeVARCHAR(2)ISO 3166-1 alpha-2
phone_codeINTEGERInternational Phone Code
currency_idUUIDDefault Currency

currencies ??Currencies

FieldTypeDescription
nameVARCHAR(3)ISO 4217 (TWD, USD)
full_nameVARCHARFull Name
symbolVARCHAR(10)Symbol (NT$, $)
decimal_placesINTEGERDecimal Places

uom_uom ??Units of Measure

FieldTypeFKDescription
nameVARCHARName
category_idUUIDuom_categories.idCategory
uom_typeVARCHARreference/bigger/smaller
factorFLOATConversion Factor

Also includes country_states, currency_rates, languages, uom_categories, ir_sequences, etc.


7.13 Other Modules

Table NameDescription
analytic_accountsAnalytic Accounts
analytic_linesAnalytic Lines
utm_sourcesUTM Sources
utm_mediumsUTM Mediums
utm_campaignsUTM Campaigns
announcementsAnnouncements
file_nodesFile Nodes
purchase_stock_linksPurchase-Stock Links
sale_stock_linksSale-Stock Links
sale_purchase_linksSale-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 CodeDescription
200Success
201Created successfully
204Deleted successfully (No Content)
400Bad Request (e.g., invalid permission values, illegal filter columns)
401Unauthorized (API Key invalid or missing)
403Forbidden (Unreferencable table, unauthorized action, unpublished reference)
404Resource Not Found
409Conflict (e.g., subdomain in use, pending publish request exists)
422Unprocessable Entity (Validation failed)
429Too Many Requests (Rate limit exceeded)
500Internal Server Error

8.2 Common Error Messages

MessageCausePossible Solution
"App is not authorized to access table '{table}'"Reference for this table not createdIf 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 actionUpdate reference to include the required permission
"Unauthorized filter column: {col}"Query uses a field not authorized in columnsAdd the field to the reference
"This table is not referencable"The table is on the blacklistSystem core tables cannot be accessed
"API Key invalid or revoked"Key does not exist or has been disabledCreate a new API Key
"Data object does not exist"Custom Table's object_id or api_slug is incorrectCall GET /open/data/objects first to verify available Custom Tables
"Record does not exist"Custom Table's record_id is incorrect or deletedVerify 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_id is 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 MethodSimple QueryAdvanced 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

LimitationDescriptionAlternative
No OR conditionsFilters can only be ANDedUse search for multi-column OR searches, or split into multiple queries
No nested conditionsCannot express (A AND B) OR CSplit into multiple queries and merge at the application layer
No JOINsCan only query a single tableQuery two tables separately and associate them at the application layer
No aggregation functionsNo SUM / AVG / GROUP BYQuery raw data and compute at the application layer
No BETWEENNo between operatorCombine gte + lte filters
No NOT INOnly in, no not_inQuery all and filter at the application layer
No NOT LIKEOnly like / ilikeQuery all and filter at the application layer
Single query limitlimit max is 500 (GET) or 1000 (Open Proxy GET)Iterate pagination using offset
No cursor paginationOnly limit + offsetFor massive data, pair with order_by and increment offset
No cross-tenant querytenant_id is forcibly injectedThis is a security design; no alternative exists

9.4 Filter Field Validation Rules Summary

Validation ItemCheck LogicFailure Return
Field Name FormatMust match ^[a-zA-Z_][a-zA-Z0-9_]*$400 Illegal field name
Field AuthorizationMust be in allowed_columns list (id is always allowed)400 Unauthorized filter column
Operator LegalityMust be one of the 11 whitelisted operators400 Unsupported operator
in Operator Typevalue must be an array400 Value for 'in' operator must be an array
select_columns AuthSelected fields must be in allowed_columns400 Unauthorized column
Order By FieldsFields not in the whitelist are silently ignoredFalls 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 a 400 / 500 error.
  • [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

TableFieldConstraintAccepted ValuesDescription
customerscustomer_type[DB]company, individualCompany / Individual
customersstatus[DB]active, suspendedActive / Suspended

10.2 Supplier Module

TableFieldConstraintAccepted ValuesDescription
supplierssupplier_type[DB]company, individualCompany / Individual
suppliersstatus[DB]active, suspendedActive / Suspended

10.3 Product Module

TableFieldConstraintAccepted ValuesDescription
product_categoriesproperty_valuation[Suggested]periodic, real_timePeriodic / Real-time (Perpetual Inventory)
product_categoriesproperty_cost_method[Suggested]standard, fifo, averageStandard Cost / FIFO / Weighted Average
product_templatestype[DB]consu, service, comboConsumable / Service / Combo Product
product_templatesinvoice_policy[DB]order, deliveryInvoice on Order / Invoice on Delivery
product_templatesservice_type[DB]manual, timesheetManual / Based on Timesheet
product_templatesexpense_policy[DB]no, cost, sales_priceNon-reimbursable / At Cost / At Sales Price
product_price_tiersprice_type[DB]fixed, marketFixed Pricing / Market Pricing

10.4 Sales Module

TableFieldConstraintAccepted ValuesDescription
sale_ordersstate[DB]draft, sent, sale, done, cancelDraft ??Quotation Sent ??Sales Order ??Done ??Cancelled
sale_ordersinvoice_status[DB]no, to_invoice, invoicedNothing to Invoice / To Invoice / Invoiced
sale_orderstax_type[Suggested]tax_included, tax_excluded, tax_exempt, zero_rateTax Included / Tax Excluded / Tax Exempt / Zero Rate
sale_ordersinvoice_format[Suggested]duplicate, triplicate, noneDuplicate / Triplicate / None
sale_orderscarrier_type[Suggested]barcode, citizen_digital, mobile, noneBarcode Carrier / Citizen Digital Cert / Mobile Barcode / None
sale_ordersdelivery_method[Suggested]pickup, delivery, mail, freightPickup / Delivery / Mail / Freight
sale_order_linesinvoice_status[DB]no, to_invoice, invoicedNothing to Invoice / To Invoice / Invoiced
sale_order_linesdisplay_type[DB]line_section, line_noteSection Header / Note Line
sale_order_template_linesdisplay_type[Suggested]line_section, line_noteSection Header / Note Line

10.5 Procurement Module

TableFieldConstraintAccepted ValuesDescription
purchase_ordersstate[DB]draft, sent, purchase, done, cancelDraft ??RFQ Sent ??Purchase Order ??Done ??Cancelled
purchase_ordersinvoice_status[DB]no, to_invoice, invoicedNothing to Invoice / To Invoice / Invoiced
purchase_orderstax_type[Suggested]tax_included, tax_excluded, tax_exempt, zero_rateTax Included / Tax Excluded / Tax Exempt / Zero Rate
purchase_requisitionsstate[DB]draft, ongoing, in_progress, open, done, cancelDraft ??Ongoing ??In Progress ??Open ??Done ??Cancelled
purchase_requisitionsrequisition_type[DB]purchase, blanket_orderPurchase Agreement / Blanket Order

10.6 Accounting Module

TableFieldConstraintAccepted ValuesDescription
account_movesmove_type[DB]entry, out_invoice, out_refund, in_invoice, in_refund, out_receipt, in_receiptJournal Entry / Customer Invoice / Customer Credit Note / Vendor Bill / Vendor Refund / Sales Receipt / Purchase Receipt
account_movesstate[DB]draft, posted, cancelDraft / Posted / Cancelled
account_movespayment_state[DB]not_paid, partial, paid, reversed, invoicing_legacy, in_paymentNot Paid / Partial / Paid / Reversed / Legacy / In Payment
account_movesjournal_type[Suggested]sale, purchase, cash, bank, generalSales / Purchase / Cash / Bank / General
account_movesvoucher_type[Suggested]general, cash, transfer, bankGeneral / Cash / Transfer / Bank Voucher
account_movessettlement_status[Suggested]receivable, payable, provisional_receipt, provisional_payment, settledReceivable / Payable / Prov. Receipt / Prov. Payment / Settled
account_fiscal_yearsstate[DB]open, closedOpen / Closed
account_periodsstate[DB]open, closedOpen / Closed
account_lock_dateslock_date_field[DB]fiscalyear_lock_date, tax_lock_date, sale_lock_date, purchase_lock_dateGlobal Lock / Tax Lock / Sales Lock / Purchase Lock
account_lock_datesstate[DB]active, revoked, expiredActive / Revoked / Expired
account_reportsreport_type[DB]general_ledger, balance_sheet, profit_loss, cash_flow, aged_receivable, aged_payable, tax_report, partner_ledger, trial_balanceGeneral Ledger / Balance Sheet / P&L / Cash Flow / Aged Receivable / Aged Payable / Tax Report / Partner Ledger / Trial Balance
account_report_linesexpression_engine[DB]domain, account_codes, aggregation, tax_tags, customDomain Filter / Account Codes / Aggregation / Tax Tags / Custom
account_paymentspayment_type[Suggested]inbound, outboundInbound / Outbound
account_paymentspartner_type[Suggested]customer, supplierCustomer / Supplier

10.7 Inventory Module

TableFieldConstraintAccepted ValuesDescription
stock_warehousesreception_steps[DB]one_step, two_steps, three_steps1 Step / 2 Steps / 3 Steps (Receipt)
stock_warehousesdelivery_steps[DB]ship_only, pick_ship, pick_pack_shipShip Only / Pick+Ship / Pick+Pack+Ship
stock_locationsusage[DB]supplier, view, internal, customer, inventory, production, transitSupplier / View / Internal / Customer / Inventory / Production / Transit
stock_picking_typescode[DB]incoming, outgoing, internal, mrp_operationReceipt / Delivery / Internal Transfer / Manufacturing
stock_pickingsstate[DB]draft, waiting, confirmed, assigned, done, cancelDraft / Waiting / Confirmed / Assigned / Done / Cancelled
stock_pickingspriority[DB]0, 1Normal / Urgent
stock_movesstate[DB]draft, waiting, confirmed, partially_available, assigned, done, cancelDraft / Waiting / Confirmed / Partially Available / Assigned / Done / Cancelled
stock_movesprocure_method[DB]make_to_stock, make_to_orderMake to Stock / Make to Order (MTO)
stock_move_linesstate[Suggested]draft, assigned, done, cancelDraft / Assigned / Done / Cancelled
stock_rulesaction[DB]pull, push, pull_push, buy, manufacturePull / Push / Pull & Push / Buy / Manufacture
stock_rulesprocure_method[DB]make_to_stock, make_to_orderMake to Stock / Make to Order
stock_scrapsstate[DB]draft, doneDraft / Done
stock_scrapsscrap_reason[Suggested]damaged, expired, quality, otherDamaged / Expired / Quality / Other
stock_storage_categoriesallow_new_product[DB]empty, same, mixedEmpty Only / Same Product / Mixed
stock_landed_costsstate[DB]draft, done, cancelDraft / Done / Cancelled
stock_landed_cost_linessplit_method[DB]equal, by_quantity, by_current_cost_price, by_weight, by_volumeEqual / By Quantity / By Cost / By Weight / By Volume
stock_picking_batchesstate[DB]draft, in_progress, done, cancelDraft / In Progress / Done / Cancelled
delivery_carriersdelivery_type[DB]fixed, base_on_ruleFixed Price / Rule Based
inventory_check_batchesstate[DB]draft, doneDraft / Done
inventory_convertsstate[DB]draft, doneDraft / Done
freight_groupsmode[DB]fixed, tiered, freeFixed / Tiered / Free Shipping

10.8 CRM Module

TableFieldConstraintAccepted ValuesDescription
crm_leadstype[DB]lead, opportunityLead / Opportunity
crm_leadspriority[DB]0, 1, 2, 3Normal / 1 Star / 2 Stars / 3 Stars
crm_activitiesactivity_type[DB]email, call, meeting, todoEmail / Call / Meeting / To-Do
crm_activitiesstate[DB]planned, done, overdue, cancelledPlanned / Done / Overdue / Cancelled

10.9 HR Human Resources Module

TableFieldConstraintAccepted ValuesDescription
hr_employeesemployee_type[Suggested]employee, student, trainee, contractor, freelanceEmployee / Student / Trainee / Contractor / Freelance
hr_employeesgender[Suggested]male, female, otherMale / Female / Other
hr_employeesmarital[Suggested]single, married, cohabitant, widower, divorcedSingle / Married / Cohabitant / Widower / Divorced
hr_employeeshr_presence_state[Suggested]present, absent, to_definePresent / Absent / To Define
hr_work_locationslocation_type[DB]home, office, otherHome / Office / Other
hr_leave_typesrequires_allocation[Suggested]yes, noRequires Allocation / Does Not Require
hr_leave_typesleave_validation_type[Suggested]no_validation, hr, manager, bothNo Validation / HR / Manager / Both
hr_leave_typestime_type[Suggested]leave, otherTime Off / Other
hr_leave_typesrequest_unit[Suggested]day, half_day, hourDay / Half Day / Hour
hr_leavesstate[DB]draft, confirm, refuse, validate1, validate, cancelDraft / Confirmed / Refused / Approved (L1) / Approved / Cancelled
hr_leavesholiday_type[Suggested]employee, company, department, categoryEmployee / Company / Department / Category
hr_leave_allocationsstate[Suggested]draft, confirm, validate1, validate, refuseDraft / Confirmed / Approved (L1) / Approved / Refused
hr_leave_allocationsallocation_type[Suggested]regular, accrualRegular / Accrual
hr_expense_sheetsstate[DB]draft, submit, approve, post, done, cancelDraft / Submitted / Approved / Posted / Done / Cancelled
hr_expense_sheetspayment_state[Suggested]not_paid, in_payment, paidNot Paid / In Payment / Paid
hr_expensesstate[DB]draft, reported, approved, done, refusedDraft / Reported / Approved / Done / Refused
hr_expensespayment_mode[Suggested]own_account, company_accountEmployee (to reimburse) / Company Account
hr_work_entriesstate[DB]draft, validated, conflict, cancelledDraft / Validated / Conflict / Cancelled

10.10 MRP Manufacturing Module

TableFieldConstraintAccepted ValuesDescription
mrp_bomstype[DB]normal, phantom, subcontractingNormal / Phantom / Subcontracting
mrp_bomsready_to_produce[DB]all_available, asapWhen all components available / ASAP
mrp_routing_workcenterstime_mode[DB]auto, manualAuto / Manual
mrp_productionsstate[DB]draft, confirmed, progress, to_close, done, cancelDraft / Confirmed / In Progress / To Close / Done / Cancelled
mrp_productionspriority[DB]0, 1Normal / Urgent
mrp_workordersstate[DB]pending, waiting, ready, progress, done, cancelPending / Waiting / Ready / In Progress / Done / Cancelled
mrp_unbuildsstate[DB]draft, doneDraft / Done

10.11 Project Management Module

TableFieldConstraintAccepted ValuesDescription
project_projectsprivacy_visibility[DB]portal, employees, followersPortal / Employees / Followers Only
project_tasksstate[DB]01_in_progress, 1_done, 1_canceled, 04_waiting_normal, 03_approved, 02_changes_requestedIn Progress / Done / Cancelled / Waiting / Approved / Changes Requested
project_taskskanban_state[DB]normal, done, blockedNormal / Ready / Blocked
project_taskspriority[DB]0, 1Normal / Urgent
project_task_recurrencesrepeat_unit[DB]day, week, month, yearDay / Week / Month / Year
project_task_recurrencesrepeat_type[DB]forever, until, afterForever / Until Date / After count
project_updatesstatus[DB]on_track, at_risk, off_track, on_hold, doneOn Track / At Risk / Off Track / On Hold / Done

10.12 Announcement Module

TableFieldConstraintAccepted ValuesDescription
announcementspriority[Suggested]normal, high, urgentNormal / High / Urgent
announcementsannouncement_type[Suggested]bulletin, pushBulletin / Push Notification
announcementssend_mode[Suggested]immediate, scheduledImmediate / Scheduled
announcementssend_status[Suggested]draft, pending, sent, failedDraft / Pending / Sent / Failed
announcementstarget_type[Suggested]all, tag, levelAll / Tag / Level
announcementsvalidity_type[Suggested]permanent, limitedPermanent / Limited Time

10.13 Fixed Asset Module

TableFieldConstraintAccepted ValuesDescription
fixed_assetsstate[DB]draft, running, fully_depreciated, disposed, closedDraft / Running / Fully Depreciated / Disposed / Closed
fixed_assetsdepreciation_method[DB]straight_line, declining_balance, sum_of_yearsStraight Line / Declining Balance / Sum of Years
fixed_asset_depreciationsstatus[DB]draft, postedDraft / Posted

10.14 Finance/Bank Module

TableFieldConstraintAccepted ValuesDescription
partner_banksaccount_type[DB]bank, ibanBank / IBAN
partner_bankspartner_type[DB]customer, supplier, member, tenantCustomer / Supplier / Member / Tenant

10.15 Core Reference Tables

TableFieldConstraintAccepted ValuesDescription
uom_uomuom_type[DB]reference, bigger, smallerReference / Bigger / Smaller
countriesname_position[Suggested]before, afterName Before / Name After
currenciesposition[Suggested]before, afterSymbol Before / Symbol After
languagesdirection[Suggested]ltr, rtlLeft-to-Right / Right-to-Left
ir_sequencesimplementation[DB]standard, no_gapStandard (allows gaps) / No Gap

10.16 System Management Module

TableFieldConstraintAccepted ValuesDescription
custom_appsaccess_mode[Suggested]internal, external, self_builtInternal / External / Self-Built

Usage Tips:

  • When querying via filters, use the eq operator for precise matching on enum fields, e.g., {"column": "state", "op": "eq", "value": "draft"}.
  • To query multiple enum values, use the in operator, 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 / 500 error 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_domain filter or default field in create and list operations 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 ilike queries to fail.

Recommended Strategies:

  • String Query Characteristics: AI GO stores custom_data in JSONB format within the database. When using the Open Proxy API (like the /query endpoint) to perform ilike filters, 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%'

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 Delete reference permission, if you trigger an underlying safeguard (e.g., unable to delete lines from a paid order), the API will return a 403 Forbidden error. 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_data of 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, and AIGO_API_KEY in .env.production or 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.