DRAGOPS
DRAGOPS
DocumentationGuidesAuthor an integration pack

Author an integration pack

Create a custom integration pack to add pre-built nodes for any HTTP API.

If DRAGOPS does not ship a pack for the API you need, you can create one. A pack is a single JSON file (.dragops-pack.json) that defines the service's authentication, one or more action nodes, and how input pins map to HTTP request parameters and response fields map back to output pins.

Before you begin

  • Familiarity with the target API — endpoints, authentication method, request and response formats
  • Understanding of integration packs

Step 1: Create the manifest skeleton

Every pack starts with the same structure:

{
  "packVersion": "1.0",
  "metadata": {},
  "connection": {},
  "nodes": []
}

The packVersion is always "1.0". The following steps fill in each section.

Step 2: Define metadata

The metadata section identifies the pack in the node library and on the Integrations page.

{
  "metadata": {
    "slug": "acme-api",
    "name": "Acme API",
    "description": "Interact with the Acme platform API.",
    "version": "1.0.0",
    "category": "utility",
    "tags": ["acme", "crm"]
  }
}
FieldDescription
slugUnique identifier. Lowercase letters, numbers, and hyphens only.
nameDisplay name shown in the node library and Integrations page.
descriptionShort summary of what this pack does.
versionSemantic version (for example, 1.0.0).
categoryGrouping category (for example, enrichment, ticketing, event-logging, utility).
tagsSearch tags. Users can find the pack by searching for any of these terms.

You can optionally include iconUrl with a path to the pack's icon.

Step 3: Define the connection

The connection section tells DRAGOPS what credentials the service requires and how to authenticate.

API key authentication

For services that use a single API key:

{
  "connection": {
    "provider": "acme-api",
    "authType": "api_key",
    "credentials": [
      {
        "name": "api-key",
        "label": "API Key",
        "description": "Your Acme API key from the developer dashboard",
        "placeholder": "Enter your API key...",
        "type": "secret",
        "required": true
      }
    ],
    "baseUrl": "https://api.acme.com/v2",
    "testRequest": {
      "method": "GET",
      "pathTemplate": "/me",
      "expectedStatus": 200
    }
  }
}

Basic authentication with dynamic base URL

For services that require multiple credentials (like Jira, which needs an email, API token, and instance URL):

{
  "connection": {
    "provider": "jira",
    "authType": "basic",
    "credentials": [
      {
        "name": "user-email",
        "label": "User Email",
        "type": "text",
        "required": true
      },
      {
        "name": "api-token",
        "label": "API Token",
        "type": "secret",
        "required": true
      },
      {
        "name": "base-url",
        "label": "Instance URL",
        "description": "Your Jira Cloud URL (e.g., https://mycompany.atlassian.net)",
        "type": "url",
        "required": true
      }
    ],
    "baseUrl": ""
  }
}

When baseUrl is empty, the base URL is resolved from a credential field at runtime. The node's execution specification indicates which credential provides the URL (see Step 4).

Connection fields

FieldDescription
providerIdentifier linking to the DRAGOPS connections system. Must be unique.
authTypeOne of api_key, bearer, basic, or oauth2_client_credentials.
credentialsArray of credential fields the user must provide.
baseUrlBase URL for all API requests. Set to "" if the URL comes from a credential field.
testRequestOptional. A lightweight request to validate credentials work (method, path, expected status).

Credential field options

FieldDescription
nameMachine name used to reference this field in node execution specifications.
labelDisplay label shown in the connection form.
descriptionHelp text shown below the input field. Optional.
placeholderPlaceholder text in the input field. Optional.
typesecret (masked input), text (visible input), or url (URL validation).
requiredWhether this field is required to save the connection.

Step 4: Define nodes

Each node represents a single API operation. A node has input pins, output pins, and an execution specification that maps between them.

Node structure

{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "nodeTypeId": "Acme-ListItems",
  "title": "List Items",
  "category": "Acme API",
  "nodeCategory": "action",
  "isPure": false,
  "isBuiltin": true,
  "inputPins": [
    { "name": "exec", "type": "exec" },
    { "name": "limit", "type": "int", "displayName": "Limit" }
  ],
  "outputPins": [
    { "name": "exec", "type": "exec" },
    { "name": "items", "type": "object", "displayName": "Items" },
    { "name": "status", "type": "int", "displayName": "Status" }
  ],
  "properties": [],
  "executionSpec": {}
}
FieldDescription
idUnique UUID for this node definition.
nodeTypeIdUnique identifier. Convention: {Prefix}-{Action} (for example, VT-GetIPReport).
titleDisplay name in the node library and on the canvas.
categoryCategory name in the node library (typically the service name).
nodeCategoryAlways "action" for pack nodes.
isPureAlways false — pack nodes make HTTP calls (side effects).
isBuiltinAlways true.
inputPinsInput pin definitions. Always include { "name": "exec", "type": "exec" } first.
outputPinsOutput pin definitions. Always include { "name": "exec", "type": "exec" } first.
propertiesAlways [] for pack nodes.

Execution specification

The execution specification tells the execution engine how to construct the HTTP request and extract the response.

{
  "executionSpec": {
    "method": "GET",
    "pathTemplate": "/items/{{itemId}}",
    "parameters": [
      { "pin": "itemId", "in": "path" }
    ],
    "auth": {
      "type": "header",
      "credentials": ["api-key"],
      "headerName": "x-api-key"
    },
    "responseMapping": [
      { "pin": "item", "path": "$body.data" },
      { "pin": "status", "path": "$status" }
    ]
  }
}

Method and path

FieldDescription
methodHTTP method: GET, POST, PUT, PATCH, or DELETE.
pathTemplateURL path with {{pinName}} placeholders for path parameters.

Parameters

Each parameter maps an input pin to a location in the HTTP request:

in valueDescriptionExample
pathReplaces {{pinName}} in the path template/issues/{{issueKey}}/issues/OPS-42
queryAdded as a URL query parameter?jql=project%3DOPS
headerAdded as a request headerX-Custom: value
body_fieldAdded as a field in the request body{"fields": {"summary": "..."}}

The optional key field overrides the parameter name. For example, { "pin": "projectKey", "in": "body_field", "key": "fields.project.key" } maps the projectKey pin to a nested body path.

Authentication

The auth object defines how credentials are injected:

typeBehaviorRequired fields
headerSends a credential as a custom headerheaderName — the header name (for example, x-apikey)
bearerSends Authorization: Bearer {token}First credential is the token
basicSends Authorization: Basic base64(user:pass)At least two credentials (username + password)
querySends a credential as a query parameterqueryParam — the parameter name
oauth2_client_credentialsObtains and caches a bearer tokentokenUrl, at least two credentials (client ID + secret)

For services with a dynamic base URL (where the URL comes from a credential field), add baseUrlCredential with the credential field name:

{
  "auth": {
    "type": "basic",
    "credentials": ["user-email", "api-token", "base-url"],
    "baseUrlCredential": "base-url"
  }
}

Response mapping

Each response mapping extracts a value from the HTTP response and delivers it through an output pin:

Path prefixSource
$bodyThe parsed JSON response body ($body for the whole body, $body.data.id for a nested field)
$statusThe HTTP status code (integer)
$headersResponse headers ($headers.x-rate-limit-remaining for a specific header)

Request body

For POST, PUT, and PATCH requests, add a body object:

{
  "body": {
    "contentType": "application/json",
    "mode": "template",
    "template": "{\"fields\":{\"project\":{\"key\":\"{{projectKey}}\"}}}"
  }
}
FieldDescription
contentTypeapplication/json or application/x-www-form-urlencoded.
modepins (collect body_field parameters into an object), template (interpolate {{pinName}}), or raw (use a single pin as the body).
templateTemplate string for template mode. Use {{pinName}} for interpolation.

Step 5: Add defaults (optional)

Pack-level defaults apply to all nodes:

{
  "defaults": {
    "headers": {
      "Accept": "application/json"
    },
    "timeout": 30
  }
}
FieldDescription
headersHeaders sent with every request from this pack.
timeoutRequest timeout in seconds (1 to 300). Default is 30.

Step 6: Validate and test

  1. Save the file with a .dragops-pack.json extension.
  2. Create a connection for the pack's provider on the Connections page.
  3. Add pack nodes to a pattern and wire test data to the inputs.
  4. Run the pattern and verify the nodes execute successfully.

Check the execution log for HTTP request and response details. If a node returns an error, verify the path template, parameter mappings, and authentication configuration in the manifest.

Complete example

This minimal pack has two nodes for a fictional "Acme API" — one to list items and one to get a single item:

{
  "packVersion": "1.0",
  "metadata": {
    "slug": "acme-api",
    "name": "Acme API",
    "description": "Interact with the Acme platform API.",
    "version": "1.0.0",
    "category": "utility",
    "tags": ["acme"]
  },
  "connection": {
    "provider": "acme-api",
    "authType": "api_key",
    "credentials": [
      {
        "name": "api-key",
        "label": "API Key",
        "type": "secret",
        "required": true
      }
    ],
    "baseUrl": "https://api.acme.com/v2",
    "testRequest": {
      "method": "GET",
      "pathTemplate": "/me",
      "expectedStatus": 200
    }
  },
  "defaults": {
    "headers": { "Accept": "application/json" },
    "timeout": 30
  },
  "nodes": [
    {
      "id": "10000001-0000-4000-8000-000000000001",
      "nodeTypeId": "Acme-ListItems",
      "title": "List Items",
      "category": "Acme API",
      "nodeCategory": "action",
      "isPure": false,
      "isBuiltin": true,
      "inputPins": [
        { "name": "exec", "type": "exec" },
        { "name": "limit", "type": "int", "displayName": "Limit" }
      ],
      "outputPins": [
        { "name": "exec", "type": "exec" },
        { "name": "items", "type": "object", "displayName": "Items" },
        { "name": "total", "type": "int", "displayName": "Total" },
        { "name": "status", "type": "int", "displayName": "Status" }
      ],
      "properties": [],
      "executionSpec": {
        "method": "GET",
        "pathTemplate": "/items",
        "parameters": [
          { "pin": "limit", "in": "query" }
        ],
        "auth": {
          "type": "header",
          "credentials": ["api-key"],
          "headerName": "x-api-key"
        },
        "responseMapping": [
          { "pin": "items", "path": "$body.data" },
          { "pin": "total", "path": "$body.total" },
          { "pin": "status", "path": "$status" }
        ]
      }
    },
    {
      "id": "10000001-0000-4000-8000-000000000002",
      "nodeTypeId": "Acme-GetItem",
      "title": "Get Item",
      "category": "Acme API",
      "nodeCategory": "action",
      "isPure": false,
      "isBuiltin": true,
      "inputPins": [
        { "name": "exec", "type": "exec" },
        { "name": "itemId", "type": "string", "displayName": "Item ID", "required": true }
      ],
      "outputPins": [
        { "name": "exec", "type": "exec" },
        { "name": "item", "type": "object", "displayName": "Item" },
        { "name": "status", "type": "int", "displayName": "Status" }
      ],
      "properties": [],
      "executionSpec": {
        "method": "GET",
        "pathTemplate": "/items/{{itemId}}",
        "parameters": [
          { "pin": "itemId", "in": "path" }
        ],
        "auth": {
          "type": "header",
          "credentials": ["api-key"],
          "headerName": "x-api-key"
        },
        "responseMapping": [
          { "pin": "item", "path": "$body.data" },
          { "pin": "status", "path": "$status" }
        ]
      }
    }
  ]
}

For real-world examples, see the VirusTotal and Jira pack reference pages.

What is next?

On this page