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

# Running Targets

> Learn how to run targets using the Singer SDK

# Background

A target is an integration that reads data and writes it to some *target* system. For example, hotglue supports targets for:

* Uploading files to storage systems S3, Azure Blob Storage, or SFTP servers.
* Creating and Updating invoices in ERPs like Netsuite, Sage Intacct, and Dynamics BC
* Upserting records into databases like Postgres, Snowflake, and BigQuery

In most cases, targets expect their input in the form of a [**Singer**](https://www.singer.io/) file, a variation of jsonl for structured streaming data.

# Setting up a local target environment

## Virtual Environments

Dependencies can differ from target to target, so it is best to use a virtual environment to isolate the target's Python dependencies.

You can create a virtual environment named `.venv` in your target workspace with:

```bash theme={null}
python -m venv .venv
```

You can then enter the virtual environment with:

```bash theme={null}
source .venv/bin/activate
```

Finally, you can install the tap's dependencies depending on how they are specified:

|   Dependency File  |              Command              |
| :----------------: | :-------------------------------: |
| `requirements.txt` | `pip install -r requirements.txt` |
|     `setup.py`     |         `pip install -e .`        |
|  `pyproject.toml`  |         `pip install -e .`        |

## Config

Targets require a valid config, which will include fields like API keys, OAuth credentials, and configuration flags.

For example:

```json theme={null}
{
  "client_id": "...",
  "client_secret": "...",
  "refresh_token": "...",
  "access_token": "...",
  "start_date": "2025-01-25T00:00:00Z"
}
```

Most target will include information about the required config values in their README's.

> 💡 To keep your workspace clean, create a `.secrets` folder to store your `config.json`. Run all tap commands out of this folder to make sure your catalogs and output data stay separate from relevant code.

## Using the Hotglue Access Token Endpoint

For OAuth connectors, you can have the target use the [access token endpoint](https://docs.hotglue.com/api-reference/access-tokens/retrieve-access-token) instead of refreshing the token locally by:

**1. Adding this flag to your `config.json`:**

```json theme={null}
{
    "_refresh_token_via_hg_api": true,
    ...
}
```

**2. Setting the following environment variables:**

|  Variable | Description                       |
| :-------: | :-------------------------------- |
|  `TENANT` | Your tenant ID                    |
| `API_KEY` | Your Hotglue API key              |
|   `FLOW`  | The flow ID                       |
|  `ENV_ID` | The environment ID                |
|  `TARGET` | The target ID (e.g. `salesforce`) |

```bash theme={null}
export TENANT="<tenant id>"
export API_KEY="<hotglue api key>"
export FLOW="<flow id>"
export ENV_ID="<environment id>"
export TARGET="<target id>"
```

## Data

If you want to try to reproduce the behavior of a particular [hotglue job](/key-concepts/jobs/sync-jobs), you can download the job folder on your hotglue job page:

<img src="https://mintcdn.com/hotglue/5Ve6qyQIr-eWU9BP/custom-connectors/images/DownloadJobImg.png?fit=max&auto=format&n=5Ve6qyQIr-eWU9BP&q=85&s=d34e7a2e14d2d6f8fe21646164825b99" alt="" width="2224" height="582" data-path="custom-connectors/images/DownloadJobImg.png" />

The etl-output folder will contain the raw input file(s) used by the target. In most cases, you'll see a singular `data.singer` file with all your data:

```jsonl theme={null}
{"type":"SCHEMA","stream":"Invoices","schema":{"type":["object","null"],"properties":{"invoiceId":{"type":["string","null"]},"date":{"type":["string","null"]},"total":{"type":["number","null"]}}},"key_properties":[]}
{"type":"RECORD","stream":"Invoices","record":{"invoiceId":"INV-001","date":"2025-02-11T00:00:00.000Z","total":112.40}}
{"type":"SCHEMA","stream":"InvoicePayments","schema":{"type":["object","null"],"properties":{"paymentId":{"type":["string","null"]},"amount":{"type":["number","null"]}}},"key_properties":[]}
{"type":"RECORD","stream":"InvoicePayments","record":{"paymentId":"PAY-001","amount":85.50}}
```

Place your `data.singer` somewhere accessible by your target. We recommend placing it in a git-ignored `.secrets` with your `config.json` to avoid accidently committing it.

# Running a target

You can now pipe your data into the target. If your target is named `target-salesforce`, you would run:

```
target-salesforce < data.singer --config config.json > target-state.json
```

This will process your singer file line by line and (if supported by the target) write the export results to a file named `target-state.json`.

If you attempted to send two contacts to Salesforce, your target state might look something like this:

```json theme={null}
{
    "bookmarks": {
        "Contacts": [
            {
                "hash": "372f2b3f76de48b1823db1ed2333042ef312ce2ba2b50165467ae64a78c05a71",
                "success": true,
                "id": 900,
                "externalId": "903093"
            }
            {
                "hash": "97a8sdhge48b1823db1ed2333042ef312ce2ba2b5016sd5467ae64a78c05a71",
                "externalId": "903094",
                "error": "Email 'Bi@ll@hotg.lue.com is invalid'"
            }
        ]
    },
    "summary": {
        "Contacts": {
            "success": 0,
            "fail": 1,
            "existing": 0,
            "updated": 1
        }
    }
}
```

Here `id` is the id in Salesforce and `externalId` (if passed on the record) is the id in the source system.

If you prefer to work with [VSCode's Debugger](https://code.visualstudio.com/docs/editor/debugging), you can run the target with the following configuration:

```json theme={null}
{
  "name": "target-salesforce",
  "type": "python",
  "request": "launch",
  "justMyCode": false,
  "program": "../target_salesforce/target.py",
  "cwd": "ABSOLUTE_PATH_TO_TARGET_DIRECTORY/target-salesforce/.secrets",
  "args": ["<", "data.singer", "--config", "config.json", ">", "state.json"],
  "console": "integratedTerminal",
  "python": "ABSOLUTE_PATH_TO_TARGET_DIRECTORY/target-salesforce/.venv/bin/python"
}
```
