Mutations
Every write operation in Golden Reports — creating, updating, deleting, publishing — is a mutation on the GraphQL endpoint.
Overview
POST https://api.goldenreports.dev/graphql
Mutations follow the GraphQL Relay-style convention: each one takes a single input: SomeInput! argument and returns a payload object containing the affected resource (or, for deletes, the id of the deleted record).
Editing a data context is a stateful, multi-step flow that uses optimistic locking with a lockToken and a monotonically increasing revision. See Data context locks before calling updateDataContext.
Workspaces
Create a workspace
CreateWorkspaceInput
- Name
name- Type
- String!
- Description
- Workspace name.
- Name
description- Type
- String
- Description
- Optional description.
- Name
active- Type
- Boolean!
- Description
- Whether the workspace is active.
Returns CreateWorkspacePayload { workspace: Workspace! }.
Request
mutation Create($input: CreateWorkspaceInput!) {
createWorkspace(input: $input) {
workspace {
id
name
}
}
}
Create a workspace with a project
Atomically creates a workspace and an initial project inside it. Prefer this when bootstrapping — it's a single round-trip and the two records are guaranteed to be created together.
CreateWorkspaceWithProjectInput
- Name
workspaceName- Type
- String!
- Description
- Workspace name.
- Name
workspaceDescription- Type
- String
- Description
- Optional workspace description.
- Name
active- Type
- Boolean!
- Description
- Workspace active flag.
- Name
projectName- Type
- String!
- Description
- Initial project name.
- Name
projectDescription- Type
- String
- Description
- Optional project description.
Request
mutation Bootstrap($input: CreateWorkspaceWithProjectInput!) {
createWorkspaceWithProject(input: $input) {
workspace {
id
name
projects { id name }
}
}
}
Update a workspace
UpdateWorkspaceInput
- Name
id- Type
- UUID!
- Description
- Workspace identifier.
- Name
name- Type
- String!
- Description
- New name.
- Name
description- Type
- String
- Description
- New description.
- Name
active- Type
- Boolean!
- Description
- Active flag.
Request
mutation Update($input: UpdateWorkspaceInput!) {
updateWorkspace(input: $input) {
workspace { id name description }
}
}
Delete a workspace
DeleteWorkspaceInput
- Name
id- Type
- UUID!
- Description
- Workspace identifier.
Request
mutation Delete($input: DeleteWorkspaceInput!) {
deleteWorkspace(input: $input) {
id
}
}
Projects
Create a project
CreateProjectInput
- Name
workspaceId- Type
- UUID!
- Description
- Parent workspace.
- Name
name- Type
- String!
- Description
- Project name.
- Name
description- Type
- String
- Description
- Optional description.
Request
mutation Create($input: CreateProjectInput!) {
createProject(input: $input) {
project { id name workspace { id } }
}
}
Update a project
UpdateProjectInput
- Name
id- Type
- UUID!
- Description
- Project identifier.
- Name
name- Type
- String!
- Description
- New name.
- Name
description- Type
- String
- Description
- New description.
Request
mutation Update($input: UpdateProjectInput!) {
updateProject(input: $input) {
project { id name }
}
}
Delete a project
DeleteProjectInput
- Name
id- Type
- UUID!
- Description
- Project identifier.
Request
mutation Delete($input: DeleteProjectInput!) {
deleteProject(input: $input) { id }
}
Reports
Create a report
Creates a new report inside a project, bound to a published data context.
CreateReportInput
- Name
code- Type
- String!
- Description
- Stable code used by
embeddedReportandexportedReport. Must be unique within the project.
- Name
name- Type
- String!
- Description
- Display name.
- Name
description- Type
- String
- Description
- Optional description.
- Name
projectId- Type
- UUID!
- Description
- Owning project.
- Name
dataContextId- Type
- UUID!
- Description
- Data context to query against.
- Name
renderSpecType- Type
- RenderSpecType!
- Description
HTMLorEXCEL.
- Name
templateId- Type
- UUID
- Description
- Optional template to seed initial state from.
Request
mutation Create($input: CreateReportInput!) {
createReport(input: $input) {
report {
id
code
renderSpecType
}
}
}
Update a report
Updates name, description, render spec data, parameters, and the GraphQL query.
UpdateReportInput
- Name
id- Type
- UUID!
- Description
- Report identifier.
- Name
name- Type
- String!
- Description
- Display name.
- Name
description- Type
- String
- Description
- Description.
- Name
renderSpecData- Type
- JSON
- Description
- Renderer-specific layout configuration.
- Name
graphQlQuery- Type
- String
- Description
- The data query.
- Name
variables- Type
- JSON
- Description
- Internal report variables.
- Name
parameters- Type
- JSON
- Description
- User-facing parameter definitions.
Every update bumps the report's version by 1.
Request
mutation Update($input: UpdateReportInput!) {
updateReport(input: $input) {
report {
id
version
lastModifiedAt
}
}
}
Delete a report
DeleteReportInput
- Name
id- Type
- UUID!
- Description
- Report identifier.
Request
mutation Delete($input: DeleteReportInput!) {
deleteReport(input: $input) { id }
}
Data sources
Create a data source
Creates a new data source by binding a connector to a configuration. Configuration shape is connector-specific — fetch the connector's configSchema from connectors to know what to send.
CreateDataSourceInput
- Name
code- Type
- String!
- Description
- Stable code, unique within the tenant.
- Name
name- Type
- String!
- Description
- Display name.
- Name
description- Type
- String
- Description
- Optional description.
- Name
connectorId- Type
- UUID!
- Description
- Connector to instantiate.
- Name
configuration- Type
- JSON!
- Description
- Connector configuration. Must validate against the connector's
configSchema.
- Name
active- Type
- Boolean!
- Description
- Whether the data source is enabled on creation.
- Name
monitoringEnabled- Type
- Boolean!
- Description
- Whether to enable automatic health monitoring.
Request
mutation Create($input: CreateDataSourceInput!) {
createDataSource(input: $input) {
dataSource {
id
code
connector { code }
}
}
}
Update a data source
Same shape as createDataSource, plus an id.
UpdateDataSourceInput
- Name
id- Type
- UUID!
- Description
- Data source identifier.
- Name
name- Type
- String!
- Description
- Display name.
- Name
description- Type
- String
- Description
- Description.
- Name
connectorId- Type
- UUID!
- Description
- Connector reference.
- Name
configuration- Type
- JSON!
- Description
- Connector configuration. Send only the keys you intend to change for secret-typed fields — others remain redacted server-side.
- Name
active- Type
- Boolean!
- Description
- Active flag.
- Name
monitoringEnabled- Type
- Boolean!
- Description
- Health monitoring flag.
Request
mutation Update($input: UpdateDataSourceInput!) {
updateDataSource(input: $input) {
dataSource { id active monitoringEnabled }
}
}
Delete a data source
Soft-deletes a data source — the row remains for audit but is excluded from default queries. Restore with restoreDataSource.
DeleteDataSourceInput
- Name
id- Type
- UUID!
- Description
- Data source identifier.
Request
mutation Delete($input: DeleteDataSourceInput!) {
deleteDataSource(input: $input) { id }
}
Restore a data source
Un-deletes a soft-deleted data source.
RestoreDataSourceInput
- Name
id- Type
- UUID!
- Description
- Data source identifier.
Request
mutation Restore($input: RestoreDataSourceInput!) {
restoreDataSource(input: $input) {
dataSource { id deletedAt }
}
}
Check health on demand
Triggers an immediate health check for a data source and returns the result synchronously. Subscribe to onDataSourceHealthChanged to receive checks for every source as they happen.
CheckDataSourceHealthInput
- Name
dataSourceId- Type
- UUID!
- Description
- Data source identifier.
The payload contains the recorded health snapshot, including status, errorCode, errorDetail, latencyMs, and lastCheckedAt.
Request
mutation Check($input: CheckDataSourceHealthInput!) {
checkDataSourceHealth(input: $input) {
dataSource {
id
health {
status
errorCode
latencyMs
lastCheckedAt
}
}
}
}
Data contexts
Data contexts have a more involved lifecycle than other resources: a mutable draft is edited under an exclusive lock, then published as an immutable version. Locks are mandatory — updateDataContext requires a valid lockToken.
Create a data context
Creates a data context and atomically acquires the editing lock for the caller. The returned lockToken is what you'll pass to subsequent updateDataContext / publishDataContext / releaseDataContextLock calls.
CreateDataContextInput
- Name
projectId- Type
- UUID!
- Description
- Owning project.
- Name
code- Type
- String!
- Description
- Stable code, unique within the project.
- Name
name- Type
- String!
- Description
- Display name.
- Name
description- Type
- String
- Description
- Optional description.
- Name
schema- Type
- String!
- Description
- SDL of the schema the data context will expose to reports.
- Name
designerState- Type
- JSON
- Description
- Opaque designer-tool state.
- Name
dataSourceIds- Type
- [UUID!]!
- Description
- Data sources to bind to the draft.
- Name
clientId- Type
- String!
- Description
- Stable identifier for the client session — used to scope the lock.
Returns CreateDataContextPayload
- Name
dataContext- Type
- DataContext!
- Description
- The created draft.
- Name
lockToken- Type
- String!
- Description
- Lock token — required by every subsequent mutation on this draft.
- Name
lockExpiresAt- Type
- DateTime!
- Description
- When the lock expires unless heartbeated.
Request
mutation Create($input: CreateDataContextInput!) {
createDataContext(input: $input) {
dataContext {
id
revision
}
lockToken
lockExpiresAt
}
}
Update a data context
Auto-save path. Requires a valid lockToken and the current revision — if your revision doesn't match the server-side value, the mutation fails. Pass force: true to override (rarely needed; usually means another client has the lock).
UpdateDataContextInput
- Name
id- Type
- UUID!
- Description
- Data context identifier.
- Name
name- Type
- String!
- Description
- Display name.
- Name
description- Type
- String
- Description
- Description.
- Name
schema- Type
- String!
- Description
- Updated SDL.
- Name
designerState- Type
- JSON
- Description
- Designer state.
- Name
dataSourceIds- Type
- [UUID!]!
- Description
- Bound data sources.
- Name
revision- Type
- Int!
- Description
- The
revisionyou last observed. Server bumps and returns the new one.
- Name
lockToken- Type
- String!
- Description
- Lock token from
acquireDataContextLock.
- Name
force- Type
- Boolean
- Description
- Bypass concurrent-edit detection.
Request
mutation Update($input: UpdateDataContextInput!) {
updateDataContext(input: $input) {
dataContext {
id
revision
}
}
}
Delete a data context
Deletes the data context (and its draft + version history) permanently. Requires the editing lock.
DeleteDataContextInput
- Name
id- Type
- UUID!
- Description
- Data context identifier.
- Name
lockToken- Type
- String!
- Description
- Lock token.
Request
mutation Delete($input: DeleteDataContextInput!) {
deleteDataContext(input: $input) { id }
}
Publish a draft
Promotes the current draft to a new immutable DataContextVersion. Reports that point at the data context will see the new version on their next render.
PublishDataContextInput
- Name
id- Type
- UUID!
- Description
- Data context identifier.
- Name
lockToken- Type
- String!
- Description
- Lock token.
Request
mutation Publish($input: PublishDataContextInput!) {
publishDataContext(input: $input) {
version {
id
number
publishedAt
}
}
}
Rollback a draft
Resets the current draft to a previous state — either a published DataContextVersion or a DataContextDraftRevision (auto-save journal entry). Requires the editing lock.
RollbackDataContextDraftInput
- Name
id- Type
- UUID!
- Description
- Data context identifier.
- Name
lockToken- Type
- String!
- Description
- Lock token.
- Name
source- Type
- RollbackSourceInput!
- Description
Either
{ versionId: UUID! }to roll back to a published version, or{ revisionId: UUID! }to roll back to a draft revision.
Request
mutation Rollback($input: RollbackDataContextDraftInput!) {
rollbackDataContextDraft(input: $input) {
dataContext {
id
revision
}
}
}
Data context locks
Editing a data context is gated by an exclusive lock. The lock is scoped to a (userId, clientId) pair — a single user editing from two browser tabs counts as two clients. Locks expire if not heartbeated.
Lock lifecycle
- Acquire the lock with
acquireDataContextLock(or get one for free fromcreateDataContext). - Heartbeat the lock at most every
(lockExpiresAt - now) / 2seconds withheartbeatDataContextLockto keep it alive. - Update the draft via
updateDataContext, passing the lock token and the currentrevision. - Publish with
publishDataContext, or - Release the lock with
releaseDataContextLockwhen done.
If your client reconnects with the same clientId, use resumeDataContextLock to receive a fresh token without rotating ownership. Subscribe to onDataContextLockChanged to react to expirations and remote acquisitions.
Acquire a data context lock
AcquireDataContextLockInput
- Name
id- Type
- UUID!
- Description
- Data context identifier.
- Name
clientId- Type
- String!
- Description
- Stable client session identifier.
Returns AcquireDataContextLockPayload
- Name
lockToken- Type
- String!
- Description
- Token to pass to subsequent draft mutations.
- Name
lockExpiresAt- Type
- DateTime!
- Description
- Token expiry. Heartbeat before this to keep editing.
- Name
revision- Type
- Int!
- Description
- Current draft revision at acquisition time.
- Name
holder- Type
- DataContextLockHolder
- Description
- User holding the lock — yourself.
Request
mutation Acquire($input: AcquireDataContextLockInput!) {
acquireDataContextLock(input: $input) {
lockToken
lockExpiresAt
revision
holder { userId userName }
}
}
Resume a lock
Returns a fresh lockToken without rotating ownership. Use after a page reload or websocket reconnect to recover from token loss when the live lock still belongs to your (user, client) pair. Fails if the lock has expired or moved to a different holder.
ResumeDataContextLockInput
- Name
id- Type
- UUID!
- Description
- Data context identifier.
- Name
clientId- Type
- String!
- Description
- Same
clientIdused to acquire.
Request
mutation Resume($input: ResumeDataContextLockInput!) {
resumeDataContextLock(input: $input) {
lockToken
lockExpiresAt
}
}
Heartbeat a lock
Extends the lock's TTL. Call before lockExpiresAt to keep editing.
HeartbeatDataContextLockInput
- Name
id- Type
- UUID!
- Description
- Data context identifier.
- Name
lockToken- Type
- String!
- Description
- Current lock token.
Request
mutation Beat($input: HeartbeatDataContextLockInput!) {
heartbeatDataContextLock(input: $input) {
lockExpiresAt
}
}
Release a lock
Releases the lock so another client can acquire it. Always call this when the user closes the editor.
ReleaseDataContextLockInput
- Name
id- Type
- UUID!
- Description
- Data context identifier.
- Name
lockToken- Type
- String!
- Description
- Lock token.
Request
mutation Release($input: ReleaseDataContextLockInput!) {
releaseDataContextLock(input: $input) { id }
}
Credits
Purchase a credit pack
Creates a Stripe Checkout Session for a credit pack and returns a checkoutUrl for the caller to redirect the user to. Once payment completes, the tenant's creditBalance is increased and a CreditTransaction is recorded.
PurchaseCreditPackInput
- Name
packId- Type
- String!
- Description
- Stripe price ID of the credit pack to purchase.
Returns PurchaseCreditPackPayload
- Name
checkoutUrl- Type
- String
- Description
- URL to redirect the user to Stripe Checkout.
Request
mutation Buy($input: PurchaseCreditPackInput!) {
purchaseCreditPack(input: $input) {
checkoutUrl
}
}