GoliathDevelopersGet an API key
Reference/Workflowsgenerated from the gateway manifest

createWorkflow

Create a workflow automation.

POST/api/v1/callWRITEidempotent · 24 hruns as the key's owner
View as Markdown

Create a workflow automation: a new group plus its initial DRAFT version. workflowDomain is CONTACT | DEAL | PROPERTY | APPOINTMENT | EVENT. There is no workflowType: the variable is gone, so sending it is a 400 unknown_variable, not a no-op. Which channels a workflow messages on is not a property of the group: it is the union of the channels its communicationConfig configures with its own text_action / email_action steps, reported as channels on this response and on getWorkflow (the paginated listings carry channelsAcrossVersions; see them for how the two differ). A create seeds NO communication config unless a templateId brings one; adding a text or email step with updateWorkflowGraph seeds that channel's editor defaults, and a sender must still be chosen before promoting. Optional templateId seeds the draft graph from a registered starter template. Edit the draft with updateWorkflowGraph, whose step vocabulary is far more than texts and emails (tags, team and round-robin assignment, teammate notifications, tasks, appointments, deals, custom fields, AI employees, webhooks, Slack, chaining workflows), then ship it with promoteWorkflowDraft. Optional sendWindow is the starting SENDING SCHEDULE (updateWorkflowSendWindow's shape); absent takes the template's when it has one, else the platform default. The graph never carries it: change it later with updateWorkflowSendWindow. THE SKIP-TRACE WORKFLOW (watches property signals in a buy-box and skip-traces each owner into a contact) is created with workflowDomain: "PROPERTY", systemCategory: "PROPERTY_SIGNAL_SKIP_TRACE" and templateId: "property_signal_skip_trace" together, as the onboarding package does. Its draft is a trigger, a create-contact step and an end. It is promoted only with TWO triggers: a MUTATION trigger whose filter names at least one property signal type (propertySignalTypes, in ONE flat OR group: a run starts when a property gets any of them), and a MATCH trigger whose filter is an AND root carrying a top-level spicyLeadScore minimum (the buy-box; places and property types are optional conditions beside it). Read the draft with getWorkflowVersionGraph, replace its trigger with those two through updateWorkflowGraph, then promoteWorkflowDraft; getWorkflow.draftValidation names whichever is missing. Each run spends a skip-trace credit. Its daily run limit is the ORGANIZATION's, shared by every skip-trace workflow: setSkipTraceDailyCap sets it, getWorkflowThrottleUsage reads it.

curl https://server.goliathdata.com/api/v1/call \
  -H "Authorization: Bearer $GOLIATH_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "operationId": "createWorkflow",
    "variables": {
      "name": "<String>",
      "workflowDomain": "PROPERTY"
    }
  }'
import { GoliathClient } from '@goliath-data/sdk'

const goliath = new GoliathClient({
  apiKey: process.env.GOLIATH_API_KEY!,
  baseUrl: 'https://server.goliathdata.com',
})

// Enum values as strings: the SDK's enum types aren't exported yet, so assert to the method's variables type.
const variables = {
  name: '<String>',
  workflowDomain: 'PROPERTY'
} as Parameters<typeof goliath.workflows.createWorkflow>[0]

const result = await goliath.workflows.createWorkflow(variables, { idempotencyKey: crypto.randomUUID() })
const res = await fetch('https://server.goliathdata.com/api/v1/call', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.GOLIATH_API_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': crypto.randomUUID(),
  },
  body: JSON.stringify({
    operationId: 'createWorkflow',
    variables: {
      name: '<String>',
      workflowDomain: 'PROPERTY'
    }
  }),
})
const { data, errors } = await res.json()

Variables

The example sends only what the schema requires. Some operations also need one of several optional variables (one filter or another, say); the description above says which.

nameString!required
descriptionString
workflowDomainWorkflowDomain!required
PROPERTYCONTACTPIPELINE_ITEMDEALAPPOINTMENTEVENTSLACKCONTRACT
templateIdString
systemCategoryString
sendWindowJSON

Response

What comes back under data: a list shows as one entry, and a value as its type.

response shape
{
  "data": {
    "workflowAutomationsMutation": {
      "createWorkflowGroup": {
        "id": "<ID>",
        "name": "…",
        "status": "DRAFT",
        "channels": [
          "TEXT"
        ],
        "workflowDomain": "PROPERTY",
        "pendingDraft": {
          "id": "<ID>",
          "name": "…",
          "status": "DRAFT"
        }
      }
    }
  }
}

Errors

Idempotency

Send an Idempotency-Key of 1 to 255 characters. A finished request retried with the same key replays its stored response, marked Idempotency-Replayed: true; one still in flight returns 409 idempotency_conflict. Keys expire after 24 hours. Write without fear →