The examples in this guide are validated against the generated plugin schema by
npm run verify:docs. Runtime GraphQL introspection remains the definitive
contract for the exact plugin version installed by an application.
The Data Hub plugin extends the Vendure Admin API with queries and mutations for pipeline management.
List all pipelines:
query {
dataHubPipelines(options: { take: 20, skip: 0 }) {
items {
id
code
name
enabled
configurationSource
createdAt
updatedAt
}
totalItems
}
}
Get a single pipeline:
query GetPipeline($id: ID!) {
dataHubPipeline(id: $id) {
id
code
name
enabled
configurationSource
definition
createdAt
updatedAt
}
}
List connections:
query {
dataHubConnections {
items {
id
code
type
configurationSource
createdAt
}
totalItems
}
}
configurationSource is DATABASE for Dashboard-managed resources and
CODE_FIRST for active deployed definitions. Update, delete, lifecycle, draft,
and restore mutations reject active code-first resources. Pipeline review,
publication, execution, export, history, and comparison remain available.
List secrets (values hidden):
query {
dataHubSecrets {
items {
id
code
provider
hasValue
createdAt
}
totalItems
}
}
List secret codes that can be referenced by pipelines, connections, triggers, and
destinations. This read-only query includes both code-first and database-managed
secrets but never returns secret values. Results are filtered on the server;
take must be between 1 and 100.
query SecretReferences($search: String, $skip: Int = 0, $take: Int = 25) {
dataHubSecretReferences(search: $search, skip: $skip, take: $take) {
items {
code
provider
source
}
totalItems
}
}
Code-first results are returned first in code order, followed by distinct
database results in code order. The query requires ReadDataHubSecret.
List available adapters:
Requires ManageDataHubAdapters.
query {
dataHubAdapters {
code
name
type
category
description
version
deprecated
deprecatedMessage
schema {
fields {
key
type
required
label
defaultValue
options { value label }
}
}
}
}
Query pipeline runs:
query GetRuns($pipelineId: ID!) {
dataHubPipelineRuns(pipelineId: $pipelineId, options: { take: 10 }) {
items {
id
status
startedAt
finishedAt
triggeredBy
}
totalItems
}
}
Get a single run:
query GetRun($id: ID!) {
dataHubPipelineRun(id: $id) {
id
status
startedAt
completedAt
metrics
triggeredBy
}
}
Query execution logs:
query GetLogs {
dataHubLogs(options: { take: 100 }) {
items {
id
level
message
stepKey
createdAt
metadata
}
totalItems
}
}
Query failed records for a specific run. Use the returned cursor to request the next page; cursors are opaque and must not be constructed by clients.
query RunErrors($runId: ID!, $first: Int!, $after: String) {
dataHubRunErrors(runId: $runId, first: $first, after: $after) {
items {
id
stepKey
message
payload
stackTrace
createdAt
}
totalItems
hasNextPage
endCursor
}
}
dataHubDeadLetters(first:, after:) uses the same page shape. Page size is
bounded by the server query limit.
Get plugin settings:
query {
dataHubSettings {
retentionDaysRuns
retentionDaysErrors
retentionDaysLogs
logPersistenceLevel
}
}
List channel-scoped delivery destinations. The API returns configuration and Secret Codes, never resolved secret values:
query {
dataHubExportDestinations {
id
name
type
enabled
url
auth {
type
secretCode
usernameSecretCode
}
}
}
Destination definitions are stored in the database and scoped to the active Vendure channel. API and worker processes read the same durable definition, so registrations survive restarts and do not rely on process-local cache invalidation. Only validated configuration and Secret Codes are persisted; resolved credential values are never written to the destination table. Pipeline destination schemas and saved pipeline definitions remain separate.
Each channel can store up to 100 managed destinations. Creation and deletion are serialized per channel with the configured Data Hub lock backend, and the capacity check runs in a transaction opened after the lock is acquired. Managed creation rejects an ID that already exists in the active channel instead of silently replacing its configuration.
Create every referenced secret first, then register the destination using only Secret Codes. Plaintext credential fields, credential-bearing static headers, embedded URL credentials, and prototype keys are rejected.
mutation RegisterPartnerDestination {
dataHubRegisterExportDestination(input: {
id: "partner-http"
name: "Partner HTTP"
type: HTTP
url: "https://partner.example.com/import"
method: "POST"
auth: {
type: BEARER
secretCode: "partner-api-token"
}
}) {
success
id
}
}
S3 uses accessKeyIdSecretCode and secretAccessKeySecretCode. FTP uses
passwordSecretCode; SFTP supports passwordSecretCode,
privateKeySecretCode, passphraseSecretCode, and
hostKeyFingerprintSecretCode. The fingerprint reference must resolve to the trusted
OpenSSH SHA256:<base64> server host-key fingerprint and is required in production.
SMTP authentication uses smtp.usernameSecretCode (or a non-secret
smtp.username) together with smtp.passwordSecretCode. Secret values are
resolved only while testing or delivering to a destination.
Delete a managed destination from the active Vendure channel. A destination
with the same ID in another channel is not affected. The mutation requires
ManageDataHubDestinations and returns Vendure’s standard deletion result.
mutation DeletePartnerDestination {
dataHubDeleteExportDestination(id: "partner-http") {
result
message
}
}
Create a pipeline:
mutation CreatePipeline($input: CreateDataHubPipelineInput!) {
createDataHubPipeline(input: $input) {
id
code
name
}
}
Variables:
{
"input": {
"code": "my-pipeline",
"name": "My Pipeline",
"definition": {
"version": 1,
"steps": [],
"edges": []
}
}
}
Update a pipeline:
mutation UpdatePipeline($input: UpdateDataHubPipelineInput!) {
updateDataHubPipeline(input: $input) {
id
name
enabled
}
}
Variables:
{
"input": {
"id": "1",
"name": "Updated Name",
"enabled": true
}
}
Delete a pipeline:
mutation DeletePipeline($id: ID!) {
deleteDataHubPipeline(id: $id) {
result
message
}
}
Pipeline lifecycle transitions are enforced by the service and revision layers:
submitDataHubPipelineForReview: DRAFT to REVIEWpublishDataHubPipeline: REVIEW to PUBLISHEDapproveDataHubPipeline: REVIEW to PUBLISHED and requires both review and publish permissionsrejectDataHubPipelineReview: REVIEW to DRAFTarchiveDataHubPipeline: PUBLISHED to ARCHIVED and disables executionreactivateDataHubPipeline: ARCHIVED to PUBLISHED, restores the active published revision, and explicitly re-enables execution
PUBLISHED pipelines and creates a new validated published revision
Draft, review, and archived pipelines cannot bypass the review workflow through revision reversion. Reactivation does not create a new revision.Publication uses the saved REVIEW definition and fails closed. It performs
full structural, semantic, adapter, dependency, resource, and hook validation;
inability to verify a dependency, connection, secret, hook script, or target
pipeline blocks publication. It also rejects reachable cycles across
dependsOn and TRIGGER_PIPELINE references and verifies the effective adapter
and operator permissions. The standalone validation query is advisory:
isValid excludes warnings and does not include every publication-only cycle,
permission, or concurrent-change check.
mutation ReactivatePipeline($id: ID!) {
reactivateDataHubPipeline(id: $id) {
id
status
enabled
version
}
}
Execute a pipeline:
mutation RunPipeline($pipelineId: ID!) {
startDataHubPipelineRun(pipelineId: $pipelineId) {
id
status
}
}
Cancel a running pipeline:
mutation CancelRun($id: ID!) {
cancelDataHubPipelineRun(id: $id) {
id
status
}
}
Execute the configured observation actions for one hook stage. Interceptor and script actions are reported as skipped because they require the pipeline’s record-processing lifecycle.
mutation TestHook($pipelineId: ID!, $stage: String!, $payload: JSON) {
runDataHubHookTest(pipelineId: $pipelineId, stage: $stage, payload: $payload) {
status
configured
executed
skipped
failed
errors {
action
type
error
}
}
}
The mutation requires the Run Data Hub Pipeline permission. A resolved mutation
is not necessarily successful: inspect status and failed.
Validate a pipeline definition:
query Validate($definition: JSON!) {
validateDataHubPipelineDefinition(definition: $definition) {
isValid
level
issues {
stepKey
field
message
reason
}
warnings {
stepKey
field
message
reason
}
}
}
Requires ReadDataHubPipeline. reason is a nullable technical code supplied
when the validator can classify an issue; unexpected failures can be
message-only.
Create a connection:
Requires ManageDataHubConnections.
mutation CreateConnection($input: CreateDataHubConnectionInput!) {
createDataHubConnection(input: $input) {
id
code
type
}
}
Update a connection:
Requires ManageDataHubConnections.
mutation UpdateConnection($input: UpdateDataHubConnectionInput!) {
updateDataHubConnection(input: $input) {
id
code
}
}
Delete a connection:
Requires ManageDataHubConnections.
mutation DeleteConnection($id: ID!) {
deleteDataHubConnection(id: $id) {
result
message
}
}
Inspect both fields. NOT_DELETED includes a missing-resource, dependency, or
persistence failure reason in message.
Create a secret:
Requires CreateDataHubSecret.
mutation CreateSecret($input: CreateDataHubSecretInput!) {
createDataHubSecret(input: $input) {
id
code
provider
hasValue
}
}
Variables:
{
"input": {
"code": "api-key",
"provider": "ENV",
"value": "MY_API_KEY"
}
}
Update a secret:
Requires UpdateDataHubSecret.
mutation UpdateSecret($input: UpdateDataHubSecretInput!) {
updateDataHubSecret(input: $input) {
id
code
}
}
The value fields have explicit three-state semantics:
value and clearValue, for example { "id": "1", "metadata": { "owner": "ops" } }value, for example { "id": "1", "value": "new-secret" }value and send { "id": "1", "clearValue": true }Sending value: null, an empty/whitespace value, or both value and clearValue is rejected instead of silently deleting data.
Changing provider requires a valid non-blank replacement in the same update. ENV values must be environment-variable names such as SUPPLIER_API_KEY and cannot contain fallbacks. INLINE writes require DATAHUB_MASTER_KEY with at least 32 characters.
Secret queries and mutation responses expose hasValue; the stored value is never returned.
Delete a secret:
Requires DeleteDataHubSecret.
mutation DeleteSecret($id: ID!) {
deleteDataHubSecret(id: $id) {
result
message
}
}
Tracked references from published pipelines, saved connections, or managed
destinations prevent deletion and return NOT_DELETED with a reason.
Missing secrets also return NOT_DELETED with Secret not found.
Retry a single failed record with an optional field patch:
mutation RetryRecord($errorId: ID!, $patch: JSON) {
retryDataHubRecord(errorId: $errorId, patch: $patch) {
success
outcome
message
errorId
runId
stepKey
adapterCode
definitionVersion
appliedPatch
rejectedPatchKeys
processed
succeeded
failed
auditId
auditRecorded
}
}
The retry uses the failed run’s immutable definition snapshot. Adapter identity is resolved from canonical step.config.adapterCode, with the typed root step.adapterCode supported for code-first definitions. A patch is rejected atomically if any requested field is not patchable; inspect success, outcome, and rejectedPatchKeys before reporting success. APPLIED means replay produced at least one successful side effect. Audit persistence is reported separately through auditRecorded and auditId.
ReplayDataHubRecord is required for every retry. A non-empty patch
also requires EditDataHubQuarantine; callers with replay-only access can
retry the recorded payload unchanged by omitting patch or passing {}.
Update plugin settings:
mutation UpdateSettings($input: DataHubSettingsInput!) {
updateDataHubSettings(input: $input) {
retentionDaysRuns
retentionDaysErrors
}
}
Inside a Vendure Dashboard extension, use its authenticated api client with a
typed document generated from the host application’s Admin API schema:
import { api } from '@vendure/dashboard';
import { graphql } from '@/gql';
const runPipelineDocument = graphql(`
mutation RunDataHubPipeline($pipelineId: ID!, $expectedRevisionId: ID) {
startDataHubPipelineRun(
pipelineId: $pipelineId
expectedRevisionId: $expectedRevisionId
) {
id
status
revisionId
}
}
`);
const result = await api.mutate(runPipelineDocument, {
pipelineId: '1',
expectedRevisionId: null,
});
const run = result.startDataHubPipelineRun;
The Dashboard client supplies the active session and channel tokens. External clients should send the same operation to Vendure’s configured Admin API path with an authenticated administrator session and, when applicable, the target channel token header.
Authorization, lookup, duplicate-code, and create/update validation failures are
returned through the GraphQL errors array. Vendure Dashboard’s api client
rejects the request with an Error that can also expose extensions and
fieldErrors; narrow an unknown caught value before reading those properties.
Do not assume Apollo-specific properties such as graphQLErrors. The exact
extensions.code depends on the originating Vendure or resolver error and is
not guaranteed for every validation path.
Delete mutations use Vendure’s DeletionResponse; inspect result and
message even when the GraphQL request itself succeeds.