CI/CD Pipelines
GitHub Actions
Generic CI pattern
#!/usr/bin/env bash
set -euo pipefail
# Authenticate via environment
export LEV_API_KEY="${LEV_API_KEY:?LEV_API_KEY must be set}"
# Fetch and process
lev -o json deals list --all > /tmp/deals.json
echo "Fetched $(jq '.data | length' /tmp/deals.json) deals"Write operations fail with exit code 2 when output is piped and --yes is not provided. This is intentional — it prevents accidental mutations in automated pipelines.
Scripting Patterns
Create and capture the ID
DEAL_ID=$(lev --yes -q deals create --title "New Deal")
echo "Created deal $DEAL_ID"The -q flag emits only the resource ID, making it easy to capture in a variable.
Chain commands
# Create a deal, then immediately add it to a pipeline
DEAL_ID=$(lev --yes -q deals create --title "123 Main St Acquisition" --loan-type acquisition)
lev --yes pipelines move --deal-id "$DEAL_ID" --pipeline-id 10 --status-id 1
echo "Deal $DEAL_ID created and added to pipeline"Conditional logic on exit codes
See CLI Reference for the full exit code table.
Data Export
CSV export
lev -o csv deals list --all > deals.csv
lev -o csv contacts list --type lender > lender-contacts.csv
lev -o csv placements list --deal-id 2303 > placements.csvJSON with jq filtering
Combine resources
# Get a deal with all sub-resources in one call
lev deals get 2303 --include financials,properties,team -o json > deal-full.json
# Or combine separately
lev -o json deals get 2303 > deal.json
lev -o json placements list --deal-id 2303 > placements.json
lev -o json term-sheets list 2303 > term-sheets.jsonBulk Operations
Fetch all records
lev deals list --allThis streams all pages with a progress bar. A safety limit of 10,000 records applies by default — override with --max-records:
lev contacts list --all --max-records 50000Pipe IDs between commands
# Get IDs of all permanent loan deals, then fetch full details for each
lev -q deals list --loan-type permanent | while read -r DEAL_ID; do
lev deals get "$DEAL_ID" --include financials -o json >> permanent-deals.jsonl
doneWhen possible, use --include on the list command to embed sub-resources in a single paginated request. Looping per-ID is slower and consumes more rate limit budget.
LLM Agent Integration
The CLI was built with LLM agents in mind. When an agent like Claude Code, Cursor, or Windsurf runs a CLI command, the output is automatically piped — which means the CLI emits structured JSON without any extra flags. This makes the CLI a natural tool-use surface for agents that can execute shell commands.
Why the CLI works well for agents
Example: agent-driven deal workflow
An LLM agent with shell access can chain CLI commands to accomplish multi-step workflows:
# Agent creates a deal and captures the ID
DEAL_ID=$(lev --yes -q deals create --title "123 Main St Acquisition" --loan-type acquisition --loan-amount 5000000)
# Agent fetches lender matches
lev lenders search --state NY --limit 5
# Agent adds the deal to a pipeline
lev --yes pipelines move --deal-id "$DEAL_ID" --pipeline-id 10 --status-id 1
# Agent retrieves the full deal context for summarization
lev deals get "$DEAL_ID" --include financials,properties,teamUse MCP when the agent needs conversational tool discovery and OAuth-scoped access. Use the CLI when the agent has shell access and you want deterministic, scriptable operations. They complement each other — MCP for interactive copilots, CLI for automated agent workflows.
Error Handling in Scripts
Structured error output
When the CLI encounters an error in JSON mode, it emits a structured error object:
{
"error": {
"status": 404,
"type": "not_found",
"message": "Deal not found"
},
"request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}Retry with backoff
#!/usr/bin/env bash
set -euo pipefail
MAX_RETRIES=3
RETRY_DELAY=5
for attempt in $(seq 1 $MAX_RETRIES); do
if lev -o json deals list --all > deals.json 2>&1; then
echo "Success on attempt $attempt"
break
fi
EXIT_CODE=$?
if [ "$EXIT_CODE" -eq 7 ] && [ "$attempt" -lt "$MAX_RETRIES" ]; then
echo "Rate limited — retrying in ${RETRY_DELAY}s (attempt $attempt/$MAX_RETRIES)"
sleep $RETRY_DELAY
RETRY_DELAY=$((RETRY_DELAY * 2))
else
echo "Failed with exit code $EXIT_CODE"
exit $EXIT_CODE
fi
doneDebug logging
LEV_DEBUG_LOG=/tmp/lev-debug.log lev deals list --verbose
# Request IDs, timing, and headers are written to the log file