affinity-sdk 0.4.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- affinity_sdk-0.4.7/.claude-plugin/commands/affinity-help.md +58 -0
- affinity_sdk-0.4.7/.claude-plugin/hooks/hooks.json +17 -0
- affinity_sdk-0.4.7/.claude-plugin/hooks/pre-xaffinity.sh +36 -0
- affinity_sdk-0.4.7/.claude-plugin/marketplace.json +16 -0
- affinity_sdk-0.4.7/.claude-plugin/plugin.json +27 -0
- affinity_sdk-0.4.7/.claude-plugin/skills/querying-affinity-crm/CLI_REFERENCE.md +349 -0
- affinity_sdk-0.4.7/.claude-plugin/skills/querying-affinity-crm/LIST_EXPORT_EXPAND.md +177 -0
- affinity_sdk-0.4.7/.claude-plugin/skills/querying-affinity-crm/SDK_REFERENCE.md +259 -0
- affinity_sdk-0.4.7/.claude-plugin/skills/querying-affinity-crm/SKILL.md +213 -0
- affinity_sdk-0.4.7/.editorconfig +19 -0
- affinity_sdk-0.4.7/.env.example +3 -0
- affinity_sdk-0.4.7/.gitattributes +7 -0
- affinity_sdk-0.4.7/.github/CODEOWNERS +9 -0
- affinity_sdk-0.4.7/.github/ISSUE_TEMPLATE/bug_report.yml +44 -0
- affinity_sdk-0.4.7/.github/ISSUE_TEMPLATE/feature_request.yml +27 -0
- affinity_sdk-0.4.7/.github/PULL_REQUEST_TEMPLATE/cli_command.md +89 -0
- affinity_sdk-0.4.7/.github/dependabot.yml +12 -0
- affinity_sdk-0.4.7/.github/labels.yml +51 -0
- affinity_sdk-0.4.7/.github/pull_request_template.md +14 -0
- affinity_sdk-0.4.7/.github/workflows/ci.yml +56 -0
- affinity_sdk-0.4.7/.github/workflows/docs.yml +97 -0
- affinity_sdk-0.4.7/.github/workflows/labels.yml +22 -0
- affinity_sdk-0.4.7/.github/workflows/linkcheck.yml +44 -0
- affinity_sdk-0.4.7/.github/workflows/openapi-validation.yml +30 -0
- affinity_sdk-0.4.7/.github/workflows/release.yml +178 -0
- affinity_sdk-0.4.7/.gitignore +58 -0
- affinity_sdk-0.4.7/.pre-commit-config.yaml +55 -0
- affinity_sdk-0.4.7/CHANGELOG.md +94 -0
- affinity_sdk-0.4.7/CODE_OF_CONDUCT.md +96 -0
- affinity_sdk-0.4.7/CONTRIBUTING.md +91 -0
- affinity_sdk-0.4.7/LICENSE +21 -0
- affinity_sdk-0.4.7/PKG-INFO +584 -0
- affinity_sdk-0.4.7/README.md +527 -0
- affinity_sdk-0.4.7/SECURITY.md +10 -0
- affinity_sdk-0.4.7/affinity/__init__.py +137 -0
- affinity_sdk-0.4.7/affinity/cli/__init__.py +7 -0
- affinity_sdk-0.4.7/affinity/cli/click_compat.py +27 -0
- affinity_sdk-0.4.7/affinity/cli/commands/__init__.py +1 -0
- affinity_sdk-0.4.7/affinity/cli/commands/_entity_files_dump.py +216 -0
- affinity_sdk-0.4.7/affinity/cli/commands/_list_entry_fields.py +41 -0
- affinity_sdk-0.4.7/affinity/cli/commands/_v1_parsing.py +52 -0
- affinity_sdk-0.4.7/affinity/cli/commands/company_cmds.py +2100 -0
- affinity_sdk-0.4.7/affinity/cli/commands/completion_cmd.py +31 -0
- affinity_sdk-0.4.7/affinity/cli/commands/config_cmds.py +505 -0
- affinity_sdk-0.4.7/affinity/cli/commands/field_cmds.py +135 -0
- affinity_sdk-0.4.7/affinity/cli/commands/interaction_cmds.py +384 -0
- affinity_sdk-0.4.7/affinity/cli/commands/list_cmds.py +2732 -0
- affinity_sdk-0.4.7/affinity/cli/commands/note_cmds.py +316 -0
- affinity_sdk-0.4.7/affinity/cli/commands/opportunity_cmds.py +1145 -0
- affinity_sdk-0.4.7/affinity/cli/commands/person_cmds.py +1931 -0
- affinity_sdk-0.4.7/affinity/cli/commands/relationship_strength_cmds.py +44 -0
- affinity_sdk-0.4.7/affinity/cli/commands/reminder_cmds.py +450 -0
- affinity_sdk-0.4.7/affinity/cli/commands/resolve_url_cmd.py +125 -0
- affinity_sdk-0.4.7/affinity/cli/commands/task_cmds.py +83 -0
- affinity_sdk-0.4.7/affinity/cli/commands/version_cmd.py +27 -0
- affinity_sdk-0.4.7/affinity/cli/commands/whoami_cmd.py +25 -0
- affinity_sdk-0.4.7/affinity/cli/config.py +108 -0
- affinity_sdk-0.4.7/affinity/cli/context.py +719 -0
- affinity_sdk-0.4.7/affinity/cli/csv_utils.py +120 -0
- affinity_sdk-0.4.7/affinity/cli/errors.py +28 -0
- affinity_sdk-0.4.7/affinity/cli/field_utils.py +355 -0
- affinity_sdk-0.4.7/affinity/cli/logging.py +100 -0
- affinity_sdk-0.4.7/affinity/cli/main.py +184 -0
- affinity_sdk-0.4.7/affinity/cli/options.py +46 -0
- affinity_sdk-0.4.7/affinity/cli/paths.py +32 -0
- affinity_sdk-0.4.7/affinity/cli/progress.py +99 -0
- affinity_sdk-0.4.7/affinity/cli/render.py +1194 -0
- affinity_sdk-0.4.7/affinity/cli/resolve.py +114 -0
- affinity_sdk-0.4.7/affinity/cli/resolvers.py +249 -0
- affinity_sdk-0.4.7/affinity/cli/results.py +44 -0
- affinity_sdk-0.4.7/affinity/cli/runner.py +152 -0
- affinity_sdk-0.4.7/affinity/cli/serialization.py +65 -0
- affinity_sdk-0.4.7/affinity/cli/types.py +70 -0
- affinity_sdk-0.4.7/affinity/client.py +769 -0
- affinity_sdk-0.4.7/affinity/clients/__init__.py +19 -0
- affinity_sdk-0.4.7/affinity/clients/http.py +3664 -0
- affinity_sdk-0.4.7/affinity/clients/pipeline.py +165 -0
- affinity_sdk-0.4.7/affinity/downloads.py +114 -0
- affinity_sdk-0.4.7/affinity/exceptions.py +593 -0
- affinity_sdk-0.4.7/affinity/filters.py +736 -0
- affinity_sdk-0.4.7/affinity/hooks.py +198 -0
- affinity_sdk-0.4.7/affinity/inbound_webhooks.py +295 -0
- affinity_sdk-0.4.7/affinity/models/__init__.py +163 -0
- affinity_sdk-0.4.7/affinity/models/entities.py +793 -0
- affinity_sdk-0.4.7/affinity/models/pagination.py +495 -0
- affinity_sdk-0.4.7/affinity/models/rate_limit_snapshot.py +48 -0
- affinity_sdk-0.4.7/affinity/models/secondary.py +413 -0
- affinity_sdk-0.4.7/affinity/models/types.py +627 -0
- affinity_sdk-0.4.7/affinity/policies.py +40 -0
- affinity_sdk-0.4.7/affinity/progress.py +22 -0
- affinity_sdk-0.4.7/affinity/py.typed +0 -0
- affinity_sdk-0.4.7/affinity/services/__init__.py +42 -0
- affinity_sdk-0.4.7/affinity/services/companies.py +1192 -0
- affinity_sdk-0.4.7/affinity/services/lists.py +1641 -0
- affinity_sdk-0.4.7/affinity/services/opportunities.py +1093 -0
- affinity_sdk-0.4.7/affinity/services/persons.py +1154 -0
- affinity_sdk-0.4.7/affinity/services/rate_limits.py +173 -0
- affinity_sdk-0.4.7/affinity/services/tasks.py +193 -0
- affinity_sdk-0.4.7/affinity/services/v1_only.py +2428 -0
- affinity_sdk-0.4.7/affinity/types.py +83 -0
- affinity_sdk-0.4.7/docs/cli-development-guide.md +586 -0
- affinity_sdk-0.4.7/docs/public/changelog.md +3 -0
- affinity_sdk-0.4.7/docs/public/cli/commands.md +703 -0
- affinity_sdk-0.4.7/docs/public/cli/index.md +121 -0
- affinity_sdk-0.4.7/docs/public/cli/scripting.md +41 -0
- affinity_sdk-0.4.7/docs/public/cli-reference.md +523 -0
- affinity_sdk-0.4.7/docs/public/examples.md +77 -0
- affinity_sdk-0.4.7/docs/public/getting-started.md +120 -0
- affinity_sdk-0.4.7/docs/public/glossary.md +22 -0
- affinity_sdk-0.4.7/docs/public/guides/api-versions-and-routing.md +46 -0
- affinity_sdk-0.4.7/docs/public/guides/authentication.md +52 -0
- affinity_sdk-0.4.7/docs/public/guides/claude-code-plugin.md +86 -0
- affinity_sdk-0.4.7/docs/public/guides/configuration.md +191 -0
- affinity_sdk-0.4.7/docs/public/guides/csv-export.md +313 -0
- affinity_sdk-0.4.7/docs/public/guides/debugging-hooks.md +92 -0
- affinity_sdk-0.4.7/docs/public/guides/errors-and-retries.md +156 -0
- affinity_sdk-0.4.7/docs/public/guides/field-types-and-values.md +126 -0
- affinity_sdk-0.4.7/docs/public/guides/field-values.md +150 -0
- affinity_sdk-0.4.7/docs/public/guides/filtering.md +197 -0
- affinity_sdk-0.4.7/docs/public/guides/ids-and-types.md +21 -0
- affinity_sdk-0.4.7/docs/public/guides/models.md +64 -0
- affinity_sdk-0.4.7/docs/public/guides/opportunity-associations.md +135 -0
- affinity_sdk-0.4.7/docs/public/guides/pagination.md +81 -0
- affinity_sdk-0.4.7/docs/public/guides/performance.md +94 -0
- affinity_sdk-0.4.7/docs/public/guides/rate-limits.md +36 -0
- affinity_sdk-0.4.7/docs/public/guides/sync-vs-async.md +54 -0
- affinity_sdk-0.4.7/docs/public/guides/v1-v2-routing.md +3 -0
- affinity_sdk-0.4.7/docs/public/guides/webhooks.md +226 -0
- affinity_sdk-0.4.7/docs/public/index.md +32 -0
- affinity_sdk-0.4.7/docs/public/reference/client.md +9 -0
- affinity_sdk-0.4.7/docs/public/reference/exceptions.md +3 -0
- affinity_sdk-0.4.7/docs/public/reference/filters.md +3 -0
- affinity_sdk-0.4.7/docs/public/reference/models.md +3 -0
- affinity_sdk-0.4.7/docs/public/reference/services/companies.md +10 -0
- affinity_sdk-0.4.7/docs/public/reference/services/lists.md +5 -0
- affinity_sdk-0.4.7/docs/public/reference/services/opportunities.md +5 -0
- affinity_sdk-0.4.7/docs/public/reference/services/persons.md +5 -0
- affinity_sdk-0.4.7/docs/public/reference/services/tasks.md +5 -0
- affinity_sdk-0.4.7/docs/public/reference/services/v1/auth.md +3 -0
- affinity_sdk-0.4.7/docs/public/reference/services/v1/field-values.md +3 -0
- affinity_sdk-0.4.7/docs/public/reference/services/v1/fields.md +3 -0
- affinity_sdk-0.4.7/docs/public/reference/services/v1/files.md +3 -0
- affinity_sdk-0.4.7/docs/public/reference/services/v1/interactions.md +3 -0
- affinity_sdk-0.4.7/docs/public/reference/services/v1/notes.md +3 -0
- affinity_sdk-0.4.7/docs/public/reference/services/v1/relationships.md +3 -0
- affinity_sdk-0.4.7/docs/public/reference/services/v1/reminders.md +3 -0
- affinity_sdk-0.4.7/docs/public/reference/services/v1/webhooks.md +3 -0
- affinity_sdk-0.4.7/docs/public/reference/types.md +3 -0
- affinity_sdk-0.4.7/docs/public/troubleshooting.md +22 -0
- affinity_sdk-0.4.7/examples/advanced_usage.py +480 -0
- affinity_sdk-0.4.7/examples/async_lifecycle.py +43 -0
- affinity_sdk-0.4.7/examples/basic_usage.py +74 -0
- affinity_sdk-0.4.7/examples/filter_builder.py +36 -0
- affinity_sdk-0.4.7/examples/hooks_debugging.py +40 -0
- affinity_sdk-0.4.7/examples/list_management.py +120 -0
- affinity_sdk-0.4.7/examples/resolve_helpers.py +38 -0
- affinity_sdk-0.4.7/examples/task_polling.py +34 -0
- affinity_sdk-0.4.7/mkdocs.yml +86 -0
- affinity_sdk-0.4.7/pyproject.toml +185 -0
- affinity_sdk-0.4.7/tests/conftest.py +180 -0
- affinity_sdk-0.4.7/tests/fixtures/webhooks/field_value_updated.json +26 -0
- affinity_sdk-0.4.7/tests/fixtures/webhooks/list_entry_created.json +20 -0
- affinity_sdk-0.4.7/tests/fixtures/webhooks/organization_created.json +12 -0
- affinity_sdk-0.4.7/tests/fixtures/webhooks/organization_merged.json +31 -0
- affinity_sdk-0.4.7/tests/fixtures/webhooks/person_created.json +13 -0
- affinity_sdk-0.4.7/tests/fixtures/webhooks/unknown_event.json +7 -0
- affinity_sdk-0.4.7/tests/test_affinity_client_wrapper_additional_coverage.py +194 -0
- affinity_sdk-0.4.7/tests/test_async_file_download_streaming.py +159 -0
- affinity_sdk-0.4.7/tests/test_cli_company_get.py +625 -0
- affinity_sdk-0.4.7/tests/test_cli_config_cmds.py +434 -0
- affinity_sdk-0.4.7/tests/test_cli_csv_export.py +2770 -0
- affinity_sdk-0.4.7/tests/test_cli_datetime_formatting.py +40 -0
- affinity_sdk-0.4.7/tests/test_cli_datetime_header_offsets.py +50 -0
- affinity_sdk-0.4.7/tests/test_cli_domain_linkification.py +24 -0
- affinity_sdk-0.4.7/tests/test_cli_entity_files_dump.py +128 -0
- affinity_sdk-0.4.7/tests/test_cli_error_rendering.py +111 -0
- affinity_sdk-0.4.7/tests/test_cli_field_value_humanization.py +110 -0
- affinity_sdk-0.4.7/tests/test_cli_json_safety.py +288 -0
- affinity_sdk-0.4.7/tests/test_cli_missing_coverage.py +324 -0
- affinity_sdk-0.4.7/tests/test_cli_no_network_commands.py +126 -0
- affinity_sdk-0.4.7/tests/test_cli_opportunity_cmds.py +390 -0
- affinity_sdk-0.4.7/tests/test_cli_pager_logic.py +55 -0
- affinity_sdk-0.4.7/tests/test_cli_person_get.py +114 -0
- affinity_sdk-0.4.7/tests/test_cli_progress_manager.py +9 -0
- affinity_sdk-0.4.7/tests/test_cli_rate_limit_rendering.py +38 -0
- affinity_sdk-0.4.7/tests/test_cli_resolve_url_parsing.py +30 -0
- affinity_sdk-0.4.7/tests/test_cli_serialization.py +174 -0
- affinity_sdk-0.4.7/tests/test_cli_v1_only_cmds.py +363 -0
- affinity_sdk-0.4.7/tests/test_cli_write_ops.py +417 -0
- affinity_sdk-0.4.7/tests/test_client.py +1283 -0
- affinity_sdk-0.4.7/tests/test_env_helpers.py +68 -0
- affinity_sdk-0.4.7/tests/test_field_value_type.py +77 -0
- affinity_sdk-0.4.7/tests/test_file_download_streaming.py +338 -0
- affinity_sdk-0.4.7/tests/test_file_upload_helpers_and_validation.py +91 -0
- affinity_sdk-0.4.7/tests/test_filters.py +390 -0
- affinity_sdk-0.4.7/tests/test_http_client_additional_coverage.py +424 -0
- affinity_sdk-0.4.7/tests/test_http_client_remaining_coverage.py +1210 -0
- affinity_sdk-0.4.7/tests/test_inbound_webhooks.py +144 -0
- affinity_sdk-0.4.7/tests/test_integration_smoke.py +36 -0
- affinity_sdk-0.4.7/tests/test_interactions_and_files_regressions.py +196 -0
- affinity_sdk-0.4.7/tests/test_list_entry_membership_and_opportunities.py +209 -0
- affinity_sdk-0.4.7/tests/test_models.py +858 -0
- affinity_sdk-0.4.7/tests/test_new_features.py +712 -0
- affinity_sdk-0.4.7/tests/test_pagination_iterators.py +486 -0
- affinity_sdk-0.4.7/tests/test_raw_pipeline_hook_events.py +359 -0
- affinity_sdk-0.4.7/tests/test_requirements_additional.py +211 -0
- affinity_sdk-0.4.7/tests/test_services_lists_additional_coverage.py +989 -0
- affinity_sdk-0.4.7/tests/test_services_opportunities_additional_coverage.py +747 -0
- affinity_sdk-0.4.7/tests/test_services_opportunities_tasks_additional_coverage.py +386 -0
- affinity_sdk-0.4.7/tests/test_services_persons_companies_additional_coverage.py +1933 -0
- affinity_sdk-0.4.7/tests/test_services_v1_only_async.py +458 -0
- affinity_sdk-0.4.7/tests/test_small_modules_coverage.py +176 -0
- affinity_sdk-0.4.7/tests/test_transport_and_readonly_mode.py +109 -0
- affinity_sdk-0.4.7/tests/test_v1_only_services_additional_coverage.py +1308 -0
- affinity_sdk-0.4.7/tests/test_v1_only_services_more_coverage.py +602 -0
- affinity_sdk-0.4.7/tools/check_cli_patterns.py +118 -0
- affinity_sdk-0.4.7/tools/generate_requirements_mapping.py +140 -0
- affinity_sdk-0.4.7/tools/sync_plugin_version.py +48 -0
- affinity_sdk-0.4.7/tools/validate_openapi_models.py +436 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
Show a quick reference for using the Affinity Python SDK and xaffinity CLI.
|
|
2
|
+
|
|
3
|
+
## IMPORTANT: Read-Only by Default
|
|
4
|
+
|
|
5
|
+
Always use read-only mode unless the user explicitly approves data modification. CRM data is sensitive!
|
|
6
|
+
|
|
7
|
+
## SDK Quick Start
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
from affinity import Affinity, F
|
|
11
|
+
from affinity.types import PersonId, CompanyId, ListId
|
|
12
|
+
from affinity.policies import Policies, WritePolicy
|
|
13
|
+
|
|
14
|
+
# ALWAYS use read-only mode by default
|
|
15
|
+
with Affinity.from_env(policies=Policies(write=WritePolicy.DENY)) as client:
|
|
16
|
+
# Identity
|
|
17
|
+
me = client.whoami()
|
|
18
|
+
|
|
19
|
+
# Iterate all companies
|
|
20
|
+
for company in client.companies.all():
|
|
21
|
+
print(company.name)
|
|
22
|
+
|
|
23
|
+
# Filter (custom fields only)
|
|
24
|
+
sales = client.persons.list(filter=F.field("Department").equals("Sales"))
|
|
25
|
+
|
|
26
|
+
# Get by ID (use typed IDs!)
|
|
27
|
+
person = client.persons.get(PersonId(123))
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## CLI Quick Start
|
|
31
|
+
|
|
32
|
+
**Always use: `--dotenv --readonly --json`**
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# Standard pattern for queries
|
|
36
|
+
xaffinity --dotenv --readonly person search "John Smith" --json
|
|
37
|
+
xaffinity --dotenv --readonly person get 123 --json
|
|
38
|
+
xaffinity --dotenv --readonly company get domain:acme.com --json
|
|
39
|
+
|
|
40
|
+
# Export to CSV (no --json needed)
|
|
41
|
+
xaffinity --dotenv --readonly person ls --all --csv people.csv
|
|
42
|
+
|
|
43
|
+
# Parse JSON with jq
|
|
44
|
+
xaffinity --dotenv --readonly person ls --json --all | jq '.data.persons[]'
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Key Gotchas
|
|
48
|
+
|
|
49
|
+
1. **Always use `--json`**: For structured, parseable output
|
|
50
|
+
2. **Always use `--readonly`**: Only allow writes when user explicitly approves
|
|
51
|
+
3. **Always use `--dotenv`**: Loads API key from .env file
|
|
52
|
+
4. **Use typed IDs (SDK)**: `PersonId(123)` not `123`
|
|
53
|
+
5. **Filters only work on custom fields** - not `type`, `name`, `domain`, etc.
|
|
54
|
+
|
|
55
|
+
## More Info
|
|
56
|
+
|
|
57
|
+
- SDK docs: https://yaniv-golan.github.io/affinity-sdk/
|
|
58
|
+
- CLI help: `xaffinity --help`
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Ensures API key is configured before xaffinity data commands",
|
|
3
|
+
"hooks": {
|
|
4
|
+
"PreToolUse": [
|
|
5
|
+
{
|
|
6
|
+
"matcher": "Bash",
|
|
7
|
+
"hooks": [
|
|
8
|
+
{
|
|
9
|
+
"type": "command",
|
|
10
|
+
"command": "bash ${CLAUDE_PLUGIN_ROOT}/.claude-plugin/hooks/pre-xaffinity.sh",
|
|
11
|
+
"timeout": 10
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
input=$(cat)
|
|
5
|
+
command=$(echo "$input" | jq -r '.tool_input.command // ""')
|
|
6
|
+
|
|
7
|
+
# Not an xaffinity command - allow
|
|
8
|
+
if [[ "$command" != *"xaffinity"* ]]; then
|
|
9
|
+
exit 0
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
# Config/help commands are always allowed
|
|
13
|
+
if [[ "$command" =~ xaffinity[[:space:]]*(--help|--version) ]] || \
|
|
14
|
+
[[ "$command" =~ xaffinity[[:space:]]+config ]] || \
|
|
15
|
+
[[ "$command" =~ --help ]]; then
|
|
16
|
+
exit 0
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
# Check if API key is configured
|
|
20
|
+
check_result=$(xaffinity --json config check-key 2>/dev/null || echo '{"data":{"configured":false}}')
|
|
21
|
+
configured=$(echo "$check_result" | jq -r '.data.configured // false')
|
|
22
|
+
|
|
23
|
+
if [ "$configured" = "true" ]; then
|
|
24
|
+
exit 0 # Key configured, allow command
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
# Not configured - block with guidance
|
|
28
|
+
cat >&2 << 'EOF'
|
|
29
|
+
{
|
|
30
|
+
"hookSpecificOutput": {
|
|
31
|
+
"permissionDecision": "deny"
|
|
32
|
+
},
|
|
33
|
+
"systemMessage": "BLOCKED: Affinity API key not configured. Tell the user to run 'xaffinity config setup-key' to configure (interactive - user must run it themselves). Then retry."
|
|
34
|
+
}
|
|
35
|
+
EOF
|
|
36
|
+
exit 2
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "affinity-sdk",
|
|
3
|
+
"owner": {
|
|
4
|
+
"name": "Yaniv Golan"
|
|
5
|
+
},
|
|
6
|
+
"metadata": {
|
|
7
|
+
"description": "Plugins for the Affinity Python SDK and xaffinity CLI"
|
|
8
|
+
},
|
|
9
|
+
"plugins": [
|
|
10
|
+
{
|
|
11
|
+
"name": "affinity-sdk",
|
|
12
|
+
"source": "./",
|
|
13
|
+
"description": "Knowledge and commands for using the Affinity Python SDK and xaffinity CLI to query and manage Affinity CRM data"
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "affinity-sdk",
|
|
3
|
+
"description": "Knowledge and commands for using the Affinity Python SDK and xaffinity CLI to query and manage Affinity CRM data",
|
|
4
|
+
"version": "0.4.7",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Yaniv Golan"
|
|
7
|
+
},
|
|
8
|
+
"homepage": "https://github.com/yaniv-golan/affinity-sdk",
|
|
9
|
+
"repository": "https://github.com/yaniv-golan/affinity-sdk",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"affinity",
|
|
13
|
+
"crm",
|
|
14
|
+
"sdk",
|
|
15
|
+
"cli",
|
|
16
|
+
"api"
|
|
17
|
+
],
|
|
18
|
+
"commands": [
|
|
19
|
+
"./.claude-plugin/commands/"
|
|
20
|
+
],
|
|
21
|
+
"skills": [
|
|
22
|
+
"./.claude-plugin/skills/"
|
|
23
|
+
],
|
|
24
|
+
"hooks": [
|
|
25
|
+
"./.claude-plugin/hooks/hooks.json"
|
|
26
|
+
]
|
|
27
|
+
}
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
# CLI Reference
|
|
2
|
+
|
|
3
|
+
Complete command reference for the `xaffinity` CLI.
|
|
4
|
+
|
|
5
|
+
## Installation and Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install "affinity-sdk[cli]"
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
**API Key options (choose one):**
|
|
12
|
+
```bash
|
|
13
|
+
# Option 1: Environment variable
|
|
14
|
+
export AFFINITY_API_KEY="your-api-key"
|
|
15
|
+
|
|
16
|
+
# Option 2: Use --dotenv to load from .env file in current directory
|
|
17
|
+
xaffinity --dotenv whoami
|
|
18
|
+
|
|
19
|
+
# Option 3: Read from file
|
|
20
|
+
xaffinity --api-key-file ~/.affinity-key whoami
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Read-Only Mode (IMPORTANT)
|
|
24
|
+
|
|
25
|
+
**Always use `--readonly` by default** to prevent accidental data modification:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# RECOMMENDED: Use --readonly for all read operations
|
|
29
|
+
xaffinity --readonly person ls --all
|
|
30
|
+
xaffinity --readonly company get 123
|
|
31
|
+
xaffinity --readonly list export 12345 --all --csv entries.csv
|
|
32
|
+
|
|
33
|
+
# Only omit --readonly when user explicitly approves writes
|
|
34
|
+
xaffinity person create --first-name Ada --last-name Lovelace
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Global Options
|
|
38
|
+
|
|
39
|
+
| Option | Description |
|
|
40
|
+
|--------|-------------|
|
|
41
|
+
| `--readonly` | **Recommended** - Prevent write operations |
|
|
42
|
+
| `--json` | Output machine-readable JSON |
|
|
43
|
+
| `--quiet` / `-q` | Suppress non-essential output |
|
|
44
|
+
| `--trace` | Show request/response traces |
|
|
45
|
+
| `--beta` | Enable beta endpoints |
|
|
46
|
+
| `--all` | Fetch all pages |
|
|
47
|
+
| `--csv <path>` | Export to CSV (requires `--all`) |
|
|
48
|
+
| `--csv-bom` | Add UTF-8 BOM for Excel |
|
|
49
|
+
|
|
50
|
+
## Timezone Note
|
|
51
|
+
|
|
52
|
+
**All datetimes from the API are in UTC.** When displaying to users:
|
|
53
|
+
- Convert to user's local timezone or clearly state "UTC"
|
|
54
|
+
- Example: `2025-12-30T13:00:00Z` (UTC) = 3:00 PM Israel time, 5:00 AM PST
|
|
55
|
+
|
|
56
|
+
## Identity
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
xaffinity whoami
|
|
60
|
+
xaffinity whoami --json
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## People
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# List all
|
|
67
|
+
xaffinity person ls
|
|
68
|
+
xaffinity person ls --all
|
|
69
|
+
xaffinity person ls --all --csv people.csv
|
|
70
|
+
|
|
71
|
+
# Search
|
|
72
|
+
xaffinity person search "alice@example.com"
|
|
73
|
+
xaffinity person search "Alice Smith" --all
|
|
74
|
+
|
|
75
|
+
# Get by ID
|
|
76
|
+
xaffinity person get 123
|
|
77
|
+
xaffinity person get 123 --all-fields
|
|
78
|
+
|
|
79
|
+
# Get by resolver
|
|
80
|
+
xaffinity person get email:alice@example.com
|
|
81
|
+
xaffinity person get 'name:"Alice Smith"'
|
|
82
|
+
|
|
83
|
+
# Get with expansions
|
|
84
|
+
xaffinity person get 123 --expand lists
|
|
85
|
+
xaffinity person get 123 --expand list-entries --list "Pipeline"
|
|
86
|
+
xaffinity person get 123 --expand list-entries --list-entry-field Stage
|
|
87
|
+
|
|
88
|
+
# Create
|
|
89
|
+
xaffinity person create --first-name Ada --last-name Lovelace --email ada@example.com
|
|
90
|
+
|
|
91
|
+
# Update
|
|
92
|
+
xaffinity person update 123 --email new@example.com
|
|
93
|
+
|
|
94
|
+
# Delete
|
|
95
|
+
xaffinity person delete 123
|
|
96
|
+
|
|
97
|
+
# Merge (requires --beta)
|
|
98
|
+
xaffinity --beta person merge 111 222
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Companies
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# List all
|
|
105
|
+
xaffinity company ls
|
|
106
|
+
xaffinity company ls --all --csv companies.csv
|
|
107
|
+
|
|
108
|
+
# Search
|
|
109
|
+
xaffinity company search "Acme"
|
|
110
|
+
|
|
111
|
+
# Get by ID
|
|
112
|
+
xaffinity company get 456
|
|
113
|
+
xaffinity company get 456 --all-fields
|
|
114
|
+
|
|
115
|
+
# Get by resolver
|
|
116
|
+
xaffinity company get domain:acme.com
|
|
117
|
+
xaffinity company get 'name:"Acme Corp"'
|
|
118
|
+
|
|
119
|
+
# Get with expansions
|
|
120
|
+
xaffinity company get 456 --expand lists
|
|
121
|
+
xaffinity company get 456 --expand people
|
|
122
|
+
|
|
123
|
+
# Create
|
|
124
|
+
xaffinity company create --name "New Corp" --domain newcorp.com
|
|
125
|
+
|
|
126
|
+
# Update
|
|
127
|
+
xaffinity company update 456 --domain updated.com
|
|
128
|
+
|
|
129
|
+
# Delete
|
|
130
|
+
xaffinity company delete 456
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Lists
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
# List all lists
|
|
137
|
+
xaffinity list ls
|
|
138
|
+
|
|
139
|
+
# Get list details
|
|
140
|
+
xaffinity list view 789
|
|
141
|
+
xaffinity list view 'name:"Deal Pipeline"'
|
|
142
|
+
|
|
143
|
+
# Get list fields
|
|
144
|
+
xaffinity list fields 789
|
|
145
|
+
|
|
146
|
+
# Export list entries
|
|
147
|
+
xaffinity list export 789 --all
|
|
148
|
+
xaffinity list export 789 --all --csv entries.csv
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### List Export with Expansions
|
|
152
|
+
|
|
153
|
+
Export list entries with associated people/companies using `--expand`:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# Export with associated people
|
|
157
|
+
xaffinity list export LIST_ID --expand people --all --csv output.csv --csv-bom
|
|
158
|
+
|
|
159
|
+
# Export with both people and companies (opportunity lists)
|
|
160
|
+
xaffinity list export LIST_ID --expand people --expand companies --all --csv output.csv
|
|
161
|
+
|
|
162
|
+
# Combine with filters
|
|
163
|
+
xaffinity list export LIST_ID --expand people \
|
|
164
|
+
--filter 'Status = "Active"' \
|
|
165
|
+
--all --csv active_with_people.csv --csv-bom
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**Valid expand values:** `people` (opportunity/company lists), `companies` (opportunity/person lists)
|
|
169
|
+
|
|
170
|
+
See [LIST_EXPORT_EXPAND.md](LIST_EXPORT_EXPAND.md) for detailed options: CSV modes, field expansion, association limits, error handling.
|
|
171
|
+
|
|
172
|
+
See [Filtering](#filtering) section for filter syntax reference.
|
|
173
|
+
|
|
174
|
+
## Opportunities
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
# List all
|
|
178
|
+
xaffinity opportunity ls
|
|
179
|
+
xaffinity opportunity ls --all --csv opps.csv
|
|
180
|
+
|
|
181
|
+
# Get by ID
|
|
182
|
+
xaffinity opportunity get 321
|
|
183
|
+
|
|
184
|
+
# Create (requires list ID)
|
|
185
|
+
xaffinity opportunity create --list-id 789 --name "New Deal"
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Field Values
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
# List field values
|
|
192
|
+
xaffinity field-value ls --field-id 123
|
|
193
|
+
|
|
194
|
+
# Get specific value
|
|
195
|
+
xaffinity field-value get 456
|
|
196
|
+
|
|
197
|
+
# Create/update
|
|
198
|
+
xaffinity field-value create --field-id 123 --entity-id 456 --value "New Value"
|
|
199
|
+
xaffinity field-value update 789 --value "Updated"
|
|
200
|
+
|
|
201
|
+
# Delete
|
|
202
|
+
xaffinity field-value delete 789
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Notes
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
# List notes
|
|
209
|
+
xaffinity note ls --person-id 123
|
|
210
|
+
xaffinity note ls --company-id 456
|
|
211
|
+
|
|
212
|
+
# Create note
|
|
213
|
+
xaffinity note create --person-id 123 --content "Meeting notes"
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Interactions (Meetings, Emails, Calls)
|
|
217
|
+
|
|
218
|
+
**Use interactions for meetings, emails, and calls** - auto-synced from calendars and email.
|
|
219
|
+
|
|
220
|
+
**CRITICAL requirements:**
|
|
221
|
+
- **Both `--start-time` AND `--end-time` are REQUIRED** (API will error without them)
|
|
222
|
+
- **Maximum date range is 1 year** - start and end must be within 1 year of each other
|
|
223
|
+
- Interactions only appear if **at least one external contact** was involved
|
|
224
|
+
- Internal-only meetings (team members only) won't appear unless logged with a note
|
|
225
|
+
- Sync lag: Google Calendar ~30 min, Office365 up to 2 hours
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
# List meetings for a person in 2025 (MUST specify date range, max 1 year)
|
|
229
|
+
xaffinity --dotenv --readonly interaction ls --person-id 123 --type meeting \
|
|
230
|
+
--start-time 2025-01-01 --end-time 2025-12-31 --json
|
|
231
|
+
|
|
232
|
+
# For multiple years, query each year separately
|
|
233
|
+
xaffinity --dotenv --readonly interaction ls --person-id 123 --type meeting \
|
|
234
|
+
--start-time 2024-01-01 --end-time 2024-12-31 --json
|
|
235
|
+
|
|
236
|
+
# Other interaction types (same date range requirements)
|
|
237
|
+
xaffinity --dotenv --readonly interaction ls --person-id 123 --type email \
|
|
238
|
+
--start-time 2025-01-01 --end-time 2025-12-31 --json
|
|
239
|
+
xaffinity --dotenv --readonly interaction ls --person-id 123 --type call \
|
|
240
|
+
--start-time 2025-01-01 --end-time 2025-12-31 --json
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Interaction types: `meeting`, `email`, `call`, `chat-message` (or `chat`)
|
|
244
|
+
|
|
245
|
+
**Alternatives for internal users:**
|
|
246
|
+
- Use notes with `isMeeting: true` for meeting records
|
|
247
|
+
- Use Smart Fields (`Last Meeting`, `Next Meeting`) on person/company records
|
|
248
|
+
|
|
249
|
+
## URL Resolution
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
# Parse Affinity UI URLs
|
|
253
|
+
xaffinity resolve-url "https://app.affinity.co/companies/123"
|
|
254
|
+
xaffinity resolve-url "https://mydomain.affinity.com/persons/456"
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## Filtering
|
|
258
|
+
|
|
259
|
+
**Custom fields only** (built-in properties like `type`, `name`, `domain` cannot be filtered server-side):
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
# Equals (quote field names with spaces)
|
|
263
|
+
xaffinity person ls --filter 'Department = "Sales"' --all
|
|
264
|
+
xaffinity person ls --filter '"Primary Email Status" = "Valid"' --all
|
|
265
|
+
|
|
266
|
+
# Contains
|
|
267
|
+
xaffinity company ls --filter 'Industry =~ "Tech"' --all
|
|
268
|
+
|
|
269
|
+
# Starts with
|
|
270
|
+
xaffinity person ls --filter 'Title =^ "VP"' --all
|
|
271
|
+
|
|
272
|
+
# AND / OR
|
|
273
|
+
xaffinity person ls --filter 'Dept = "Sales" & Status = "Active"' --all
|
|
274
|
+
xaffinity company ls --filter 'Region = "US" | Region = "EU"' --all
|
|
275
|
+
|
|
276
|
+
# NOT
|
|
277
|
+
xaffinity person ls --filter '!(Archived = true)' --all
|
|
278
|
+
|
|
279
|
+
# NULL checks
|
|
280
|
+
xaffinity person ls --filter 'Manager != *' --all # is null
|
|
281
|
+
xaffinity person ls --filter 'Manager = *' --all # is not null
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Filter Operators Reference
|
|
285
|
+
|
|
286
|
+
| Meaning | Operator | Example |
|
|
287
|
+
|---------|----------|---------|
|
|
288
|
+
| equals | `=` | `Status = "Active"` |
|
|
289
|
+
| not equals | `!=` | `Status != "Closed"` |
|
|
290
|
+
| contains | `=~` | `Name =~ "Corp"` |
|
|
291
|
+
| starts with | `=^` | `Name =^ "Ac"` |
|
|
292
|
+
| ends with | `=$` | `Name =$ "Inc"` |
|
|
293
|
+
| is null | `!= *` | `Email != *` |
|
|
294
|
+
| is not null | `= *` | `Email = *` |
|
|
295
|
+
| is empty | `= ""` | `Notes = ""` |
|
|
296
|
+
| AND | `&` | `A = 1 & B = 2` |
|
|
297
|
+
| OR | `\|` | `A = 1 \| B = 2` |
|
|
298
|
+
| NOT | `!` | `!(A = 1)` |
|
|
299
|
+
|
|
300
|
+
**Note:** Field names with spaces must be quoted: `"Primary Email Status" = "Valid"`
|
|
301
|
+
|
|
302
|
+
## JSON Output for Scripting
|
|
303
|
+
|
|
304
|
+
All commands support `--json` for machine-readable output:
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
# Get JSON
|
|
308
|
+
xaffinity person ls --json --all
|
|
309
|
+
|
|
310
|
+
# Pipe to jq
|
|
311
|
+
xaffinity person ls --json --all | jq '.data.persons[]'
|
|
312
|
+
xaffinity company get 123 --json | jq '.data.company.name'
|
|
313
|
+
|
|
314
|
+
# Filter built-in properties with jq (since --filter only works on custom fields)
|
|
315
|
+
xaffinity person ls --json --all | jq '.data.persons[] | select(.type == "internal")'
|
|
316
|
+
xaffinity company ls --json --all | jq '.data.companies[] | select(.domain | endswith(".com"))'
|
|
317
|
+
|
|
318
|
+
# Custom CSV with jq
|
|
319
|
+
xaffinity person ls --json --all | jq -r '.data.persons[] | [.id, .name, .primaryEmail] | @csv'
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
## JSON Data Structure
|
|
323
|
+
|
|
324
|
+
```json
|
|
325
|
+
{
|
|
326
|
+
"data": {
|
|
327
|
+
"persons": [...], // for person ls
|
|
328
|
+
"companies": [...], // for company ls
|
|
329
|
+
"opportunities": [...],
|
|
330
|
+
"person": {...}, // for person get
|
|
331
|
+
"company": {...} // for company get
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
## CSV Export
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
# Basic export
|
|
340
|
+
xaffinity person ls --all --csv people.csv
|
|
341
|
+
xaffinity company ls --all --csv companies.csv
|
|
342
|
+
xaffinity opportunity ls --all --csv opps.csv
|
|
343
|
+
xaffinity list export 123 --all --csv entries.csv
|
|
344
|
+
|
|
345
|
+
# Excel-compatible (UTF-8 BOM)
|
|
346
|
+
xaffinity person ls --all --csv people.csv --csv-bom
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
**Note**: `--csv` requires `--all` to fetch all pages.
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# List Export with Expansions
|
|
2
|
+
|
|
3
|
+
Export list entries along with their associated entities (people, companies, opportunities).
|
|
4
|
+
|
|
5
|
+
## Valid Expand Values by List Type
|
|
6
|
+
|
|
7
|
+
| List Type | Valid `--expand` Values |
|
|
8
|
+
|-----------|------------------------|
|
|
9
|
+
| opportunity | `people`, `companies` |
|
|
10
|
+
| person | `companies`, `opportunities` |
|
|
11
|
+
| company | `people`, `opportunities` |
|
|
12
|
+
|
|
13
|
+
Using an invalid expand value for the list type fails with exit code 2.
|
|
14
|
+
|
|
15
|
+
## Basic Usage
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# Export with associated people
|
|
19
|
+
xaffinity list export LIST_ID --expand people --all --csv output.csv --csv-bom
|
|
20
|
+
|
|
21
|
+
# Export with both people and companies (opportunity lists)
|
|
22
|
+
xaffinity list export LIST_ID --expand people --expand companies --all --csv output.csv
|
|
23
|
+
|
|
24
|
+
# Combine with filters
|
|
25
|
+
xaffinity list export LIST_ID --expand people \
|
|
26
|
+
--filter 'Status = "Active"' \
|
|
27
|
+
--all --csv active_with_people.csv --csv-bom
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Controlling Association Limits
|
|
31
|
+
|
|
32
|
+
By default, up to 100 associations are fetched per entry per expand type.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# Limit associations per entry (default: 100)
|
|
36
|
+
xaffinity list export LIST_ID --expand people --expand-max-results 50 --all --csv output.csv
|
|
37
|
+
|
|
38
|
+
# Fetch ALL associations (no limit) - use for complete data
|
|
39
|
+
xaffinity list export LIST_ID --expand people --expand-all --all --csv output.csv
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**Note:** `--expand-max-results` applies per expand type per entry. With `--expand people --expand companies --expand-max-results 10`, you get up to 10 people AND up to 10 companies per entry.
|
|
43
|
+
|
|
44
|
+
## CSV Output Modes
|
|
45
|
+
|
|
46
|
+
### Flat Mode (default)
|
|
47
|
+
|
|
48
|
+
One row per association - easier to filter in spreadsheets:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
xaffinity list export LIST_ID --expand people --csv-mode flat --all --csv flat.csv
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Output:
|
|
55
|
+
```csv
|
|
56
|
+
listEntryId,entityName,Status,expandedType,expandedId,expandedName,expandedEmail
|
|
57
|
+
123,Big Deal,Active,person,789,Alice Smith,alice@example.com
|
|
58
|
+
123,Big Deal,Active,person,790,Bob Jones,bob@example.com
|
|
59
|
+
123,Big Deal,Active,company,101,Acme Corp,
|
|
60
|
+
124,Small Deal,Pending,company,102,Beta Inc,
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Nested Mode
|
|
64
|
+
|
|
65
|
+
One row per entry with JSON arrays in columns:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
xaffinity list export LIST_ID --expand people --csv-mode nested --all --csv nested.csv
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Output:
|
|
72
|
+
```csv
|
|
73
|
+
listEntryId,entityName,Status,_expand_people
|
|
74
|
+
123,Big Deal,Active,"[{""id"": 789, ""name"": ""Alice Smith""}]"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Warning:** `--expand-all` with `--csv-mode nested` can be memory-intensive for entries with many associations.
|
|
78
|
+
|
|
79
|
+
## Expanding Entity Fields (Phase 4)
|
|
80
|
+
|
|
81
|
+
By default, only core fields are included (id, name, email/domain). To include additional fields:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
# Include specific fields on expanded entities
|
|
85
|
+
xaffinity list export LIST_ID --expand people \
|
|
86
|
+
--expand-fields "Title" --expand-fields "Department" \
|
|
87
|
+
--all --csv output.csv
|
|
88
|
+
|
|
89
|
+
# Include all fields of a type (global, enriched, relationship-intelligence)
|
|
90
|
+
xaffinity list export LIST_ID --expand people \
|
|
91
|
+
--expand-field-type enriched \
|
|
92
|
+
--all --csv output.csv
|
|
93
|
+
|
|
94
|
+
# Combine both (union of specified fields and field types)
|
|
95
|
+
xaffinity list export LIST_ID --expand people \
|
|
96
|
+
--expand-fields "Custom Status" --expand-field-type enriched \
|
|
97
|
+
--all --csv output.csv
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Expanding Opportunities (Phase 5)
|
|
101
|
+
|
|
102
|
+
For person and company lists, you can expand associated opportunities:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
# Expand opportunities for all people on a person list
|
|
106
|
+
xaffinity list export LIST_ID --expand opportunities --all --csv output.csv
|
|
107
|
+
|
|
108
|
+
# Scope to a specific opportunity list (recommended for performance)
|
|
109
|
+
xaffinity list export LIST_ID --expand opportunities \
|
|
110
|
+
--expand-opportunities-list "Pipeline" \
|
|
111
|
+
--all --csv output.csv
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Performance Warning:** Without `--expand-opportunities-list`, the CLI searches ALL opportunity lists you have access to. This can be very slow for large workspaces. Always specify `--expand-opportunities-list` when possible.
|
|
115
|
+
|
|
116
|
+
## Filtering Expanded Associations (Phase 5)
|
|
117
|
+
|
|
118
|
+
Filter which associations are included based on field values:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
# Only include people named "Alice"
|
|
122
|
+
xaffinity list export LIST_ID --expand people \
|
|
123
|
+
--expand-filter "name=Alice" \
|
|
124
|
+
--all --csv output.csv
|
|
125
|
+
|
|
126
|
+
# Exclude inactive associations
|
|
127
|
+
xaffinity list export LIST_ID --expand people \
|
|
128
|
+
--expand-filter "status!=Inactive" \
|
|
129
|
+
--all --csv output.csv
|
|
130
|
+
|
|
131
|
+
# Multiple conditions (AND logic)
|
|
132
|
+
xaffinity list export LIST_ID --expand people \
|
|
133
|
+
--expand-filter "name=Alice,primaryEmail!=none" \
|
|
134
|
+
--all --csv output.csv
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Supported operators:
|
|
138
|
+
- `field=value` - exact match
|
|
139
|
+
- `field!=value` - not equal
|
|
140
|
+
|
|
141
|
+
Multiple conditions are separated by `,` or `;` and use AND logic.
|
|
142
|
+
|
|
143
|
+
## Error Handling
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
# Default: stop on first error
|
|
147
|
+
xaffinity list export LIST_ID --expand people --all --csv output.csv
|
|
148
|
+
|
|
149
|
+
# Continue on per-entry errors (skip failed entries)
|
|
150
|
+
xaffinity list export LIST_ID --expand people --expand-on-error skip --all --csv output.csv
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Use `--expand-on-error skip` for permissive exports where partial data is acceptable.
|
|
154
|
+
|
|
155
|
+
## Important Constraints
|
|
156
|
+
|
|
157
|
+
1. **No cursor with expand:** `--cursor` cannot be combined with `--expand`. Use `--all` for complete exports.
|
|
158
|
+
|
|
159
|
+
2. **Memory considerations:** `--expand-all` with `--csv-mode nested` loads all associations into memory per entry. For entries with hundreds of associations, prefer `--csv-mode flat`.
|
|
160
|
+
|
|
161
|
+
3. **Truncation warnings:** When associations are truncated due to `--expand-max-results`, a warning is emitted at the end of the export.
|
|
162
|
+
|
|
163
|
+
4. **Opportunities expansion is expensive:** Without `--expand-opportunities-list`, expanding opportunities requires searching all opportunity lists, which can be very slow.
|
|
164
|
+
|
|
165
|
+
## Options Reference
|
|
166
|
+
|
|
167
|
+
| Option | Type | Default | Description |
|
|
168
|
+
|--------|------|---------|-------------|
|
|
169
|
+
| `--expand` | choice (repeatable) | - | Expand type: `people`, `companies`, or `opportunities` |
|
|
170
|
+
| `--expand-max-results` | int | 100 | Max associations per entry per type |
|
|
171
|
+
| `--expand-all` | flag | false | Fetch all associations (no limit) |
|
|
172
|
+
| `--expand-fields` | string (repeatable) | - | Specific fields to include |
|
|
173
|
+
| `--expand-field-type` | choice (repeatable) | - | Field types: `global`, `enriched`, `relationship-intelligence` |
|
|
174
|
+
| `--expand-on-error` | choice | `raise` | Error handling: `raise` or `skip` |
|
|
175
|
+
| `--csv-mode` | choice | `flat` | CSV format: `flat` or `nested` |
|
|
176
|
+
| `--expand-filter` | string | - | Filter associations (e.g., `field=value`) |
|
|
177
|
+
| `--expand-opportunities-list` | string | - | Scope `--expand opportunities` to a specific list |
|