English
Managing users via GraphQL
You need to provision a subscriber, grant a team member access to a subgraph, or make someone an admin — without opening the browser. All three operations are available as GraphQL mutations. They're designed to be driven by an agent or a script.
This requires admin API access. See en/user/graphql for authentication setup.
Typical workflow
- Create a note with
subgraph: namefrontmatter → sync → subgraph appears createUser(email)→ getuserIdallSubgraphs→ getsubgraphIdscreateUserSubgraphAccess(userId, subgraphIds)→ grant content access- Optionally
createAdmin(userId)→ full admin rights
Step 1. Create a user
mutation {
admin {
createUser(input: { email: "user@example.com" }) {
__typename
... on CreateUserPayload {
user { id email }
}
... on ErrorPayload { message }
}
}
}
The response includes the new user's id. You need it for every subsequent mutation.
Step 2. Get subgraph IDs
Subgraphs are created by syncing a note that declares one in its frontmatter:
---
subgraph: premium
---
Or multiple subgraphs at once:
---
subgraphs: [premium, beta]
---
After syncing from Obsidian, the subgraph appears in the system. List all subgraphs to get their IDs:
{ admin { allSubgraphs { nodes { id name } } } }
Step 3. Grant subgraph access
mutation {
admin {
createUserSubgraphAccess(input: {
userId: 6
subgraphIds: [1]
expiresAt: null
}) {
__typename
... on CreateUserSubgraphAccessPayload {
accesses { id userId subgraphId expiresAt }
}
... on ErrorPayload { message }
}
}
}
subgraphIds is an array — you can grant access to multiple subgraphs in one call. Omit expiresAt (or pass null) for permanent access. Pass an ISO 8601 timestamp for time-limited access.
Step 4. Make a user admin (optional)
mutation {
admin {
createAdmin(input: { userId: 6 }) {
__typename
... on CreateAdminPayload {
admin { id user { id email } }
}
... on ErrorPayload { message }
}
}
}
Admin status gives full access to the admin panel and all GraphQL mutations. Use it for team members who need to manage the site, not for regular subscribers.
Warning: notes without a subgraph are visible to all signed-in users
By default, any note that has no subgraph or subgraphs in its frontmatter is visible to every authenticated user — including users you grant access to only one specific subgraph.
Fix: hide unassigned notes behind a system subgraph.
Create a vault-based frontmatter patch (_private.md or similar):
---
type: frontmatter-patch
include: ["**"]
priority: 0
---
if !std.objectHas(meta, 'subgraph') && !std.objectHas(meta, 'subgraphs')
then meta + { subgraph: 'notes_without_subgraph' }
else meta
This assigns every untagged note to the notes_without_subgraph subgraph. Since you never grant anyone access to it, those notes are invisible to regular users. Admins always see everything regardless of subgraph assignment.
See en/user/frontmatter-patches for the full patch syntax.
Use case: share a single page with one person by email
You want to give someone access to one specific note — not the whole site, not a paid subgraph. The cleanest way:
1. Create the note
shares/alice/intro.md
Frontmatter:
---
subgraph: alice
---
Sync from Obsidian. The alice subgraph appears automatically.
2. Provision the user
# Create the user
mutation { admin { createUser(input: { email: "alice@example.com" }) {
... on CreateUserPayload { user { id } }
} } }
# Get the subgraph ID (look for name = "alice")
{ admin { allSubgraphs { nodes { id name } } } }
# Grant access
mutation { admin { createUserSubgraphAccess(input: { userId: <id>, subgraphIds: [<subgraphId>] }) {
... on CreateUserSubgraphAccessPayload { accesses { id } }
} } }
3. Send the user a message
Hi Alice,
I've shared a page with you: https://yoursite.com/shares/alice/intro
To open it, click the link and sign in with this email. You'll receive a one-time code — no password needed.
That's it. Alice sees only the alice subgraph. Add more notes to shares/alice/ as needed.
Alternative: share without requiring a login
If you don't need access control — just a hard-to-guess link — use free: true instead:
shares/a3f7c2d1-invoice-may.md
---
free: true
created_at: 2026-05-25
expires_at: 2026-06-25
---
Anyone with the URL can open it, no sign-in needed. The unguessable path acts as the access token. Suitable for one-off documents, invoices, drafts — anything where the link itself is the secret.
expires_at is metadata only for now — useful for future cleanup automation (cron that hides or deletes expired shares).
Lookup queries
If you don't know a user's id or a subgraph's id, look them up first.
# Find a user's ID by email
{ admin { allUsers { nodes { id email } } } }
# List subgraphs with their IDs
{ admin { allSubgraphs { nodes { id name } } } }
# Check a user's current accesses
{ admin { allUserSubgraphAccesses { nodes { id userId subgraphId expiresAt } } } }