GraphQL
The GraphQL API allows you to query and manipulate your database data using a dynamically generated schema. Each table in your schema is automatically mapped to GraphQL types, queries, and mutations.
Endpoint and Authentication
HTTP
The HTTP endpoint is schema-specific (see Schemas for more information):
POST https://api.centia.io/api/graphql/schema/{schema_name}
Authentication is handled via a Bearer token in the Authorization header (see OAuth for more information).
POST https://api.centia.io/api/graphql/schema/public
Authorization: Bearer <your_token>
Content-Type: application/json
{
"query": "query { ... }"
}
WebSocket
All GraphQL operations — queries, mutations, and subscriptions — are also available over WebSocket:
wss://event.centia.io?token=<your_token>
Send operations as JSON messages with type, schema, and query:
{
"type": "subscribe",
"id": "q1",
"schema": "public",
"query": "query { getArtists { artist_id legal_name } }"
}
This works identically for mutations:
{
"type": "subscribe",
"id": "m1",
"schema": "public",
"query": "mutation { insertArtists(objects: [{ legal_name: \"Jane Doe\" }]) { artist_id } }"
}
Introspection
You can use standard GraphQL introspection to explore the available types and fields. This is useful for tools like GraphiQL or Apollo Studio.
query {
__schema {
types {
name
}
}
}
Queries
For every table in your database, the API provides a query field named get[TableName] (in camelCase).
Basic Query
To fetch records from a table named artists:
POST https://api.centia.io/api/graphql/schema/public
Content-Type: application/json
Authorization: Bearer <your_token>
{
"query": "query { getArtists { artist_id legal_name } }"
}
Filtering
The where argument supports complex filtering using logical and comparison operators. Simple equality filters are also supported.
Simple Equality:
{ getArtists(where: { artist_id: 1 }) { legal_name } }
Supported Operators:
eq: Equalneq: Not equalgt: Greater thangte: Greater than or equallt: Less thanlte: Less than or equalin: Included in arraylike: Case-sensitive pattern matchilike: Case-insensitive pattern match
Logical Operators:
and: Logical ANDor: Logical ORnot: Logical NOT
POST https://api.centia.io/api/graphql/schema/public
Content-Type: application/json
Authorization: Bearer <your_token>
{
"query": "query { getArtists(where: { and: [ { legal_name: { ilike: \"%Linus%\" } }, { instrument: { eq: \"guitar\" } } ] }) { legal_name instrument } }"
}
Pagination
Use limit and offset for pagination.
POST https://api.centia.io/api/graphql/schema/public
Content-Type: application/json
Authorization: Bearer <your_token>
{
"query": "query { getArtists(limit: 10, offset: 20) { artist_id legal_name } }"
}
Relationships
If there are foreign key constraints between tables, the GraphQL API automatically exposes them as nested fields.
POST https://api.centia.io/api/graphql/schema/public
Content-Type: application/json
Authorization: Bearer <your_token>
{
"query": "query { getAlbums { title bands { name subgenre } } }"
}
Mutations
The API provides insert, update, and delete mutations for each table.
Insert
Use insert[TableName] to add new records. You can provide a single record via data or multiple records via objects.
POST https://api.centia.io/api/graphql/schema/public
Content-Type: application/json
Authorization: Bearer <your_token>
{
"query": "mutation { insertArtists(objects: [{ legal_name: \"John Doe\", instrument: \"Piano\" }]) { artist_id legal_name } }"
}
Update
Use update[TableName] to modify existing records. Use the where argument to specify which records to update and data for the new values.
POST https://api.centia.io/api/graphql/schema/public
Content-Type: application/json
Authorization: Bearer <your_token>
{
"query": "mutation { updateArtists(where: { artist_id: { eq: 1 } }, data: { instrument: \"Electric Guitar\" }) { artist_id instrument } }"
}
Delete
Use delete[TableName] to remove records.
POST https://api.centia.io/api/graphql/schema/public
Content-Type: application/json
Authorization: Bearer <your_token>
{
"query": "mutation { deleteArtists(where: { artist_id: { eq: 1 } }) { artist_id } }"
}
Subscriptions
Subscriptions let you receive real-time database change events (INSERT, UPDATE, DELETE) over the WebSocket connection using GraphQL syntax.
Subscribing
After connecting to the WebSocket (see WebSocket above), send a message to register a subscription:
{
"type": "subscribe",
"id": "sub1",
"schema": "public",
"query": "subscription { ArtistsMessageAdded { artist_id legal_name instrument } }"
}
The server responds with an acknowledgement:
{
"type": "subscribe_ack",
"id": "sub1"
}
Subscription Field Names
Each table gets three subscription fields following the pattern {TableName}Message{Event}:
{TableName}MessageAdded— triggered on INSERT{TableName}MessageUpdated— triggered on UPDATE{TableName}MessageDeleted— triggered on DELETE
The table name is in PascalCase, matching the same convention as queries and mutations.
Filtering
Use the where argument to only receive events matching specific conditions. The same JSON object syntax used in queries and mutations is supported:
{
"type": "subscribe",
"id": "sub2",
"schema": "public",
"query": "subscription { ArtistsMessageUpdated(where: {instrument: {eq: \"guitar\"}}) { artist_id legal_name instrument } }"
}
Supported operators:
eq,neq,gt,gte,lt,lte,in,like,ilike
Logical operators:
AND,OR,NOT
{
"type": "subscribe",
"id": "sub3",
"schema": "public",
"query": "subscription { ArtistsMessageAdded(where: {OR: [{instrument: {eq: \"guitar\"}}, {instrument: {eq: \"piano\"}}]}) { artist_id legal_name } }"
}
A SQL-style string syntax is also supported:
{
"type": "subscribe",
"id": "sub4",
"schema": "public",
"query": "subscription { ArtistsMessageAdded(where: \"instrument = 'guitar'\") { artist_id legal_name } }"
}
Subscription filtering only works with scalar column types (integer, float, boolean, string, etc.). Complex types such as geometric types, range types, and JSON are not supported in subscription where clauses.
Column Selection
The fields you select in the subscription body determine which columns are included in the event payload. Only matching columns are returned.
JavaScript Example
const ws = new WebSocket(
`wss://event.centia.io?token=${encodeURIComponent(token)}`
);
ws.onopen = () => {
// Query over WebSocket
ws.send(JSON.stringify({
type: "subscribe",
id: "q1",
schema: "public",
query: `query { getArtists { artist_id legal_name } }`
}));
// Subscribe to real-time events
ws.send(JSON.stringify({
type: "subscribe",
id: "sub1",
schema: "public",
query: `subscription {
ArtistsMessageAdded(where: {instrument: {eq: "guitar"}}) {
artist_id
legal_name
instrument
}
}`
}));
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log("Received:", data);
};
Data Types
The GraphQL API supports various PostgreSQL data types, mapping them to appropriate GraphQL types:
- Scalars:
integer,float,boolean,string,JSON,ID,Date,Time,DateTime. - Geometric Types:
Point,Line,Lseg,Box,Circle,Path,Polygon. - Range Types:
Int4range,Int8range,Numrange,Tsrange,Tstzrange,Daterange. - Arrays: Any type can be returned as a list (e.g.,
[String],[Int]).
Any complex types can be used as input arguments for mutations. Type hints are not required because the schemas are dynamically generated from the database relations.
Se also Types.
Consider a generated schema like this:
type Tours {
id: ID!
artist_name: String!
tour_name: String!
from_to: Daterange!
}
"""
Date is accepted in almost any reasonable format, including ISO 8601, SQL-compatible, traditional POSTGRES, and others.
"""
scalar Date
"""Range type for daterange, with lower and upper bounds of type Date."""
type Daterange {
lower: Date
upper: Date
lowerInclusive: Boolean
upperInclusive: Boolean
}
type Mutation {
insertTours(data: JSON, objects: [JSON]): [Tours]
updateTours(id: ID, where: JSON, data: JSON): [Tours]
deleteTours(id: ID, where: JSON): [Tours]
}
Then you can insert a new tour using the following mutation. The Daterange field is represented as JSON:
mutation InsertTours($data: JSON) {
insertTours(data: $data) {
id
from_to {
lower
upper
}
}
}
{
"data": {
"artist_name": "Guns n’ Roses",
"tour_name": "Europe: Summer 2026",
"from_to": {
"lower": "2010-04-06",
"upper": "2011-03-07",
"lowerInclusive": true,
"upperInclusive": true
}
}
}