> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://developer.deel.com/cli/guides/automation/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://developer.deel.com/_mcp/server. # Scripting and CI > Patterns for running the Deel CLI in shell scripts and CI pipelines This page collects the patterns that make unattended runs reliable: non-interactive authentication, a pinned version, error handling, and job polling. The CLI prints a JSON envelope, reports failures in a stable error envelope, and sends an idempotency key with every write. ## Non-interactive authentication Inject the token as a secret and pass it through the environment or stdin. Never write it to the workspace. ```bash export DEEL_TOKEN="$DEEL_PAT" # from your CI secret store export DEEL_ENV=demo # or prod, explicitly deel auth status --fields valid >/dev/null ``` `deel auth status` is a preflight check: it fails with `auth.missing` or `auth.invalid` before the script does any work. ## Pin the CLI version Beta releases can change commands and output. Pin the version in automation and upgrade deliberately. ```bash curl -fsSL https://cli.deel.com/v0.1.1/install.sh | sh # or, with npm npm install -g @deel-org/cli@0.1.1 ``` ## Fail fast and read error codes Use `set -e` semantics for the exit status and jq for the reason. ```bash set -euo pipefail if ! deel adjustments create --invoice --input file://bonus.json >result.json 2>error.json; then jq -r '"deel failed: \(.error.code): \(.error.message) (request \(.error.request_id // "n/a"))"' error.json >&2 exit 1 fi ADJUSTMENT_ID=$(jq -r '.data.adjustment_id' result.json) ``` Retryable conditions (`429`, `5xx`) are already retried by the CLI up to three times. A script that sees `http.429` after that should back off for longer rather than loop immediately. ## Retry safety Every mutating command carries a deterministic idempotency key derived from its content. Re-running a failed script step sends the same key and cannot create a duplicate record. If a step must create a second identical record on purpose, pass a new `--idempotency-key`. See [Idempotency and retries](/cli/usage/idempotency-and-retries). ## Build bodies with jq Generate request bodies from your own data instead of templating strings. ```bash jq -n --arg contract "$CONTRACT_ID" --arg amount "$AMOUNT" --arg date "$(date +%F)" \ '{type:"BONUS", amount:($amount|tonumber), contract_id:$contract, description:"Monthly bonus", date_submitted:$date}' \ | deel adjustments create --invoice --input - ``` For bulk operations, map a CSV or database export into the array shape the operation expects and pass it with `--input file://`. Bulk adjustment operations accept up to 50 items per request; split larger sets into batches. ## Follow asynchronous jobs Bulk commands return a `job_id`. Poll until the job reaches a terminal status and inspect failed items. See [Asynchronous jobs](/cli/usage/async-jobs) for a complete loop. ```bash JOB_ID=$(deel adjustments create-bulk --invoice --input file://batch.json --quiet) until deel job status "$JOB_ID" --jq '.status' --raw | grep -Eq 'SUCCEEDED|FAILED'; do sleep 5; done deel jobs status --job_id="$JOB_ID" --jq '.items[] | select(.status == "FAILED")' ``` ## GitHub Actions example > **Warning** > > This job writes real payroll data in production. Review the batch file before wiring this into a real pipeline, and treat `DEEL_ENV: prod` as a deliberate choice, not a default to copy unexamined. ```yaml jobs: submit-adjustments: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 22 - run: npm install -g @deel-org/cli@0.1.1 - name: Submit payroll adjustments env: DEEL_TOKEN: ${{ secrets.DEEL_PAT }} DEEL_ENV: prod run: | deel auth status --fields valid deel adjustments create-bulk --payroll --input file://payroll/adjustments.json --fields job_id ``` Runners set `CI=true`, so the CLI treats the session as non-interactive and prints JSON regardless of flags. ## Logging in CI The local log is written to the runner's home directory and discarded with the job. Disable it with `DEEL_LOG=off` if the runner's filesystem is shared or persisted, or keep it and upload it as an artifact for auditing; tokens are masked and bodies are omitted by default. ## Next steps #### [Output and filtering](/cli/usage/output) Shape command output for the next step in a pipeline #### [Errors and exit codes](/cli/usage/errors) The complete list of error codes > Build apps and integrations that extend and enhance the Deel services.