Skip to content
Graphs Console Schema Reference API Keys Team Settings

Reference

Clauses

MATCH

Finds patterns in the graph. Variables are bound to matched nodes and relationships.

MATCH (n:Person {name: 'Alice'}) RETURN n
MATCH (a:Person)-[:FRIEND]->(b:Person) RETURN a, b

OPTIONAL MATCH

Like MATCH, but returns null for unmatched variables instead of eliminating the row.

MATCH (a:Person)
OPTIONAL MATCH (a)-[:FRIEND]->(b)
RETURN a.name, b.name

WHERE

Filters results. Used after MATCH or WITH.

MATCH (n:Person) WHERE n.age > 30 RETURN n
MATCH (n:Person) WHERE n.name STARTS WITH 'A' AND n.age >= 25 RETURN n

RETURN

Projects output columns. Supports aliases, DISTINCT, and * for all variables.

MATCH (n:Person) RETURN n.name AS personName
MATCH (n:Person) RETURN DISTINCT n.city
MATCH (n:Person) RETURN *

WITH

Pipes intermediate results between query parts. Same syntax as RETURN.

MATCH (n:Person)
WITH n.name AS name, n.age AS age WHERE age > 30
RETURN name

ORDER BY / SKIP / LIMIT

Sorting and pagination. SKIP and LIMIT accept integers or $parameter refs.

MATCH (n:Person) RETURN n.name ORDER BY n.age DESC
MATCH (n:Person) RETURN n SKIP 5 LIMIT 10

CREATE

Creates nodes and relationships.

CREATE (n:Person {name: 'Alice', age: 30})
CREATE (a)-[:FRIEND {since: 2020}]->(b)

MERGE

Match-or-create. Finds the pattern if it exists, creates it if not.

MERGE (p:Person {name: 'Alice'})
  ON CREATE SET p.created = timestamp()
  ON MATCH SET p.lastSeen = timestamp()

SET

Updates properties on nodes or relationships.

MATCH (n:Person {name: 'Alice'}) SET n.age = 31
MATCH (n:Person {name: 'Alice'}) SET n += {city: 'NYC'}

DELETE / DETACH DELETE

Removes nodes and relationships. DETACH DELETE also removes connected edges.

MATCH (n:Person {name: 'Alice'}) DELETE n
MATCH (n:Person {name: 'Alice'}) DETACH DELETE n

REMOVE

Removes properties from nodes.

MATCH (n:Person) REMOVE n.age

UNWIND

Expands a list into individual rows.

UNWIND [1, 2, 3] AS x RETURN x
UNWIND [{name: 'Alice'}, {name: 'Bob'}] AS props
CREATE (p:Person) SET p.name = props.name

FOREACH

Iterates over a list and executes mutation clauses per element.

MATCH (a:Person {name: 'Alice'})
FOREACH (name IN ['Bob', 'Carol'] |
  CREATE (a)-[:FRIEND]->(:Person {name: name})
)

CALL { subquery }

Runs a subquery for each incoming row.

MATCH (p:Person)
CALL {
  WITH p
  MATCH (p)-[:FRIEND]->(f)
  RETURN count(f) AS friendCount
}
RETURN p.name, friendCount

UNION / UNION ALL

Combines results from multiple queries. UNION deduplicates; UNION ALL keeps all.

MATCH (a:Person) RETURN a.name AS name
UNION
MATCH (b:Company) RETURN b.name AS name

CREATE INDEX / DROP INDEX

CREATE INDEX ON :Person(name)
DROP INDEX ON :Person(name)

Patterns

Node Patterns

()                                -- anonymous node
(n)                               -- bound to variable n
(n:Person)                       -- with label
(n:Person:Employee)              -- multiple labels
(n:Person {name: 'Alice'})      -- with property filter

Relationship Patterns

-[r:FRIEND]->                    -- outgoing, typed
<-[r:FRIEND]-                    -- incoming, typed
-[r:FRIEND]-                     -- undirected
-->                               -- outgoing shorthand
<--                               -- incoming shorthand
--                                -- undirected shorthand
-[:FRIEND|COWORKER]->           -- type alternation
-[r:FRIEND {since: 2020}]->    -- with property filter

Variable-Length Paths

-[*1..3]->     -- 1 to 3 hops
-[*2]->        -- exactly 2 hops
-[*]->         -- 1 to 10 hops (default)
-[:FRIEND*1..5]->  -- typed variable-length

Maximum depth is capped at 10.

Named Paths

p = (a:Person)-[:FRIEND*1..3]->(b:Person)
RETURN p, nodes(p), relationships(p)

The path variable is an array of alternating [node, edge, node, edge, ...].

shortestPath / allShortestPaths

-- Find the shortest path between two nodes
MATCH p = shortestPath((a:Person {name:'Alice'})-[*]-(b:Person {name:'Charlie'}))
RETURN p, length(p)

-- Find all shortest paths (all paths at minimum depth)
MATCH p = allShortestPaths((a:Person)-[*]-(b:Person))
RETURN p

Uses BFS to find the shortest path(s). Supports typed relationships and property filters. Maximum depth defaults to 15.

Expressions

Literals

42                  -- integer
3.14                -- float
'hello'             -- string
true / false        -- boolean
null                -- null
[1, 2, 3]           -- list
{name: 'Alice'}     -- map

CASE Expression

Generic form:

CASE
  WHEN n.age > 30 THEN 'senior'
  WHEN n.age > 20 THEN 'junior'
  ELSE 'unknown'
END

Simple form:

CASE n.status
  WHEN 'active' THEN 1
  WHEN 'inactive' THEN 0
  ELSE -1
END

List Indexing & Slicing

list[0]        -- first element
list[-1]       -- last element
list[1..3]     -- slice (exclusive end)

Out-of-bounds access returns null.

List Comprehension

[x IN [1,2,3,4,5] WHERE x > 2 | x * 10]   -- [30, 40, 50]
[x IN range(1, 5) | x * x]                  -- [1, 4, 9, 16, 25]

Pattern Comprehension

-- Inline pattern matching that returns a list
MATCH (a:Person)
RETURN [(a)-[:FRIEND]->(f) | f.name] AS friends

-- With WHERE filter
MATCH (a:Person)
RETURN [(a)-[:FRIEND]->(f) WHERE f.age > 25 | f.name] AS olderFriends

Evaluates a pattern inline per row and returns a list of projected values.

Map Projection

-- Select specific properties from a node
MATCH (n:Person)
RETURN n { .name, .age } AS person

-- Mix shorthand and computed properties
MATCH (n:Person)
RETURN n { .name, upperName: toUpper(n.name) } AS person

Creates a map from selected properties. Shorthand .prop reads from the object; explicit key: expr evaluates an expression.

EXISTS Subquery

MATCH (n:Person)
WHERE exists { MATCH (n)-[:FRIEND]->() }
RETURN n

Parameters

Query parameters use $name syntax and are resolved from the execution context.

MATCH (n:Person {name: $name}) RETURN n
MATCH (n:Person) RETURN n LIMIT $limit

Operators

Comparison

=Equal
<> !=Not equal
< > <= >=Ordering

Boolean

ANDLogical and
ORLogical or
XORExclusive or
NOTNegation

Arithmetic

+ - * / %Standard math
^Power
+String concatenation

String

STARTS WITHPrefix match
ENDS WITHSuffix match
CONTAINSSubstring match
=~Regex (full-string, JS syntax)

Null & List

IS NULLNull check
IS NOT NULLNon-null check
INList membership

Aggregate Functions

Aggregate functions group rows and reduce them. All support DISTINCT: count(DISTINCT x).

FunctionDescription
count(expr) / count(*)Count values or rows
collect(expr)Collect into a list
sum(expr)Sum numeric values
avg(expr)Average
min(expr) / max(expr)Min / max
stdev(expr) / stdevp(expr)Sample / population std dev
percentileCont(expr, pct)Continuous percentile
percentileDisc(expr, pct)Discrete percentile

String Functions

FunctionDescription
toLower(str) / toUpper(str)Case conversion
trim(str) / ltrim(str) / rtrim(str)Whitespace trimming
replace(str, search, repl)Replace all occurrences
substring(str, start, len?)Extract substring
left(str, n) / right(str, n)First / last n chars
split(str, delim)Split into list
reverse(str)Reverse
toString(val)Convert to string

Math Functions

FunctionDescription
abs(x)Absolute value
round(x) / floor(x) / ceil(x)Rounding
sign(x)Sign (-1, 0, 1)
sqrt(x)Square root
log(x) / log10(x)Logarithm
exp(x)e^x
rand()Random [0, 1)
FunctionDescription
sin cos tanTrigonometric
asin acos atan atan2Inverse trig
degrees(x) / radians(x)Angle conversion
pi() / e()Constants

List Functions

FunctionDescription
head(list) / last(list)First / last element
tail(list)All except first
size(list)Length (also strings)
range(start, end, step?)Integer list (inclusive)
reverse(list)Reverse
coalesce(a, b, ...)First non-null

Type Functions

FunctionDescription
toInteger(val) / toFloat(val) / toBoolean(val)Type conversion
toStringOrNull / toIntegerOrNull / toFloatOrNull / toBooleanOrNullNull-safe conversion
valueType(val)Type name string

Graph Functions

FunctionDescription
id(entity)Internal ID
labels(node)List of labels
type(rel)Relationship type
properties(entity) / keys(entity)Property map / keys
startNode(rel) / endNode(rel)Source / target node
nodes(path) / relationships(path)Extract from path
length(path)Path or list length
timestamp()Epoch milliseconds

Examples

Build a social network

CREATE (alice:Person {name: 'Alice', age: 30})
CREATE (bob:Person {name: 'Bob', age: 25})

MATCH (a:Person {name: 'Alice'}), (b:Person {name: 'Bob'})
CREATE (a)-[:FRIEND {since: 2020}]->(b)

Aggregation with grouping

MATCH (p:Person)-[:FRIEND]->(f)
RETURN p.name, count(f) AS friends ORDER BY friends DESC

Batch upsert

UNWIND [{name: 'Alice'}, {name: 'Bob'}] AS props
MERGE (p:Person {name: props.name})
  ON CREATE SET p.status = 'new'
  ON MATCH SET p.status = 'existing'

Variable-length path

MATCH p = (a:Person {name: 'Alice'})-[:FRIEND*1..3]->(b)
RETURN b.name, length(relationships(p)) AS distance

List comprehension

WITH [1,2,3,4,5,6,7,8,9,10] AS nums
RETURN [x IN nums WHERE x % 2 = 0 | x * x] AS evenSquares

Base URL

https://api.graphiquity.com

All endpoints are relative to this base. Requests and responses use application/json.

Authentication

All authenticated requests require the Authorization header.

API Key Recommended for apps

Create an API key on the API Keys page. Pass it as a Bearer token:

Authorization: Bearer gq_a1b2c3d4e5f6...

API keys grant access to the /query endpoint. Store keys securely — they cannot be retrieved after creation.

JWT Token For web apps

Authenticate via Cognito to get an ID token:

Authorization: Bearer eyJraWQiOiJ...

JWT tokens grant access to all endpoints and expire after 1 hour.

POST /query

Execute a Cypher query against a graph. JWT API Key

Request Body

FieldTypeDescription
graphstringRequiredGraph name
cypherstringRequiredCypher query
parametersobjectOptionalQuery parameters ($param syntax)
atTimestringOptionalISO 8601 timestamp for time travel

Response

{
  "status": 200,
  "data": [
    { "name": "Alice", "age": 30 },
    { "name": "Bob", "age": 25 }
  ]
}

Examples

curl -X POST https://api.graphiquity.com/query \
  -H "Authorization: Bearer gq_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "graph": "my-graph",
    "cypher": "MATCH (n:Person) WHERE n.age > $minAge RETURN n.name, n.age",
    "parameters": { "minAge": 25 }
  }'
const API_KEY = 'gq_YOUR_API_KEY';
const BASE    = 'https://api.graphiquity.com';

async function query(graph, cypher, parameters = {}) {
  const res = await fetch(`${BASE}/query`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type':  'application/json',
    },
    body: JSON.stringify({ graph, cypher, parameters }),
  });
  const json = await res.json();
  if (json.error) throw new Error(json.error);
  return json.data;
}

// Usage
const people = await query('my-graph',
  'MATCH (n:Person) WHERE n.age > $minAge RETURN n.name, n.age',
  { minAge: 25 }
);
import requests

API_KEY = "gq_YOUR_API_KEY"
BASE    = "https://api.graphiquity.com"

def query(graph, cypher, parameters=None, at_time=None):
    body = {"graph": graph, "cypher": cypher}
    if parameters:
        body["parameters"] = parameters
    if at_time:
        body["atTime"] = at_time
    resp = requests.post(
        f"{BASE}/query",
        headers={"Authorization": f"Bearer {API_KEY}"},
        json=body,
    )
    data = resp.json()
    if "error" in data:
        raise Exception(data["error"])
    return data["data"]

# Usage
people = query("my-graph",
  "MATCH (n:Person) WHERE n.age > $minAge RETURN n.name, n.age",
  {"minAge": 25}
)
package main

import ("bytes"; "encoding/json"; "fmt"; "net/http")

const apiKey  = "gq_YOUR_API_KEY"
const baseURL = "https://api.graphiquity.com"

func query(graph, cypher string, params map[string]interface{}) (map[string]interface{}, error) {
    body, _ := json.Marshal(map[string]interface{}{
        "graph": graph, "cypher": cypher, "parameters": params,
    })
    req, _ := http.NewRequest("POST", baseURL+"/query", bytes.NewReader(body))
    req.Header.Set("Authorization", "Bearer "+apiKey)
    req.Header.Set("Content-Type", "application/json")
    resp, err := http.DefaultClient.Do(req)
    if err != nil { return nil, err }
    defer resp.Body.Close()
    var result map[string]interface{}
    json.NewDecoder(resp.Body).Decode(&result)
    return result, nil
}
require 'net/http'; require 'json'; require 'uri'

API_KEY = "gq_YOUR_API_KEY"
BASE    = "https://api.graphiquity.com"

def query(graph, cypher, parameters: {})
  uri = URI("#{BASE}/query")
  req = Net::HTTP::Post.new(uri)
  req["Authorization"] = "Bearer #{API_KEY}"
  req["Content-Type"]  = "application/json"
  req.body = { graph: graph, cypher: cypher, parameters: parameters }.to_json
  res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
  JSON.parse(res.body)["data"]
end
import java.net.http.*; import java.net.URI;

HttpRequest req = HttpRequest.newBuilder()
    .uri(URI.create("https://api.graphiquity.com/query"))
    .header("Authorization", "Bearer " + API_KEY)
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("""
        {"graph":"my-graph","cypher":"MATCH (n:Person) RETURN n","parameters":{}}
    """)).build();

HttpResponse<String> res = HttpClient.newHttpClient()
    .send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(res.body());
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {apiKey}");

var body = JsonSerializer.Serialize(new {
    graph = "my-graph",
    cypher = "MATCH (n:Person) WHERE n.age > $minAge RETURN n",
    parameters = new { minAge = 25 }
});
var res = await client.PostAsync("https://api.graphiquity.com/query",
    new StringContent(body, Encoding.UTF8, "application/json"));
Console.WriteLine(await res.Content.ReadAsStringAsync());
<?php
$ch = curl_init('https://api.graphiquity.com/query');
curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer gq_YOUR_API_KEY',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'graph'  => 'my-graph',
        'cypher' => 'MATCH (n:Person) RETURN n.name',
    ]),
]);
$result = json_decode(curl_exec($ch), true);
print_r($result['data']);
?>

Creating Data

Use CREATE and MERGE via the query endpoint.

// Create a node
await query('my-graph', `CREATE (p:Person {name: $name, age: $age}) RETURN p`,
  { name: 'Alice', age: 30 });

// Create a relationship
await query('my-graph', `
  MATCH (a:Person {name: $from}), (b:Person {name: $to})
  CREATE (a)-[:FRIEND {since: $year}]->(b)`,
  { from: 'Alice', to: 'Bob', year: 2024 });

// Batch upsert
await query('my-graph', `
  UNWIND $people AS props
  MERGE (p:Person {name: props.name})
  ON CREATE SET p.age = props.age`,
  { people: [{name:'Alice',age:30}, {name:'Bob',age:25}] });
# Create a node
query("my-graph", "CREATE (p:Person {name: $name, age: $age})",
  {"name": "Alice", "age": 30})

# Batch upsert
query("my-graph", """
  UNWIND $people AS props
  MERGE (p:Person {name: props.name})
  ON CREATE SET p.age = props.age
""", {"people": [{"name":"Alice","age":30}, {"name":"Bob","age":25}]})
curl -X POST https://api.graphiquity.com/query \
  -H "Authorization: Bearer gq_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"graph":"my-graph","cypher":"CREATE (:Person {name:$name})",
       "parameters":{"name":"Alice"}}'

Temporal Queries (Time Travel)

Pass atTime as an ISO 8601 timestamp to query the graph as it was at that point.

const res = await fetch(`${BASE}/query`, {
  method: 'POST',
  headers: { 'Authorization': `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({
    graph: 'my-graph',
    cypher: 'MATCH (n:Person) RETURN n.name, n.age',
    atTime: '2024-01-01T00:00:00Z',
  }),
});
result = query("my-graph", "MATCH (n:Person) RETURN n", at_time="2024-01-01T00:00:00Z")
curl -X POST https://api.graphiquity.com/query \
  -H "Authorization: Bearer gq_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"graph":"my-graph","cypher":"MATCH (n) RETURN n","atTime":"2024-01-01T00:00:00Z"}'

Graph Management JWT only

GET /graphs

List all graphs.

POST /graphs

Create a graph.

FieldTypeDescription
namestringRequiredLetters, numbers, hyphens, underscores. Max 64 chars.
descriptionstringOptionalDescription

DELETE /graphs/{name}

Delete a graph.

API Key Management JWT only

GET /apikeys

List keys (prefixes only).

POST /apikeys

Create a key. The full key is only shown once.

// Response
{ "status": 201, "data": { "key": "gq_a1b2c3...", "prefix": "gq_a1b2c3d", "name": "My Key" } }

DELETE /apikeys/{prefix}

Revoke a key by prefix.

Graph Schema

GET /graphs/{name}/schema

Returns the labels and edge types present in the graph. Useful for autocomplete and introspection.

// Response
{
  "status": 200,
  "data": {
    "labels": ["Person", "Company"],
    "edgeTypes": ["FRIEND", "WORKS_AT"]
  }
}

Contracts (Schema Validation)

Contracts enforce per-label and per-edge-type schemas — type checking, required fields, unique constraints, and regex patterns. Each contract has an enforcement mode:

ModeBehavior
OFFNo validation (default)
WARNWrites succeed but response includes warnings array
STRICTInvalid writes are rejected with HTTP 400

GET /graphs/{name}/contracts

List all contracts defined for the graph.

// Response
{
  "status": 200,
  "data": [
    {
      "kind": "node",
      "label": "Person",
      "mode": "STRICT",
      "properties": {
        "name":  { "type": "string", "required": true, "maxLength": 200 },
        "email": { "type": "string", "unique": true },
        "age":   { "type": "integer" }
      }
    }
  ]
}

PUT /graphs/{name}/contracts

Create or replace a contract. The request body is the contract object.

FieldTypeDescription
kindstringRequired"node" or "edge"
labelstringNode label (required when kind=node)
relTypestringEdge type (required when kind=edge)
modestringOFF | WARN | STRICT
propertiesobjectMap of property name → definition

Property definition fields: type (string|integer|float|boolean|timestamp|json|vector), required, unique, maxLength, pattern, enum, dims.

// JavaScript
await fetch("https://api.graphiquity.com/graphs/myGraph/contracts", {
  method: "PUT",
  headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    kind: "node", label: "Person", mode: "STRICT",
    properties: {
      name:  { type: "string",  required: true, maxLength: 200 },
      email: { type: "string",  unique: true, pattern: "^[^@]+@[^@]+$" },
      age:   { type: "integer" }
    }
  })
});
# Python
import requests
requests.put(
    "https://api.graphiquity.com/graphs/myGraph/contracts",
    headers={"Authorization": f"Bearer {token}"},
    json={
        "kind": "node", "label": "Person", "mode": "STRICT",
        "properties": {
            "name":  {"type": "string", "required": True, "maxLength": 200},
            "email": {"type": "string", "unique": True},
            "age":   {"type": "integer"}
        }
    }
)

DELETE /graphs/{name}/contracts

Remove a contract. Pass {"label": "Person"} for node contracts or {"relType": "FRIEND"} for edge contracts.

Cypher Constraint Syntax

You can also create and drop unique constraints via Cypher:

// Create a unique constraint
CREATE CONSTRAINT ON (p:Person) ASSERT p.email IS UNIQUE

// Drop a unique constraint
DROP CONSTRAINT ON (p:Person) ASSERT p.email IS UNIQUE

Usage Analytics

GET /usage

Returns per-day operation counts for the tenant. Data is retained for 90 days.

// Response
{
  "status": 200,
  "data": [
    { "date": "2026-03-02", "operation": "query", "count": 142 },
    { "date": "2026-03-02", "operation": "createGraph", "count": 1 }
  ]
}

User Management JWT only

GET /users

List all users in the tenant.

POST /users/invite

Invite a user. Requires owner role.

FieldTypeDescription
emailstringRequiredEmail address
rolestringOptionalowner or member (default)

DELETE /users/{userId}

Remove a user. Requires owner role.

Errors

{ "status": 400, "error": "graph and cypher are required" }
StatusMeaning
200Success
201Created
400Bad request (missing fields, invalid Cypher)
401Unauthorized
403Forbidden (insufficient role)
404Not found
409Conflict (duplicate resource)
429Rate limit exceeded (60 req/min per tenant)
500Internal error

Quick Start

1. Get an API key

Go to API Keys and create one. Copy it immediately.

2. Create a graph

Use the Dashboard or the POST /graphs endpoint.

3. Query away

const gq = (cypher, p) =>
  fetch('https://api.graphiquity.com/query', {
    method: 'POST',
    headers: { Authorization: 'Bearer gq_YOUR_KEY', 'Content-Type': 'application/json' },
    body: JSON.stringify({ graph: 'my-graph', cypher, parameters: p }),
  }).then(r => r.json()).then(r => r.data);

await gq("CREATE (:Person {name:'Alice'})-[:FRIEND]->(:Person {name:'Bob'})");
const friends = await gq("MATCH (a)-[:FRIEND]->(b) RETURN a.name, b.name");
// [{ "a.name": "Alice", "b.name": "Bob" }]
import requests
def gq(cypher, p={}):
    return requests.post("https://api.graphiquity.com/query",
        headers={"Authorization": "Bearer gq_YOUR_KEY"},
        json={"graph": "my-graph", "cypher": cypher, "parameters": p}).json()["data"]

gq("CREATE (:Person {name:'Alice'})-[:FRIEND]->(:Person {name:'Bob'})")
friends = gq("MATCH (a)-[:FRIEND]->(b) RETURN a.name, b.name")
# [{"a.name": "Alice", "b.name": "Bob"}]