insim-cli 1.0.0__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.
- insim_cli-1.0.0/PKG-INFO +263 -0
- insim_cli-1.0.0/cli_anything/insim/README.md +226 -0
- insim_cli-1.0.0/cli_anything/insim/__init__.py +2 -0
- insim_cli-1.0.0/cli_anything/insim/core/__init__.py +0 -0
- insim_cli-1.0.0/cli_anything/insim/core/account.py +67 -0
- insim_cli-1.0.0/cli_anything/insim/core/api.py +68 -0
- insim_cli-1.0.0/cli_anything/insim/core/auth.py +74 -0
- insim_cli-1.0.0/cli_anything/insim/core/calls.py +93 -0
- insim_cli-1.0.0/cli_anything/insim/core/campaigns.py +141 -0
- insim_cli-1.0.0/cli_anything/insim/core/contacts.py +231 -0
- insim_cli-1.0.0/cli_anything/insim/core/lists.py +192 -0
- insim_cli-1.0.0/cli_anything/insim/core/qualifications.py +139 -0
- insim_cli-1.0.0/cli_anything/insim/core/sms.py +158 -0
- insim_cli-1.0.0/cli_anything/insim/core/stats.py +53 -0
- insim_cli-1.0.0/cli_anything/insim/core/templates.py +137 -0
- insim_cli-1.0.0/cli_anything/insim/insim_cli.py +194 -0
- insim_cli-1.0.0/cli_anything/insim/skills/SKILL.md +617 -0
- insim_cli-1.0.0/cli_anything/insim/utils/__init__.py +0 -0
- insim_cli-1.0.0/cli_anything/insim/utils/output.py +112 -0
- insim_cli-1.0.0/insim_cli.egg-info/PKG-INFO +263 -0
- insim_cli-1.0.0/insim_cli.egg-info/SOURCES.txt +32 -0
- insim_cli-1.0.0/insim_cli.egg-info/dependency_links.txt +1 -0
- insim_cli-1.0.0/insim_cli.egg-info/entry_points.txt +2 -0
- insim_cli-1.0.0/insim_cli.egg-info/not-zip-safe +1 -0
- insim_cli-1.0.0/insim_cli.egg-info/requires.txt +7 -0
- insim_cli-1.0.0/insim_cli.egg-info/top_level.txt +1 -0
- insim_cli-1.0.0/setup.cfg +4 -0
- insim_cli-1.0.0/setup.py +54 -0
- insim_cli-1.0.0/tests/test_auth.py +67 -0
- insim_cli-1.0.0/tests/test_calls.py +35 -0
- insim_cli-1.0.0/tests/test_campaigns.py +51 -0
- insim_cli-1.0.0/tests/test_contacts.py +94 -0
- insim_cli-1.0.0/tests/test_integration.py +79 -0
- insim_cli-1.0.0/tests/test_sms.py +51 -0
insim_cli-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: insim-cli
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: inSIM CLI — Control your SMS, contacts and campaigns from the command line. Built for AI agents and humans alike.
|
|
5
|
+
Home-page: https://github.com/ArdaryinSIM/insim-cli
|
|
6
|
+
Author: Reach Technologies SAS
|
|
7
|
+
Author-email: dev@reach-technologies.com
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
11
|
+
Classifier: Topic :: Communications :: Telephony
|
|
12
|
+
Classifier: Topic :: Office/Business
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
Requires-Dist: click>=8.0.0
|
|
22
|
+
Requires-Dist: requests>=2.28.0
|
|
23
|
+
Requires-Dist: prompt-toolkit>=3.0.0
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
26
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
27
|
+
Dynamic: author
|
|
28
|
+
Dynamic: author-email
|
|
29
|
+
Dynamic: classifier
|
|
30
|
+
Dynamic: description
|
|
31
|
+
Dynamic: description-content-type
|
|
32
|
+
Dynamic: home-page
|
|
33
|
+
Dynamic: provides-extra
|
|
34
|
+
Dynamic: requires-dist
|
|
35
|
+
Dynamic: requires-python
|
|
36
|
+
Dynamic: summary
|
|
37
|
+
|
|
38
|
+
# insim-cli
|
|
39
|
+
|
|
40
|
+
**Control your SMS, contacts, and campaigns from the command line.**
|
|
41
|
+
|
|
42
|
+
[](https://pypi.org/project/insim-cli/)
|
|
43
|
+
[](https://pypi.org/project/insim-cli/)
|
|
44
|
+
[](https://opensource.org/licenses/MIT)
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Why insim-cli?
|
|
49
|
+
|
|
50
|
+
**Stop switching between tabs.** Manage your entire SMS business from your terminal.
|
|
51
|
+
|
|
52
|
+
- **Send SMS in seconds** — one command, done. No login pages, no clicks.
|
|
53
|
+
- **AI-ready** — Claude, GPT, Gemini, and any LLM can pilot inSIM with structured JSON output.
|
|
54
|
+
- **Automate your campaigns** — create lists, compose messages, and launch campaigns programmatically.
|
|
55
|
+
- **Track everything** — call logs, delivery reports, click tracking, all at your fingertips.
|
|
56
|
+
- **Works everywhere** — macOS, Linux, Windows. Any terminal. Any automation tool.
|
|
57
|
+
|
|
58
|
+
## Quick Start (2 minutes)
|
|
59
|
+
|
|
60
|
+
### 1. Install
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install insim-cli
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 2. Login
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
insim login your@email.com --key YOUR_ACCESS_KEY
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Your access key is in your inSIM account settings, under API.
|
|
73
|
+
|
|
74
|
+
### 3. Start using
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# Find a contact
|
|
78
|
+
insim contacts search "John Doe"
|
|
79
|
+
|
|
80
|
+
# Send an SMS
|
|
81
|
+
insim sms send "+33612345678" "Hello from the command line!"
|
|
82
|
+
|
|
83
|
+
# Check your stats
|
|
84
|
+
insim stats overview
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
That's it. You're ready.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## What can you do?
|
|
92
|
+
|
|
93
|
+
### Send SMS
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# Simple message
|
|
97
|
+
insim sms send "+33612345678" "Meeting confirmed for tomorrow at 10am"
|
|
98
|
+
|
|
99
|
+
# With link tracking
|
|
100
|
+
insim sms send "+33612345678" "Check our offer: [link]" --url "https://your-site.com/promo"
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Manage Contacts
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
# Smart search (handles typos, inversions, accents)
|
|
107
|
+
insim contacts search "cecile dubois"
|
|
108
|
+
|
|
109
|
+
# Find by phone number
|
|
110
|
+
insim contacts find-phone "0612345678"
|
|
111
|
+
|
|
112
|
+
# Tag contacts for segmentation
|
|
113
|
+
insim contacts tags-add CONTACT_ID vip premium
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Launch Campaigns
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
# Create a list with all your contacts
|
|
120
|
+
insim lists create "Spring Promo"
|
|
121
|
+
insim lists add-all LIST_ID
|
|
122
|
+
|
|
123
|
+
# Create and launch a campaign
|
|
124
|
+
insim campaigns create --name "Spring Promo" --message "20% off this week!" --list LIST_ID
|
|
125
|
+
insim campaigns start CAMPAIGN_ID
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Track Calls
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
# See missed calls
|
|
132
|
+
insim calls list --type missed
|
|
133
|
+
|
|
134
|
+
# Qualify a call
|
|
135
|
+
insim calls qualify CALL_ID --option OPTION_ID --notes "Interested in premium plan"
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### View Statistics
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
# Global overview
|
|
142
|
+
insim stats overview
|
|
143
|
+
|
|
144
|
+
# SMS sent this month
|
|
145
|
+
insim stats overview --from "2026-04-01"
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## For AI Agents
|
|
151
|
+
|
|
152
|
+
insim-cli is designed to be used by AI coding agents like **Claude Code**, **GitHub Copilot**, **Cursor**, and others.
|
|
153
|
+
|
|
154
|
+
### Setup for agents
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
export INSIM_LOGIN="your@email.com"
|
|
158
|
+
export INSIM_ACCESS_KEY="your_access_key"
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### JSON output
|
|
162
|
+
|
|
163
|
+
Add `--json` to any command for machine-readable output:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
insim --json contacts search "john doe"
|
|
167
|
+
insim --json sms list --limit 5
|
|
168
|
+
insim --json account info
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### AI workflow example
|
|
172
|
+
|
|
173
|
+
An agent receiving "send a message to John saying meeting is confirmed":
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
# Step 1: Find the contact
|
|
177
|
+
insim --json contacts search "john"
|
|
178
|
+
# → {"contacts": [{"phone_number": "+33612345678", "score": 100}]}
|
|
179
|
+
|
|
180
|
+
# Step 2: Send the SMS
|
|
181
|
+
insim sms send "+33612345678" "Meeting is confirmed"
|
|
182
|
+
# → SMS sent successfully!
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### SKILL.md
|
|
186
|
+
|
|
187
|
+
The package includes a comprehensive `SKILL.md` file with **25 detailed workflows** that any AI agent can read to understand exactly how to use every feature of insim-cli. The REPL mode displays the path to this file on startup.
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Interactive Mode (REPL)
|
|
192
|
+
|
|
193
|
+
Run `insim` without arguments for an interactive session with **auto-completion** and **command history**:
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
$ insim
|
|
197
|
+
SKILL.md: /path/to/skills/SKILL.md
|
|
198
|
+
inSIM CLI — Interactive Mode
|
|
199
|
+
Type commands without 'insim' prefix. Type 'help' or 'exit'.
|
|
200
|
+
|
|
201
|
+
insim> contacts search "mourad"
|
|
202
|
+
insim> sms send "+33664456336" "Hello!"
|
|
203
|
+
insim> stats overview
|
|
204
|
+
insim> exit
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## All Commands
|
|
210
|
+
|
|
211
|
+
| Group | Commands |
|
|
212
|
+
|-------|----------|
|
|
213
|
+
| **Auth** | `login`, `logout`, `whoami` |
|
|
214
|
+
| **Contacts** | `list`, `search`, `find-phone`, `detail`, `switch-pro`, `delete`, `tags-add`, `tags-remove`, `custom-fields` |
|
|
215
|
+
| **SMS** | `list`, `detail`, `conversation`, `send` |
|
|
216
|
+
| **Calls** | `list`, `qualify`, `clictocall` |
|
|
217
|
+
| **Qualifications** | `list`, `options`, `options-create`, `options-update`, `options-delete`, `stats` |
|
|
218
|
+
| **Account** | `info`, `webhooks-set` |
|
|
219
|
+
| **Lists** | `list`, `create`, `detail`, `update`, `delete`, `add-contacts`, `remove-contacts`, `add-all` |
|
|
220
|
+
| **Campaigns** | `list`, `create`, `detail`, `cancel`, `start` |
|
|
221
|
+
| **Templates** | `list`, `create`, `update`, `delete`, `send` |
|
|
222
|
+
| **Stats** | `overview`, `clicks` |
|
|
223
|
+
|
|
224
|
+
Run `insim COMMAND --help` for details on any command.
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Configuration
|
|
229
|
+
|
|
230
|
+
| Method | Priority | Description |
|
|
231
|
+
|--------|----------|-------------|
|
|
232
|
+
| Environment variables | Highest | `INSIM_LOGIN`, `INSIM_ACCESS_KEY` |
|
|
233
|
+
| Credentials file | Lower | `~/.insim/credentials.json` (created by `insim login`) |
|
|
234
|
+
|
|
235
|
+
Custom server URL:
|
|
236
|
+
```bash
|
|
237
|
+
export INSIM_BASE_URL="https://custom-server.com"
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Development
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
git clone https://github.com/ArdaryinSIM/insim-cli.git
|
|
246
|
+
cd insim-cli
|
|
247
|
+
pip install -e ".[dev]"
|
|
248
|
+
pytest tests/ -v
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## About inSIM
|
|
254
|
+
|
|
255
|
+
[inSIM](https://insim.app) is a SaaS platform for SMS management, CRM, and marketing campaigns. It connects to your phone via a mobile app and lets you send, receive, and track SMS from your computer.
|
|
256
|
+
|
|
257
|
+
**insim-cli** is the official command-line interface, built by [Reach Technologies SAS](https://reach-technologies.com).
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## License
|
|
262
|
+
|
|
263
|
+
MIT
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# insim-cli
|
|
2
|
+
|
|
3
|
+
**Control your SMS, contacts, and campaigns from the command line.**
|
|
4
|
+
|
|
5
|
+
[](https://pypi.org/project/insim-cli/)
|
|
6
|
+
[](https://pypi.org/project/insim-cli/)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Why insim-cli?
|
|
12
|
+
|
|
13
|
+
**Stop switching between tabs.** Manage your entire SMS business from your terminal.
|
|
14
|
+
|
|
15
|
+
- **Send SMS in seconds** — one command, done. No login pages, no clicks.
|
|
16
|
+
- **AI-ready** — Claude, GPT, Gemini, and any LLM can pilot inSIM with structured JSON output.
|
|
17
|
+
- **Automate your campaigns** — create lists, compose messages, and launch campaigns programmatically.
|
|
18
|
+
- **Track everything** — call logs, delivery reports, click tracking, all at your fingertips.
|
|
19
|
+
- **Works everywhere** — macOS, Linux, Windows. Any terminal. Any automation tool.
|
|
20
|
+
|
|
21
|
+
## Quick Start (2 minutes)
|
|
22
|
+
|
|
23
|
+
### 1. Install
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install insim-cli
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 2. Login
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
insim login your@email.com --key YOUR_ACCESS_KEY
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Your access key is in your inSIM account settings, under API.
|
|
36
|
+
|
|
37
|
+
### 3. Start using
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Find a contact
|
|
41
|
+
insim contacts search "John Doe"
|
|
42
|
+
|
|
43
|
+
# Send an SMS
|
|
44
|
+
insim sms send "+33612345678" "Hello from the command line!"
|
|
45
|
+
|
|
46
|
+
# Check your stats
|
|
47
|
+
insim stats overview
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
That's it. You're ready.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## What can you do?
|
|
55
|
+
|
|
56
|
+
### Send SMS
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# Simple message
|
|
60
|
+
insim sms send "+33612345678" "Meeting confirmed for tomorrow at 10am"
|
|
61
|
+
|
|
62
|
+
# With link tracking
|
|
63
|
+
insim sms send "+33612345678" "Check our offer: [link]" --url "https://your-site.com/promo"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Manage Contacts
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# Smart search (handles typos, inversions, accents)
|
|
70
|
+
insim contacts search "cecile dubois"
|
|
71
|
+
|
|
72
|
+
# Find by phone number
|
|
73
|
+
insim contacts find-phone "0612345678"
|
|
74
|
+
|
|
75
|
+
# Tag contacts for segmentation
|
|
76
|
+
insim contacts tags-add CONTACT_ID vip premium
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Launch Campaigns
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# Create a list with all your contacts
|
|
83
|
+
insim lists create "Spring Promo"
|
|
84
|
+
insim lists add-all LIST_ID
|
|
85
|
+
|
|
86
|
+
# Create and launch a campaign
|
|
87
|
+
insim campaigns create --name "Spring Promo" --message "20% off this week!" --list LIST_ID
|
|
88
|
+
insim campaigns start CAMPAIGN_ID
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Track Calls
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# See missed calls
|
|
95
|
+
insim calls list --type missed
|
|
96
|
+
|
|
97
|
+
# Qualify a call
|
|
98
|
+
insim calls qualify CALL_ID --option OPTION_ID --notes "Interested in premium plan"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### View Statistics
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# Global overview
|
|
105
|
+
insim stats overview
|
|
106
|
+
|
|
107
|
+
# SMS sent this month
|
|
108
|
+
insim stats overview --from "2026-04-01"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## For AI Agents
|
|
114
|
+
|
|
115
|
+
insim-cli is designed to be used by AI coding agents like **Claude Code**, **GitHub Copilot**, **Cursor**, and others.
|
|
116
|
+
|
|
117
|
+
### Setup for agents
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
export INSIM_LOGIN="your@email.com"
|
|
121
|
+
export INSIM_ACCESS_KEY="your_access_key"
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### JSON output
|
|
125
|
+
|
|
126
|
+
Add `--json` to any command for machine-readable output:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
insim --json contacts search "john doe"
|
|
130
|
+
insim --json sms list --limit 5
|
|
131
|
+
insim --json account info
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### AI workflow example
|
|
135
|
+
|
|
136
|
+
An agent receiving "send a message to John saying meeting is confirmed":
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
# Step 1: Find the contact
|
|
140
|
+
insim --json contacts search "john"
|
|
141
|
+
# → {"contacts": [{"phone_number": "+33612345678", "score": 100}]}
|
|
142
|
+
|
|
143
|
+
# Step 2: Send the SMS
|
|
144
|
+
insim sms send "+33612345678" "Meeting is confirmed"
|
|
145
|
+
# → SMS sent successfully!
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### SKILL.md
|
|
149
|
+
|
|
150
|
+
The package includes a comprehensive `SKILL.md` file with **25 detailed workflows** that any AI agent can read to understand exactly how to use every feature of insim-cli. The REPL mode displays the path to this file on startup.
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Interactive Mode (REPL)
|
|
155
|
+
|
|
156
|
+
Run `insim` without arguments for an interactive session with **auto-completion** and **command history**:
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
$ insim
|
|
160
|
+
SKILL.md: /path/to/skills/SKILL.md
|
|
161
|
+
inSIM CLI — Interactive Mode
|
|
162
|
+
Type commands without 'insim' prefix. Type 'help' or 'exit'.
|
|
163
|
+
|
|
164
|
+
insim> contacts search "mourad"
|
|
165
|
+
insim> sms send "+33664456336" "Hello!"
|
|
166
|
+
insim> stats overview
|
|
167
|
+
insim> exit
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## All Commands
|
|
173
|
+
|
|
174
|
+
| Group | Commands |
|
|
175
|
+
|-------|----------|
|
|
176
|
+
| **Auth** | `login`, `logout`, `whoami` |
|
|
177
|
+
| **Contacts** | `list`, `search`, `find-phone`, `detail`, `switch-pro`, `delete`, `tags-add`, `tags-remove`, `custom-fields` |
|
|
178
|
+
| **SMS** | `list`, `detail`, `conversation`, `send` |
|
|
179
|
+
| **Calls** | `list`, `qualify`, `clictocall` |
|
|
180
|
+
| **Qualifications** | `list`, `options`, `options-create`, `options-update`, `options-delete`, `stats` |
|
|
181
|
+
| **Account** | `info`, `webhooks-set` |
|
|
182
|
+
| **Lists** | `list`, `create`, `detail`, `update`, `delete`, `add-contacts`, `remove-contacts`, `add-all` |
|
|
183
|
+
| **Campaigns** | `list`, `create`, `detail`, `cancel`, `start` |
|
|
184
|
+
| **Templates** | `list`, `create`, `update`, `delete`, `send` |
|
|
185
|
+
| **Stats** | `overview`, `clicks` |
|
|
186
|
+
|
|
187
|
+
Run `insim COMMAND --help` for details on any command.
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Configuration
|
|
192
|
+
|
|
193
|
+
| Method | Priority | Description |
|
|
194
|
+
|--------|----------|-------------|
|
|
195
|
+
| Environment variables | Highest | `INSIM_LOGIN`, `INSIM_ACCESS_KEY` |
|
|
196
|
+
| Credentials file | Lower | `~/.insim/credentials.json` (created by `insim login`) |
|
|
197
|
+
|
|
198
|
+
Custom server URL:
|
|
199
|
+
```bash
|
|
200
|
+
export INSIM_BASE_URL="https://custom-server.com"
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Development
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
git clone https://github.com/ArdaryinSIM/insim-cli.git
|
|
209
|
+
cd insim-cli
|
|
210
|
+
pip install -e ".[dev]"
|
|
211
|
+
pytest tests/ -v
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## About inSIM
|
|
217
|
+
|
|
218
|
+
[inSIM](https://insim.app) is a SaaS platform for SMS management, CRM, and marketing campaigns. It connects to your phone via a mobile app and lets you send, receive, and track SMS from your computer.
|
|
219
|
+
|
|
220
|
+
**insim-cli** is the official command-line interface, built by [Reach Technologies SAS](https://reach-technologies.com).
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## License
|
|
225
|
+
|
|
226
|
+
MIT
|
|
File without changes
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Account info and configuration."""
|
|
2
|
+
import click
|
|
3
|
+
from cli_anything.insim.core.api import InsimAPIError
|
|
4
|
+
from cli_anything.insim.core.auth import require_auth
|
|
5
|
+
from cli_anything.insim.utils.output import output, print_error
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@click.group()
|
|
9
|
+
def account():
|
|
10
|
+
"""Account info and configuration."""
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@account.command("info")
|
|
15
|
+
def account_info():
|
|
16
|
+
"""Show account information: login, plan, credits, options."""
|
|
17
|
+
ctx = click.get_current_context()
|
|
18
|
+
json_mode = ctx.obj.get("json", False) if ctx.obj else False
|
|
19
|
+
try:
|
|
20
|
+
api = require_auth()
|
|
21
|
+
result = api.post("/api/v2/account")
|
|
22
|
+
if json_mode:
|
|
23
|
+
output(result, json_mode=True)
|
|
24
|
+
else:
|
|
25
|
+
acct = result.get("account", {})
|
|
26
|
+
click.echo(click.style("Account Information", bold=True))
|
|
27
|
+
click.echo(f" {click.style('Login', fg='cyan')}: {acct.get('login', '')}")
|
|
28
|
+
click.echo(f" {click.style('Plan', fg='cyan')}: {acct.get('plan', '')}")
|
|
29
|
+
click.echo(f" {click.style('Credits', fg='cyan')}: {acct.get('credits', '')}")
|
|
30
|
+
options = acct.get("options", {})
|
|
31
|
+
if options:
|
|
32
|
+
click.echo(f" {click.style('Options', fg='cyan')}:")
|
|
33
|
+
for key, val in options.items():
|
|
34
|
+
click.echo(f" {key}: {val}")
|
|
35
|
+
except InsimAPIError as e:
|
|
36
|
+
print_error(e.error_code, str(e), e.field, e.extra)
|
|
37
|
+
raise SystemExit(1)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@account.command("webhooks-set")
|
|
41
|
+
@click.option("--sms", default="", help="Incoming SMS webhook URL.")
|
|
42
|
+
@click.option("--dlr", default="", help="Delivery status webhook URL.")
|
|
43
|
+
@click.option("--clicks", default="", help="Link clicks webhook URL.")
|
|
44
|
+
@click.option("--calls", default="", help="Call events webhook URL.")
|
|
45
|
+
@click.option("--qualif", default="", help="Call qualifications webhook URL.")
|
|
46
|
+
def account_webhooks_set(sms, dlr, clicks, calls, qualif):
|
|
47
|
+
"""Set account webhook URLs."""
|
|
48
|
+
ctx = click.get_current_context()
|
|
49
|
+
json_mode = ctx.obj.get("json", False) if ctx.obj else False
|
|
50
|
+
try:
|
|
51
|
+
api = require_auth()
|
|
52
|
+
result = api.post("/api/v2/account/webhooks", {
|
|
53
|
+
"webhooks": {
|
|
54
|
+
"incoming_sms": sms,
|
|
55
|
+
"delivery_status": dlr,
|
|
56
|
+
"link_clicks": clicks,
|
|
57
|
+
"call_events": calls,
|
|
58
|
+
"call_qualifications": qualif,
|
|
59
|
+
},
|
|
60
|
+
})
|
|
61
|
+
if json_mode:
|
|
62
|
+
output(result, json_mode=True)
|
|
63
|
+
else:
|
|
64
|
+
click.echo(click.style("Webhooks updated.", fg="green"))
|
|
65
|
+
except InsimAPIError as e:
|
|
66
|
+
print_error(e.error_code, str(e), e.field, e.extra)
|
|
67
|
+
raise SystemExit(1)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""HTTP client for inSIM API v2."""
|
|
2
|
+
import requests
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class InsimAPIError(Exception):
|
|
7
|
+
"""Error returned by the inSIM API."""
|
|
8
|
+
def __init__(self, message: str, error_code: str = "", status: int = 0, field: str = "", extra: dict | None = None):
|
|
9
|
+
self.error_code = error_code
|
|
10
|
+
self.status = status
|
|
11
|
+
self.field = field
|
|
12
|
+
self.extra = extra or {}
|
|
13
|
+
super().__init__(message)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class InsimAPI:
|
|
17
|
+
"""Client for inSIM API v2."""
|
|
18
|
+
|
|
19
|
+
def __init__(self, base_url: str, login: str, access_key: str):
|
|
20
|
+
self.base_url = base_url.rstrip("/")
|
|
21
|
+
self.login = login
|
|
22
|
+
self.access_key = access_key
|
|
23
|
+
self.session = requests.Session()
|
|
24
|
+
self.session.headers.update({
|
|
25
|
+
"Content-Type": "application/json",
|
|
26
|
+
"User-Agent": "insim-cli/1.0.0",
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
def post(self, endpoint: str, data: dict | None = None) -> dict:
|
|
30
|
+
"""POST to an API v2 endpoint with automatic auth injection."""
|
|
31
|
+
payload = {
|
|
32
|
+
"login": self.login,
|
|
33
|
+
"accessKey": self.access_key,
|
|
34
|
+
}
|
|
35
|
+
if data:
|
|
36
|
+
payload.update(data)
|
|
37
|
+
|
|
38
|
+
url = f"{self.base_url}{endpoint}"
|
|
39
|
+
|
|
40
|
+
try:
|
|
41
|
+
resp = self.session.post(url, json=payload, timeout=60, verify=False)
|
|
42
|
+
except requests.ConnectionError:
|
|
43
|
+
raise InsimAPIError(f"Cannot connect to {self.base_url}. Is the server running?")
|
|
44
|
+
except requests.Timeout:
|
|
45
|
+
raise InsimAPIError("Request timed out after 30 seconds.")
|
|
46
|
+
|
|
47
|
+
try:
|
|
48
|
+
body = resp.json()
|
|
49
|
+
except ValueError:
|
|
50
|
+
raise InsimAPIError(f"Invalid response from server (HTTP {resp.status_code})")
|
|
51
|
+
|
|
52
|
+
if not body.get("success", False):
|
|
53
|
+
extra = {}
|
|
54
|
+
if body.get("error_code") == "LICENSE_REQUIRED":
|
|
55
|
+
extra = {
|
|
56
|
+
"subscription_type": body.get("subscription_type", ""),
|
|
57
|
+
"upgrade_url": body.get("upgrade_url", ""),
|
|
58
|
+
"feature": body.get("feature", ""),
|
|
59
|
+
}
|
|
60
|
+
raise InsimAPIError(
|
|
61
|
+
message=body.get("error", "Unknown error"),
|
|
62
|
+
error_code=body.get("error_code", "UNKNOWN"),
|
|
63
|
+
status=resp.status_code,
|
|
64
|
+
field=body.get("field", ""),
|
|
65
|
+
extra=extra,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
return body
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""Authentication: login, logout, credentials storage."""
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Optional
|
|
6
|
+
from cli_anything.insim.core.api import InsimAPI, InsimAPIError
|
|
7
|
+
|
|
8
|
+
CREDENTIALS_DIR = Path.home() / ".insim"
|
|
9
|
+
CREDENTIALS_FILE = CREDENTIALS_DIR / "credentials.json"
|
|
10
|
+
DEFAULT_BASE_URL = "https://www.insim.app"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_base_url() -> str:
|
|
14
|
+
return os.environ.get("INSIM_BASE_URL", DEFAULT_BASE_URL)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def save_credentials(login: str, access_key: str, base_url: str = "") -> None:
|
|
18
|
+
CREDENTIALS_DIR.mkdir(parents=True, exist_ok=True)
|
|
19
|
+
data = {"login": login, "accessKey": access_key}
|
|
20
|
+
if base_url:
|
|
21
|
+
data["base_url"] = base_url
|
|
22
|
+
CREDENTIALS_FILE.write_text(json.dumps(data, indent=2))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def load_credentials() -> Optional[dict]:
|
|
26
|
+
# Priority 1: environment variables
|
|
27
|
+
env_login = os.environ.get("INSIM_LOGIN")
|
|
28
|
+
env_key = os.environ.get("INSIM_ACCESS_KEY")
|
|
29
|
+
if env_login and env_key:
|
|
30
|
+
return {"login": env_login, "accessKey": env_key}
|
|
31
|
+
|
|
32
|
+
# Priority 2: credentials file
|
|
33
|
+
if CREDENTIALS_FILE.exists():
|
|
34
|
+
try:
|
|
35
|
+
return json.loads(CREDENTIALS_FILE.read_text())
|
|
36
|
+
except (json.JSONDecodeError, OSError):
|
|
37
|
+
return None
|
|
38
|
+
|
|
39
|
+
return None
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def remove_credentials() -> bool:
|
|
43
|
+
if CREDENTIALS_FILE.exists():
|
|
44
|
+
CREDENTIALS_FILE.unlink()
|
|
45
|
+
return True
|
|
46
|
+
return False
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def login(email: str, access_key: str) -> dict:
|
|
50
|
+
"""Validate credentials against the API and save them."""
|
|
51
|
+
base_url = get_base_url()
|
|
52
|
+
api = InsimAPI(base_url, email, access_key)
|
|
53
|
+
result = api.post("/api/v2/account")
|
|
54
|
+
save_credentials(email, access_key, base_url)
|
|
55
|
+
return result.get("account", {})
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def require_auth() -> InsimAPI:
|
|
59
|
+
"""Return an authenticated API client or raise an error."""
|
|
60
|
+
creds = load_credentials()
|
|
61
|
+
if not creds:
|
|
62
|
+
raise InsimAPIError(
|
|
63
|
+
"Not logged in. Run: insim login YOUR_EMAIL --key YOUR_ACCESS_KEY",
|
|
64
|
+
error_code="NOT_AUTHENTICATED",
|
|
65
|
+
)
|
|
66
|
+
base_url = creds.get("base_url", get_base_url())
|
|
67
|
+
return InsimAPI(base_url, creds["login"], creds["accessKey"])
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def whoami() -> dict:
|
|
71
|
+
"""Return account info for the current user."""
|
|
72
|
+
api = require_auth()
|
|
73
|
+
result = api.post("/api/v2/account")
|
|
74
|
+
return result.get("account", {})
|