> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stackone.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Build Workflow

> The order to build a connector in — pull first, get authentication working, then build actions and iterate.

Building a connector is a loop, and the order matters: every action you write depends on authentication already working. Validate each stage before moving to the next.

```mermaid theme={null}
flowchart LR
    A[Pull existing or create] --> B[Build authentication]
    B --> C[Connect an account]
    C --> D[Build actions]
    D --> E[Test and debug]
    E --> D
    E --> F[Publish]

    style A fill:#ecfdf5,stroke:#10b981,color:#065f46
    style B fill:#ecfdf5,stroke:#10b981,color:#065f46
    style C fill:#ecfdf5,stroke:#10b981,color:#065f46
    style D fill:#dbeafe,stroke:#3b82f6,color:#1e40af
    style E fill:#dbeafe,stroke:#3b82f6,color:#1e40af
    style F fill:#fef9c3,stroke:#eab308,color:#854d0e
```

This assumes you've already got the [CLI installed and authenticated](/connector-building/first-connector).

## Pull existing or create

Always check whether a connector already exists before writing one, since starting from the registry gives you a working foundation. Files save to `./connectors/[provider]/` by default:

```bash theme={null}
stackone pull --connector [provider] --profile [profile-label]
ls connectors/[provider]/
```

If nothing exists to pull, the agent writes the files for you, laid out as described in [File Structure](/connector-yaml-reference/file-structure).

## Build authentication

<Warning>
  Don't move on until authentication works. Everything else depends on it.
</Warning>

Configure authentication in the main connector file. The common patterns:

<Tabs>
  <Tab title="API Key (Bearer)">
    ```yaml theme={null}
    authentication:
      - custom:
          type: custom
          label: API Key
          authorization:
            type: bearer
            token: $.credentials.apiKey
          configFields:
            - key: apiKey
              label: API Key
              type: password
              required: true
              secret: true
          testActionsIds:
            - list_users  # simple action to test authentication
    ```
  </Tab>

  <Tab title="API Key (Header)">
    ```yaml theme={null}
    authentication:
      - custom:
          type: custom
          label: API Key
          authorization:
            type: none
          customHeaders:
            X-API-Key: $.credentials.apiKey
          configFields:
            - key: apiKey
              label: API Key
              type: password
              required: true
              secret: true
    ```
  </Tab>

  <Tab title="Basic Auth">
    ```yaml theme={null}
    authentication:
      - custom:
          type: custom
          label: Basic Auth
          authorization:
            type: basic
            username: $.credentials.username
            password: $.credentials.password
          configFields:
            - key: username
              label: Username
              type: text
              required: true
            - key: password
              label: Password
              type: password
              required: true
              secret: true
    ```
  </Tab>
</Tabs>

Add one simple action — a `list_users` or equivalent — and use it to prove authentication works before building anything else.

## Connect an account

Most providers offer sandbox or developer accounts. Check the provider's developer portal to sign up and generate credentials, and note any rate limits or restrictions that apply to sandbox access.

For local development, keep the account config and credentials in separate files:

```bash theme={null}
echo '{"environment": "production", "provider": "[provider]"}' > account.json
echo '{"apiKey": "your_sandbox_api_key"}' > credentials.json
```

<Warning>
  Add `credentials.json` to `.gitignore`. Keep sandbox credentials separate from production ones.
</Warning>

Then run your test action against those files:

```bash theme={null}
stackone run \
  --connector connectors/[provider]/[provider].connector.s1.yaml \
  --account account.json \
  --credentials credentials.json \
  --action-id list_users \
  --debug
```

<Accordion title="Alternative: push and link an account instead">
  Rather than local credential files, you can push the connector and link an account in the dashboard, then run against that account by ID:

  ```bash theme={null}
  stackone push connectors/[provider]/ --profile [profile]
  # link the account in the dashboard, then:
  stackone run \
    --connector connectors/[provider]/[provider].connector.s1.yaml \
    --account-id [account-id] \
    --action-id list_users
  ```

  `[profile]` is the name you set with `stackone init`.

  A pushed connector appears in the dashboard alongside the StackOne ones, so linking an account against it is the same flow as any other connector: [create a connector profile](/gateway/quickstart#setup-connector-profile), then [link an account](/gateway/quickstart#link-account). Other linking methods are covered in [Linking Accounts](/connect/managing-connectors/linking-accounts).
</Accordion>

## Build actions and iterate

With authentication proven, add your remaining actions to the resource partials. Each action is built from [step functions](/connector-yaml-reference/step-functions). Then cycle: validate the syntax, run the action with `--debug`, fix, repeat.

If the actions should return a normalized shape rather than the provider's own, see [Defined Output Schemas](/connector-building/defined-output-schemas).

```bash theme={null}
stackone validate connectors/[provider]/ --watch
```

Running `validate` with `--watch` keeps checking as you edit, so you catch schema mistakes without rerunning by hand.

<Tip>
  The [Playground](/embed/call-actions/troubleshooting/playground) also runs your connector's actions in natural language, which is handy for a quick check without the CLI.
</Tip>

## Debugging

Add `--debug` to any `stackone run` to surface:

* The raw HTTP request sent to the provider — URL, method, headers, body
* The full response body, before any mapping is applied
* The inputs and outputs of each step
* The resolved values of any JSONPath or JEXL expressions

<Accordion title="Empty or incorrect results">
  When mapping produces something unexpected, work backwards from the raw response:

  <Steps>
    <Step title="Check the raw response first">
      Temporarily return the unmapped data so you can see what the provider actually sent:

      ```yaml theme={null}
      result:
        data: $.steps.get_employees.output.data  # raw, before map_fields
      ```
    </Step>

    <Step title="Verify the response structure">
      Run with `--debug` and inspect the real paths:

      ```bash theme={null}
      stackone run --debug ... | jq '.steps.get_employees.output'
      ```
    </Step>

    <Step title="Add fields one at a time">
      Start with a single field in `map_fields`, confirm it resolves, then add the rest.
    </Step>

    <Step title="Check the expression context">
      Inline fields in `map_fields` reference the field directly (`$.email`), not via the step (`$.get_employees.email`).
    </Step>
  </Steps>
</Accordion>

| Symptom                          | Likely cause                    | Fix                                                              |
| -------------------------------- | ------------------------------- | ---------------------------------------------------------------- |
| 401 Unauthorized                 | Invalid credentials             | Check the API key, regenerate if needed                          |
| Empty data array                 | Wrong `dataKey` path            | Use `--debug` to verify the actual response structure            |
| Null field values                | Incorrect expression path       | Check the nested paths match the real response                   |
| Pagination returns the same data | Wrong `iterator.key`            | Check the provider's docs for the expected cursor parameter name |
| Enum not translated              | `matchExpression` case mismatch | The provider might return `"ACTIVE"` rather than `"Active"`      |

## Publish

When the connector behaves, push it to your project's registry so linked accounts can use it:

```bash theme={null}
stackone push connectors/[provider]/ --profile [profile]
```

For team workflows, connectors are usually published through a Git pipeline rather than a direct push. See [GitHub CI/CD](/connector-building/github-ci-cd).

<Card title="Connector Versioning" icon="code-branch" href="/connector-building/connector-versioning">
  Release new versions without breaking existing linked accounts.
</Card>

### Other ways to test

Once it's published, `stackone run` is no longer the only way in. Each of these exercises the deployed version against a linked account's real credentials, so they need a [connector profile](/gateway/quickstart#setup-connector-profile) and a [linked account](/gateway/quickstart#link-account) first:

| Surface                                                              | Use it to                                                                     |
| -------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| [Request Tester](/embed/call-actions/troubleshooting/request-tester) | Pick an action in the dashboard, fill in parameters, and inspect the response |
| [`POST /actions/rpc`](/embed/call-actions/rpc-http)                  | Call the action the way your own backend will                                 |
| [Playground](/embed/call-actions/troubleshooting/playground)         | Check an agent picks the right action from your descriptions                  |

<Warning>
  An action only shows up on these surfaces once it's enabled on the [connector profile](/secure/scoping-connectors).
</Warning>

## Next steps

<CardGroup cols={2}>
  <Card title="Defined Output Schemas" icon="arrows-rotate" href="/connector-building/defined-output-schemas">
    Map provider responses onto a schema of your own.
  </Card>

  <Card title="Step Functions" icon="diagram-project" href="/connector-yaml-reference/step-functions">
    The building blocks each action is made of.
  </Card>

  <Card title="StackOne CLI" icon="terminal" href="/connector-building/stackone-cli">
    Full command reference for pull, validate, run, and push.
  </Card>

  <Card title="Implementing Events" icon="webhook" href="/connector-building/implementing-events">
    Define the events your connector emits.
  </Card>
</CardGroup>
