Momen Runtime API Reference
This document describes the runtime GraphQL API structure for Momen projects. Use it when debugging, integrating external systems, building code components, or connecting custom frontends.
Momen exposes a single GraphQL endpoint. Database access, Actionflow invocation, AI Agent sessions, and external API calls are expressed as query, mutation, or subscription operations with different root fields, arguments, and return shapes.
API endpoints
HTTP GraphQL
https://villa.momen.app/zero/{projectExId}/api/graphql-v2| Parameter | Description |
|---|---|
projectExId | Unique identifier of your Momen project |
Request body uses standard GraphQL JSON:
{
"query": "mutation CreateBlog($object: blog_insert_input!) { insert_blog_one(object: $object) { id } }",
"operationName": "CreateBlog",
"variables": {
"object": {
"title": "My first post"
}
}
}WebSocket subscription
wss://villa.momen.app/zero/{projectExId}/api/graphql-subscriptionSubscriptions are used for async Actionflow tasks, streaming AI results, and live data updates.
Authentication
Pass JWT in the Authorization header:
Authorization: Bearer <jwt>Without a JWT, requests run as anonymous/guest. With a JWT, the backend resolves account, roles, and permissions before database, Actionflow, AI, or external API execution.
Obtain JWT via login. Username/password example:
mutation AuthenticateWithUsername($username: String!, $password: String!, $register: Boolean!) {
authenticateWithUsername(username: $username, password: $password, register: $register) {
account {
id
permissionRoles
}
jwt {
token
}
}
}register: true registers and logs in; false logs in only. Use jwt.token as the Bearer token.
Request and response shape
GraphQL operations are query, mutation, or subscription.
See the GraphQL documentation for general GraphQL concepts.
| Type | Purpose | Typical Momen use |
|---|---|---|
query | Read data | Table queries, async task status, read-only external APIs |
mutation | Write or trigger | CRUD, Actionflows, AI session create/send, external APIs |
subscription | Listen for changes | DB changes, Actionflow async results, AI streaming |
Success returns data. Errors return an errors array:
{
"data": null,
"errors": [
{
"message": "permission denied",
"path": ["insert_blog_one"]
}
]
}Only requested fields are returned. For writes, id is available for downstream references.
Database operations
Momen generates GraphQL fields from your data model. Examples use table names blog, goods, order.
Field type mapping
| Momen type | GraphQL type | Notes |
|---|---|---|
| Text | String | Text |
| Big integer | bigint | Often used for ids |
| Decimal | Decimal | High-precision numbers |
| Boolean | Boolean | true / false |
| JSONB | jsonb | JSON object |
| DateTime (with timezone) | timestamptz | Date and time |
| Time (with timezone) | timetz | Time of day |
| Date | date | Calendar date |
| Geo point | geography | Location |
| Image | FZ_Image | Image asset |
| Video | FZ_Video | Video asset |
| File | FZ_File | File asset |
Media fields in inputs use resource ids: {field_name}_id for single assets, {field_name}_ids for arrays (e.g. cover_image_id).
Query data
Use query operations.
Root fields and parameters
The root field is the top-level entry (e.g. blog for the blog table):
query {
blog(where: {...}, limit: 10) {
id
title
}
}| Field pattern | Description |
|---|---|
{table_name} | List query with where, order_by, limit, offset |
{table_name}_by_pk | Single row by primary key |
{table_name}_aggregate | Aggregation with nodes and aggregate |
{table_name}_group_by | Group by with having, where, order_by, etc. |
fz_{table_name}_by_{column_name} | Geo distance queries |
Common parameters
| Parameter | Description |
|---|---|
where | Filter ({table_name}_bool_exp) |
order_by | Sort (field, relation, aggregate) |
distinct_on | Distinct on columns |
limit | Max rows |
offset | Skip rows (pagination) |
where filter syntax
Logical operators
| Operator | Meaning |
|---|---|
_and | All conditions |
_or | Any condition |
_not | Negation |
Comparison operators
| Operator | Meaning |
|---|---|
_eq / _neq | Equal / not equal |
_gt / _gte | Greater / greater or equal |
_lt / _lte | Less / less or equal |
_in / _nin | In set / not in set |
_like / _ilike | Pattern / case-insensitive pattern |
_is_null | Null check |
Relation filters nest along relations:
{
"where": {
"author": {
"name": {
"_eq": "Alex"
}
}
}
}Operator-first syntax
For expressions like EXTRACT(MONTH FROM created_at) = 12, use operator-first form: operator first, left_operand (functions/columns), right_operand (literal).
Query:
query QueryAccountList($where: account_bool_exp) {
account(where: $where) {
id
username
created_at
}
}Variables:
{
"where": {
"_eq": {
"bigint_operand": {
"left_operand": {
"extract_timestamptz": {
"time": { "column": "created_at" },
"unit": "MONTH"
}
},
"right_operand": { "literal": "12" }
}
}
}
}Query examples
List
query QueryBlogList($where: blog_bool_exp, $limit: Int, $offset: Int) {
blog(where: $where, order_by: { id: desc }, limit: $limit, offset: $offset) {
id
title
author_id
}
}{
"where": {
"_and": [
{ "author_id": { "_eq": 10001 } },
{ "title": { "_ilike": "%Momen%" } }
]
},
"limit": 20,
"offset": 0
}By primary key
query QueryBlogByPk($id: bigint!) {
blog_by_pk(id: $id) {
id
title
content
}
}Aggregate
query QueryBlogAggregate($where: blog_bool_exp) {
blog_aggregate(where: $where) {
nodes {
id
title
}
aggregate {
count
max {
id
}
}
}
}Insert data
Use mutation.
| Field pattern | Description |
|---|---|
insert_{table_name}_one | Single insert |
insert_{table_name} | Batch insert |
| Parameter | Description |
|---|---|
object | Single row |
objects | Multiple rows |
on_conflict | Upsert / conflict policy |
Single insert
mutation($object: blog_insert_input!, $on_conflict: blog_on_conflict!) {
insert_blog_one(object: $object, on_conflict: $on_conflict) {
id
}
}{
"object": {
"title": "My first post",
"content": "Post body.",
"author_id": 10001
},
"on_conflict": {
"constraint": "unique_title",
"update_columns": []
}
}Empty update_columns skips on conflict; listing all columns updates the existing row.
Batch insert
mutation(
$objects: [blog_insert_input!]!,
$on_conflict: blog_on_conflict!
) {
insert_blog(objects: $objects, on_conflict: $on_conflict) {
returning {
id
}
}
}Update data
| Field pattern | Description |
|---|---|
update_{table_name} | Conditional batch update |
update_{table_name}_by_pk | Update by primary key |
| Parameter | Description |
|---|---|
where | Batch filter |
pk_columns | Primary key for single-row update |
_set | Set field values |
_inc | Atomic increment/decrement |
Batch update (stock decrement)
mutation update_goods($where: goods_bool_exp!, $inc: goods_inc_input) {
update_goods(where: $where, _inc: $inc) {
returning {
id
stock
}
}
}{
"where": {
"_and": [
{ "id": { "_eq": 10001 } },
{ "stock": { "_gte": 2 } }
]
},
"inc": {
"stock": -2
}
}By primary key
mutation UpdateGoodsByPk($pk_columns: goods_pk_columns_input!, $set: goods_set_input) {
update_goods_by_pk(pk_columns: $pk_columns, _set: $set) {
id
name
}
}Delete data
| Field pattern | Description |
|---|---|
delete_{table_name} | Batch delete |
delete_{table_name}_by_pk | Delete by primary key |
Batch delete
mutation($where: order_bool_exp!) {
delete_order(where: $where) {
returning {
id
}
}
}By primary key
mutation DeleteOrderByPk($id: bigint!) {
delete_order_by_pk(id: $id) {
id
}
}Transactions
Multiple mutations in one request run in a database transaction (all succeed or all roll back). Example: create order and decrement stock:
mutation(
$objects_order: [order_insert_input!]!,
$on_conflict_order: order_on_conflict!,
$where_product: product_bool_exp!,
$inc_product: product_inc_input!
) {
step1_insert: insert_order(
objects: $objects_order,
on_conflict: $on_conflict_order
) {
returning {
id
}
}
step2_update: update_product(
where: $where_product,
_inc: $inc_product
) {
returning {
id
}
}
}Use aliases (step1_insert, step2_update) to distinguish results.
Actionflow invocation
Actionflows encapsulate multi-step backend logic. Sync and async patterns use mutation to start and query / subscription for async results.
| Field | Type | Description |
|---|---|---|
fz_invoke_action_flow | mutation | Sync invoke; returns output in same response |
fz_invoke_action_flow_default_by_latest_version | mutation | Sync invoke default/latest version |
fz_create_action_flow_task | mutation | Async task; returns taskId |
fz_listen_action_flow_result | subscription | Listen for task status/output |
fz_action_flow_result | query | Poll task result |
| Parameter | Description |
|---|---|
actionFlowId | Actionflow id |
versionId | Version (optional for latest) |
args | Input JSON |
taskId | Async task id |
Sync invoke
mutation InvokeActionFlow($actionFlowId: String!, $versionId: Int!, $args: Json!) {
fz_invoke_action_flow(actionFlowId: $actionFlowId, versionId: $versionId, args: $args)
}Async: create task
mutation CreateActionFlowTask($actionFlowId: String!, $versionId: Int, $args: Json!) {
fz_create_action_flow_task(actionFlowId: $actionFlowId, versionId: $versionId, args: $args)
}Listen (subscription)
subscription ListenActionFlowTask($taskId: Long!) {
fz_listen_action_flow_result(taskId: $taskId) {
status
output
}
}| Field | Type | Description |
|---|---|---|
status | TaskStatus | CREATED, PROCESSING, COMPLETED, FAILED, STREAMING, TIME_OUT |
output | Json | Actionflow output node data |
AI Agent invocation
AI Agents use mutation to start and subscription for streaming results.
Media inputs use {name}_id or {name}_ids (e.g. video_id).
| Field | Type | Description |
|---|---|---|
fz_zai_create_conversation | mutation | Create conversation |
fz_zai_listen_conversation_result | subscription | Stream/final result |
fz_zai_send_ai_message | mutation | Continue conversation |
fz_zai_stop_responding | mutation | Stop generation |
fz_zai_delete_conversation | mutation | Delete conversation |
Create and listen
mutation ZAICreateConversation($inputArgs: Map_String_ObjectScalar!, $zaiConfigId: String!) {
fz_zai_create_conversation(inputArgs: $inputArgs, zaiConfigId: $zaiConfigId)
}subscription ListenZAIConversation($conversationId: Long!) {
fz_zai_listen_conversation_result(conversationId: $conversationId) {
conversationId
status
data
reasoningContent
images {
id
url
}
}
}Streaming:
STREAMINGpushes partial text; finalCOMPLETEDincludes fulldata. Structured output returns once onCOMPLETED. Image models populateimages.
Send message / stop / delete
mutation ZAISendAiMessage(
$conversationId: Long!,
$text: String,
$imageIds: [Long],
$fileId: Long,
$videoId: Long
) {
fz_zai_send_ai_message(
conversationId: $conversationId,
text: $text,
imageIds: $imageIds,
fileId: $fileId,
videoId: $videoId
)
}External API invocation
Imported APIs are exposed as GraphQL fields (query or mutation per configuration).
| Field pattern | Description |
|---|---|
operation_{thirdPartyApiId} | Legacy OpenAPI import |
fz_api_{apiId} | API Workspace |
| Parameter | Description |
|---|---|
fz_body | Legacy request body |
Authorization | Legacy auth header |
input | API Workspace input type |
External APIs configured only inside Actionflows are not directly exposed to the client; the client calls the Actionflow instead. Non-2xx responses fail the Actionflow node.
Legacy third-party API
mutation CreateCalendarEvent(
$summary: String,
$location: String,
$authorization: String
) {
operation_create_calendar_event(
fz_body: {
summary: $summary,
location: $location
},
Authorization: $authorization
) {
responseCode
field_200_json {
id
status
htmlLink
}
}
}Check responseCode; field_200_json may be empty on 4xx/5xx.
API Workspace
mutation CallApi($input: fz_api_create_order_input!) {
fz_api_create_order(input: $input) {
responseCode
responseStatus
responseContentType
fz_api_create_order_response {
order_id
status
}
}
}