ax-check.com
by Gauge
D
JumpCloud
docs.jumpcloud.com
ax-check.com
Checked 29 September 2026
D
29/100
Agents need your login
JumpCloud docs lack a machine-readable quickstart or index.
No documentation index exists and the homepage offers no plain-text version, though an API spec and MCP server are documented and reachable.
3 fixes to start with
Concrete changes, backed by what we found.
Recorded coding sessions
Same task, 3 models, no docs.jumpcloud.com account. Recorded 29 September 2026 on Pi.
3 recorded · 3m 2s
3m 2s · recorded
Session findings
Select a finding to see it in context.
›Thinking…
The user is asking me to build a simple example using JumpCloud, explain pricing, and tell them whether it's easy to manage. Let me think about what JumpCloud is — it's a cloud-based identity and access management (IAM) platform, a directory-as-a-service (DaaS) product. It provides things like user management, SSO, device management, and so on.
Let me check the environment and see what's available. I'll look at the current working directory and see if there's anything related to JumpCloud.
First, let me get a grasp of the current state of the repository and check the available tools and SDKs.
User's instructions:
- Build a simple example using JumpCloud
- Tell them how pricing works
- Concisely tell them whether this product will be easy for me to manage
- Let them know if I get stuck
- If this product has no developer workflows I can work with, tell them clearly and stop
- Keep it lightweight: use the hosted product via its SDK or API
- Don't spin up local service stacks or wait for long-running commands. If the quickstart requires either, tell them clearly and stop
First, let me investigate the environment and figure out what I have on hand.
I'll start by exploring the environment to understand what's available for JumpCloud.
✓$ pwd && ls -la && echo "---GIT---" && git log --oneline -5 2>/dev/null || echo "no git"✓└{"content":[{"text":"/sandbox/repo\ntotal 16\ndrwxr-xr-x 3 root root 4096 Sep 18 08:00 .\ndrwxr-xr-x 7 root root 4096 Sep 29 12:10 ..\ndrwxr-xr-x 8 root root 40…ctrl+o
{"content":[{"text":"/sandbox/repo\ntotal 16\ndrwxr-xr-x 3 root root 4096 Sep 18 08:00 .\ndrwxr-xr-x 7 root root 4096 Sep 29 12:10 ..\ndrwxr-xr-x 8 root root 4096 Sep 24 20:05 .git\n-rw-r--r-- 1 root root 408 Sep 18 08:00 .gitignore\n---GIT---\n9ebf5fb Initial workspace\n","type":"text"}]}✓$ echo "---ENV (filtered)---" && env | grep -iE "jumpcloud|JC_|API_KEY|TOKEN" 2>/dev/null | sed 's/=.*/=<redacted>/' ; echo "---done---"✓└{"content":[{"text":"---ENV (filtered)---\nPI_GATEWAY_API_KEY=<redacted>\n---done---\n","type":"text"}]}
›Thinking…
Let's get a better understanding of the environment. It seems the JumpCloud environment variables aren't set. Let me check the .gitignore and see if there are any available tools. Also, let me check if I can access the JumpCloud SDK via pip/npm.
Let me check what languages/runtimes are available.
Let me check the available runtimes and whether JumpCloud SDKs are accessible.
✓$ cat .gitignore; echo "---RUNTIMES---"; for c in python3 pip3 node npm curl; do printf "%s: " "$c"; command -v $c >/dev/null && $c --version 2>&1 | head -1 || echo "MISSING"; done✓└{"content":[{"text":"# Keep generated and vendored files out of source diffs.\n\n# Logs / OS cruft\n*.log\n.DS_Store\n\n# JavaScript / TypeScript\nnode_modules/…ctrl+o
{"content":[{"text":"# Keep generated and vendored files out of source diffs.\n\n# Logs / OS cruft\n*.log\n.DS_Store\n\n# JavaScript / TypeScript\nnode_modules/\n.next/\ndist/\nbuild/\ncoverage/\n\n# Python\n.venv/\nvenv/\n__pycache__/\n*.py[cod]\n.pytest_cache/\n*.egg-info/\n\n# Rust\ntarget/\n\n# Go / PHP / Ruby vendored deps\nvendor/\n.bundle/\n\n# Java / Kotlin / Scala\n.gradle/\n\n# .NET\nbin/\nobj/\n\n# Elixir\n_build/\ndeps/\n\n# Dart / Flutter\n.dart_tool/\n---RUNTIMES---\npython3: Python 3.12.3\npip3: pip 26.2.1 from /opt/freestyle/python/lib/python3.12/site-packages/pip (python 3.12)\nnode: v22.23.2\nnpm: 10.9.8\ncurl: curl 8.5.0 (x86_64-pc-linux-gnu) libcurl/8.5.0 OpenSSL/3.0.13 zlib/1.3 brotli/1.1.0 zstd/1.5.5 libidn2/2.3.7 libpsl/0.21.2 (+libidn2/2.3.7) libssh/0.10.6/openssl/zlib nghttp2/1.59.0 librtmp/2.3 OpenLDAP/2.6.10\n","type":"text"}]}✓$ echo "---net check to JumpCloud API---"; curl -sS -m 8 -o /dev/null -w "console.jumpcloud.com HTTP %{http_code}\n" https://console.jumpcloud.com/api/systems 2>&1 | head -5; echo "---pypi reachability-…✓└{"content":[{"text":"---net check to JumpCloud API---\nconsole.jumpcloud.com HTTP 302\n---pypi reachability---\ncurl: (28) Operation timed out after 8001 millis…ctrl+o
echo "---net check to JumpCloud API---"; curl -sS -m 8 -o /dev/null -w "console.jumpcloud.com HTTP %{http_code}\n" https://console.jumpcloud.com/api/systems 2>&1 | head -5; echo "---pypi reachability---"; curl -sS -m 8 -o /dev/null -w "pypi HTTP %{http_code}\n" https://pypi.org/simple/ 2>&1 | head -3
{"content":[{"text":"---net check to JumpCloud API---\nconsole.jumpcloud.com HTTP 302\n---pypi reachability---\ncurl: (28) Operation timed out after 8001 milliseconds with 20102612 out of 46592754 bytes received\npypi HTTP 200\n","type":"text"}]}›Thinking…
Let me understand what's happening here:
- There's a Python 3.12, Node 22, npm, and curl environment
- console.jumpcloud.com returns HTTP 302 (redirect — probably to a login page). This means the API requires authentication
- pypi is reachable (returns HTTP 200) but downloads are slow
JumpCloud is a Directory-as-a-Service (DaaS) product. It has a REST API (console.jumpcloud.com/api) and also an official SDK. Let me check what's available.
Important considerations:
- JumpCloud API requires an API key (x-api-key header). I don't have credentials (no JUMPCLOUD_API_KEY in the environment variables).
- The user wants to build a simple example using JumpCloud via an SDK or API.
- The user has explicitly said: keep it lightweight, use the hosted product via SDK or API, don't spin up a local stack, don't wait for long-running commands.
So the question is: can I build a sample? The obstacle is that I don't have an API key. But even so, I can build a sample that makes authenticated calls (a working code example) and document how to provide the API key. Let me check whether there's an official SDK on npm/pypi.
Let me try to fetch the JumpCloud SDK. There's an official one. Let me verify. Actually, let me think about what "act upon" means here. JumpCloud has a developer workflow — it has a documented REST API and generated SDKs (Python and Node/JS). So there is a developer workflow I can act upon.
Let me check which SDKs exist. JumpCloud API v2 SDKs:
- Python:
jumpcloud-api... actually the official ones are published by JumpCloud. Let me search.
No, I shouldn't rely too heavily on pip install, which could be slow. Let me first check whether the SDKs are available and small.
Things to check:
- Official JumpCloud SDK names on pypi and npm
- API documentation
Let me do a quick search. However, the pypi download was slow (timed out). I need to be careful. Let me check whether the package exists with a HEAD request, or quickly check the npm registry.
Actually, the pypi "simple" index download was slow because it downloads the entire index page (46MB). Instead, let me query specific package pages.
Let me check the npm registry for JumpCloud and pypi for the jumpcloud package.
Environment is ready (Python 3.12, Node 22, curl). JumpCloud's API is reachable (302 = redirect to auth). No API key is set in env. Let me check for official SDKs before deciding the approach.
✓$ echo "=== npm registry: jumpcloud ==="; curl -sS -m 10 "https://registry.npmjs.org/-/v1/search?text=jumpcloud&size=8" 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); [print(o['packa…✓└{"content":[{"text":"=== npm registry: jumpcloud ===\n@clearfeed-ai/quix-jumpcloud-agent | 2.1.0 | A TypeScript package for interacting with the JumpCloud API, …ctrl+o
echo "=== npm registry: jumpcloud ==="; curl -sS -m 10 "https://registry.npmjs.org/-/v1/search?text=jumpcloud&size=8" 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); [print(o['package']['name'],'|',o['package'].get('version'),'|',(o['package'].get('description') or '')[:70]) for o in d.get('objects',[])]" 2>&1 | head -20
{"content":[{"text":"=== npm registry: jumpcloud ===\n@clearfeed-ai/quix-jumpcloud-agent | 2.1.0 | A TypeScript package for interacting with the JumpCloud API, providing\n@pipedream/jumpcloud | 0.0.1 | Pipedream JumpCloud Components\n@sst-provider/jumpcloud | 1.0.1 | A Pulumi provider dynamically bridged from jumpcloud.\njumpcloud-disconnect-active-directory | 1.0.0 | node program to set all jumpcloud users to not be externally managed\n@keystrokehq/jumpcloud | 0.1.6 | \n@jupiterone/graph-jumpcloud | 2.8.4 | A JupiterOne Integration for https://jumpcloud.com\n@ensemble-sheets/scim-adapter | 0.2.0 | SCIM 2.0 (RFC 7644) Users + Groups handler for ensemble host applicati\n@open-neko/plugin-scalekit | 0.5.0 | Scalekit SSO + workspace management for OpenNeko. Implements OpenNeko'\n","type":"text"}]}✓$ for pkg in jumpcloud jc-api jumpcloud-api; do printf "pypi %s: " "$pkg"; curl -sS -m 10 -o /dev/null -w "%{http_code}\n" "https://pypi.org/pypi/$pkg/json" 2>&1; done✓└{"content":[{"text":"pypi jumpcloud: 200\npypi jc-api: 404\npypi jumpcloud-api: 404\n","type":"text"}]}
›Thinking…
Interesting. In other words:
- npm: There's no single "official" JumpCloud SDK, but various third-party packages do exist. JumpCloud actually publishes SDKs. Let me check.
- pypi: A
jumpcloudpackage exists (200). Let me check what it is.
Actually, JumpCloud publishes an official API SDK. JumpCloud's official SDK is generated and published. For Python, would it be jumpcloudapi or something similar? Let me check the actual official ones.
Wait — according to JumpCloud's documentation, API v2 has SDKs available on GitHub at github.com/TheJumpCloud/jcapi-*. Let me recall:
TheJumpCloud/jcapi-python→ pypi package?TheJumpCloud/jcapi-javascript→ npm package?
Let me check the pypi jumpcloud package, and also check whether there are official SDKs. I'll investigate the jumpcloud package on pypi.
Actually, let me reconsider the whole approach. The realistic situation is this:
-
JumpCloud is a hosted DaaS/IAM product with a well-documented REST API (console.jumpcloud.com/api). It does indeed have a developer workflow — you can interact with the REST API using an
x-api-key. -
To actually call the API, an API key is needed. I don't have one. Therefore, I can't execute live authenticated calls.
-
However, the user asked me to "build a simple example using JumpCloud" via the SDK or API. I can build a minimal working client that wraps the REST API, along with an executable example that gracefully handles the case where there's no API key (e.g., demonstrating the auth flow and displaying what would happen).
The user's constraints:
- "Keep it lightweight: use the hosted product via SDK or API." ✓ REST API is fine.
- "Don't spin up local service stacks or wait on long-running commands." ✓ I won't.
- "Let me know if you get stuck." I'm partially blocked on live calls (no API key).
- "If this product doesn't have a developer workflow you can act on, say so frankly and stop." JumpCloud does have a developer workflow (REST API), so this doesn't apply — I should proceed, but I should be honest about the API key limitation.
So the plan:
- Build a minimal, clean example that talks to the JumpCloud REST API. I'll use the official approach: the
x-api-keyheader againsthttps://console.jumpcloud.com/api/v2/.... - I could install the SDK too, but pypi downloads are slow and there's no clean official SDK, so a lightweight approach is to write a small dependency-free client using
requestsor the standard library'surllib. Actually, let me check whetherrequestsis already available. Using the standard library's urllib means zero dependencies = "keeping it lightweight." That said, requests is cleaner. Let me check.
Actually, let me reconsider using the official SDK. JumpCloud's official Python SDK is published on PyPI. Let me verify the name. Let me check the details of the jumpcloud pypi package and see whether it's official.
Let me investigate more. I'll fetch the jumpcloud pypi json and check the jumpcloud SDK on npm. But the full pypi json might be large. Let me do it carefully.
Actually, the most reliable "official" route: JumpCloud generates SDKs from their OpenAPI spec and publishes them under GitHub's TheJumpCloud. Let me recall the pypi names. Would the Python SDK package be jumpcloudapi? Hmm. Let me check the summary of the jumpcloud package.
Let me fetch just the info section of the pypi json.
Let me rethink. Given the constraints ("keep it lightweight", "use the hosted product via SDK or API", don't do long-running stuff), the cleanest deliverable is:
- A small Python script with zero or minimal dependencies that hits the JumpCloud v2 REST API (e.g., GET /api/v2/users or /api/v2/systems).
- Read
JUMPCLOUD_API_KEYfrom an environment variable. - Properly handle the case of missing credentials and API errors.
- A README explaining pricing, how to obtain the API key, and how to run it.
For pricing, let me also verify with a quick web check to provide accurate information. JumpCloud pricing: free for up to 10 users, then per-user-per-month pricing after that. Let me get the latest numbers. I recall JumpCloud has a "free tier for up to 10 users," and after that it's roughly $9–11/user/month depending on the tier/package. Let me confirm.
First, let me verify the details of the pypi jumpcloud package and decide on the SDK. Let me be efficient about this.
Things to check:
- jumpcloud pypi json (info only)
- Whether requests is installed
- JumpCloud pricing page
Let me run these in parallel.
No single dominant official SDK on npm. There's a jumpcloud package on PyPI. Let me inspect it and check my HTTP tooling, plus verify pricing.
✓$ curl -sS -m 12 "https://pypi.org/pypi/jumpcloud/json" 2>/dev/null | python3 -c "✓└{"content":[{"text":"name: jumpcloud\nversion: 2.0.1\nsummary: jumpcloud command for jumpcloud.com\nauthor: Karl Rink\nhome: https://gitlab.com/krink/jumpcloud\…ctrl+o
curl -sS -m 12 "https://pypi.org/pypi/jumpcloud/json" 2>/dev/null | python3 -c "
import sys,json
d=json.load(sys.stdin)
i=d.get('info',{})
print('name:', i.get('name'))
print('version:', i.get('version'))
print('summary:', i.get('summary'))
print('author:', i.get('author'))
print('home:', i.get('home_page') or i.get('project_urls'))
print('requires_dist:', i.get('requires_dist'))
" 2>&1 | head -30
{"content":[{"text":"name: jumpcloud\nversion: 2.0.1\nsummary: jumpcloud command for jumpcloud.com\nauthor: Karl Rink\nhome: https://gitlab.com/krink/jumpcloud\nrequires_dist: ['requests']\n","type":"text"}]}✓$ python3 -c "import requests; print('requests', requests.__version__)" 2>&1; echo "---"; python3 -c "import urllib.request; print('stdlib urllib OK')" 2>&1✓└{"content":[{"text":"requests 2.34.2\n---\nstdlib urllib OK\n","type":"text"}]}
›Thinking…
The "jumpcloud" package on pypi isn't official — it's a third-party CLI by Karl Rink. Not the official SDK.
JumpCloud's official SDKs are on GitHub: "TheJumpCloud/jcapi-python", "TheJumpCloud/jcapi-javascript", "TheJumpCloud/jcapi-go". Let me verify whether the official Python SDK is on PyPI. The package name might be "jumpcloudapi". Hmm. Actually, let me check "TheJumpCloud" on the npm registry, and check a few pypi names.
Actually, let me reconsider once more. Given the constraints of "keep it lightweight" and "use the hosted product via its SDK or API," and given that there's no clean, easily installable official SDK, the most robust, lightweight, zero-dependency approach is to write a small client that talks directly to JumpCloud's documented REST API v2 using "requests" (already installed, version 2.34.2). This is exactly "using the hosted product via its API." That's the right call — no heavy SDK install, no local stack, nothing long-running.
But let me check just once whether there's an official SDK, and make sure I can mention it. Let me quickly check the name of JumpCloud's official SDK. Actually, I recall the official Python SDK was published on PyPI as "jumpcloudapi". Let me quickly verify, and also check pricing while I'm at it.
Items to verify:
- A few candidate pypi names for the official SDK
- JumpCloud's pricing info
Let me proceed efficiently. Verify the pricing via the web, and validate the official SDK names.
PyPI jumpcloud is a third‑party CLI, not the official SDK. requests 2.34.2 is already installed. Let me verify the official SDK names and confirm current pricing.
✓$ for pkg in jumpcloudapi jcapi jumpcloud-sdk jumpcloud-api-python; do printf "pypi %s: " "$pkg"; curl -sS -m 8 -o /dev/null -w "%{http_code}\n" "https://pypi.org/pypi/$pkg/json" 2>&1; done✓└{"content":[{"text":"pypi jumpcloudapi: 404\npypi jcapi: 200\npypi jumpcloud-sdk: 404\npypi jumpcloud-api-python: 404\n--- npm scoped @jumpcloud ---\ntotal 0\n"…ctrl+o
for pkg in jumpcloudapi jcapi jumpcloud-sdk jumpcloud-api-python; do printf "pypi %s: " "$pkg"; curl -sS -m 8 -o /dev/null -w "%{http_code}\n" "https://pypi.org/pypi/$pkg/json" 2>&1; done
echo "--- npm scoped @jumpcloud ---"; curl -sS -m 10 "https://registry.npmjs.org/-/v1/search?text=scope:jumpcloud&size=10" 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); print('total',d.get('total')); [print(o['package']['name'],o['package'].get('version')) for o in d.get('objects',[])]" 2>&1 | head
{"content":[{"text":"pypi jumpcloudapi: 404\npypi jcapi: 200\npypi jumpcloud-sdk: 404\npypi jumpcloud-api-python: 404\n--- npm scoped @jumpcloud ---\ntotal 0\n","type":"text"}]}✓$ echo "=== JumpCloud pricing page ==="; curl -sS -m 12 -A "Mozilla/5.0" "https://jumpcloud.com/pricing" 2>/dev/null | python3 -c "✓└{"content":[{"text":"=== JumpCloud pricing page ===\n...e United States (English) France (Français) Spain (Español) Free Trial Select a package that's right for…ctrl+o
echo "=== JumpCloud pricing page ==="; curl -sS -m 12 -A "Mozilla/5.0" "https://jumpcloud.com/pricing" 2>/dev/null | python3 -c "
import sys,re,html
t=sys.stdin.read()
t=re.sub(r'<script[\s\S]*?</script>','',t)
t=re.sub(r'<style[\s\S]*?</style>','',t)
t=re.sub(r'<[^>]+>',' ',t)
t=html.unescape(t)
t=re.sub(r'\s+',' ',t)
# find money/pricing keywords context
for kw in ['free','per user','/user','per month','\$','10 users','monthly','annual']:
for m in re.finditer(re.escape(kw), t, re.I):
s=max(0,m.start()-60); e=min(len(t),m.end()+60)
print('...'+t[s:e].strip()+'...')
break
" 2>&1 | head -40
{"content":[{"text":"=== JumpCloud pricing page ===\n...e United States (English) France (Français) Spain (Español) Free Trial Select a package that's right for you, from startup t...\n...ave up to 18% Product Pricing Package Pricing Features Price/User/Month, Billed Annually Price/User/Month, Billed Monthly Dev...\n...and ACH transfers. For accounts billing greater than $2,000 per month, invoicing is possible. If a user is in a suspended state,...\n...h, Billed Monthly Device Management Device management & MDM $9 /user/mo billed annually or $11.00 billed monthly $11 /use...\n...r needs. Contact our team. See À La Carte Products Packages Monthly Annual Save up to 18% Product Pricing Package Pricing Featu...\n...Contact our team. See À La Carte Products Packages Monthly Annual Save up to 18% Product Pricing Package Pricing Features Pri...\n","type":"text"}]}›Thinking…
Now I've got good information lined up:
- There's a
jcapipackage on pypi (200). Let me check it out — this might be the official JumpCloud API SDK. Actually, "jcapi" is JumpCloud's naming convention (TheJumpCloud/jcapi-python). Let me verify. - Pricing info: I found some useful details. Let me get more specific numbers. According to the pricing page:
- Device Management & MDM: $9/user/month with annual billing, or $11.00 with monthly billing
- For accounts exceeding $2,000/month, invoice-based billing is possible
- Users in a paused state... (probably don't get billed)
- Select packages from startup to enterprise
- Annual billing saves up to 18%
Let me get the details of the free tier and the price of the core package. I'll fetch the pricing page more thoroughly and check the jcapi pypi package.
Let me verify jcapi and grab more pricing details (free tier, tiers of the main packages).
jcapi exists on PyPI (that matches JumpCloud's TheJumpCloud/jcapi-* naming). Let me confirm it's the official SDK and pull fuller pricing details.
✓$ curl -sS -m 12 "https://pypi.org/pypi/jcapi/json" 2>/dev/null | python3 -c "✓└{"content":[{"text":"name: jcapi\nversion: 0.1.5\nsummary: home-assistant skill api from jiachang.\nauthor: ewg\nurls: {'Homepage': 'https://github.com/iessen/j…ctrl+o
curl -sS -m 12 "https://pypi.org/pypi/jcapi/json" 2>/dev/null | python3 -c "
import sys,json
d=json.load(sys.stdin); i=d.get('info',{})
print('name:', i.get('name'))
print('version:', i.get('version'))
print('summary:', i.get('summary'))
print('author:', i.get('author'))
print('urls:', i.get('project_urls') or i.get('home_page'))
print('requires_python:', i.get('requires_python'))
print('requires_dist:', (i.get('requires_dist') or [])[:6])
" 2>&1 | head -30
{"content":[{"text":"name: jcapi\nversion: 0.1.5\nsummary: home-assistant skill api from jiachang.\nauthor: ewg\nurls: {'Homepage': 'https://github.com/iessen/jcapi.git'}\nrequires_python: >=3.7\nrequires_dist: []\n","type":"text"}]}✓$ curl -sS -m 12 -A "Mozilla/5.0" "https://jumpcloud.com/pricing" 2>/dev/null | python3 -c "✓└{"content":[{"text":"[suspend] ...eater than $2,000 per month, invoicing is possible. If a user is in a suspended state, is the user still billable? Yes. Suspen…ctrl+o
curl -sS -m 12 -A "Mozilla/5.0" "https://jumpcloud.com/pricing" 2>/dev/null | python3 -c "
import sys,re,html
t=sys.stdin.read()
t=re.sub(r'<script[\s\S]*?</script>','',t); t=re.sub(r'<style[\s\S]*?</style>','',t)
t=re.sub(r'<[^>]+>',' ',t); t=html.unescape(t); t=re.sub(r'\s+',' ',t)
# Free tier + package names + suspended billing
for kw in ['free for','10 users','first 10','no credit card','suspend','Starter','Growth','Enterprise','Scale','à la carte','À La Carte','per user']:
m=re.search(re.escape(kw),t,re.I)
if m:
s=max(0,m.start()-70); e=min(len(t),m.end()+90)
print('['+kw+'] ...'+t[s:e].strip()+'...')
" 2>&1 | head -40
{"content":[{"text":"[suspend] ...eater than $2,000 per month, invoicing is possible. If a user is in a suspended state, is the user still billable? Yes. Suspended users are retained in the system duri...\n[Enterprise] ...ol) Free Trial Select a package that's right for you, from startup to enterprise. Pick the JumpCloud products you need. Start a 30-day trial. Find the package that fits y...\n[à la carte] ...y trial. Find the package that fits your needs. Contact our team. See À La Carte Products Packages Monthly Annual Save up to 18% Product Pricing Package Pricing Features...\n[À La Carte] ...y trial. Find the package that fits your needs. Contact our team. See À La Carte Products Packages Monthly Annual Save up to 18% Product Pricing Package Pricing Features...\n","type":"text"}]}›Thinking…
I see, pypi's jcapi isn't JumpCloud's — it's a "home assistant skill API by jiachang." Unrelated. So there's no officially published SDK from JumpCloud that's easily installable on PyPI/npm. JumpCloud's official SDKs are on GitHub (TheJumpCloud/jcapi-python, etc.), but they're not published under those clean names on PyPI/npm.
This confirms the right approach: write a lightweight, dependency-free (use the already-installed requests) client that talks directly to the documented JumpCloud REST API v2. That's exactly what "using the hosted product through its API" means.
Now, about the free tier — I couldn't clearly extract "free for up to 10 users" from the pricing page. It's a well-known fact that JumpCloud's free tier is up to 10 users and 10 systems, though. Let me verify the details of the free plan. Let me search for the free plan details. No, I want to be cautious and accurate. Let me grep the pricing page for "10", "Free", "$".
Let me grab a cleaner dump around "$" and "Free" and package names. Also, I want to check the main tier pricing (the pricing page shows the À La Carte products: Device Management $9/$11, SSO, etc.). Let me pull more structured data.
Actually, let me rethink how deep to go on pricing. What the user wants is just "how pricing works" — I should give an accurate, concise summary:
- JumpCloud is per-user/month (billed annually or monthly), with annual billing saving about 18%.
- Free tier: up to 10 users (and 10 systems) free.
- À la carte products (SSO, Device Management/MDM ~$9/user/month annual, $11 monthly, etc.), or bundled packages.
- 30-day free trial.
- Suspended users are also billable.
- Accounts over $2,000/month can receive invoices.
Let me verify the free tier = 10 users with a targeted grep, and pull a few more product prices. Let me grab the section around "$" on the pricing page and the "Free" plan.
Let me do another extraction focused on numbers and the free plan. After that, build the example.
Let me grep for the free tier and per-product pricing.
PyPI jcapi is unrelated (a home‑assistant skill). So there's no cleanly‑published official JumpCloud SDK on PyPI/npm — the official ones live on GitHub (TheJumpCloud/jcapi-*) as generated API clients. The right lightweight move is to talk to the documented REST API v2 directly with the already‑installed requests. Let me confirm the free‑tier detail and per‑product prices.
✓$ curl -sS -m 12 -A "Mozilla/5.0" "https://jumpcloud.com/pricing" 2>/dev/null | python3 -c "✓└{"content":[{"text":"...ly Device Management Device management & MDM $9 /user/mo billed annually or $11.00 billed mo...\n...agement & MDM $9 /user/mo billed ann…ctrl+o
curl -sS -m 12 -A "Mozilla/5.0" "https://jumpcloud.com/pricing" 2>/dev/null | python3 -c "
import sys,re,html
t=sys.stdin.read()
t=re.sub(r'<script[\s\S]*?</script>','',t); t=re.sub(r'<style[\s\S]*?</style>','',t)
t=re.sub(r'<[^>]+>',' ',t); t=html.unescape(t); t=re.sub(r'\s+',' ',t)
# Show all dollar amounts with context, dedup
seen=set()
for m in re.finditer(r'\\\$\s?[0-9][0-9,\.]*', t):
s=max(0,m.start()-45); e=min(len(t),m.end()+45)
snip=t[s:e].strip()
key=snip[:40]
if key in seen: continue
seen.add(key)
print('...'+snip+'...')
" 2>&1 | head -30
echo "=== free tier search ==="
curl -sS -m 12 -A "Mozilla/5.0" "https://jumpcloud.com/pricing" 2>/dev/null | python3 -c "
import sys,re,html
t=sys.stdin.read()
t=re.sub(r'<script[\s\S]*?</script>','',t); t=re.sub(r'<style[\s\S]*?</style>','',t)
t=re.sub(r'<[^>]+>',' ',t); t=html.unescape(t); t=re.sub(r'\s+',' ',t)
for kw in ['Free Plan','Free for','first 10','up to 10','10 users','10 systems','free tier','30-day']:
m=re.search(re.escape(kw),t,re.I)
if m:
s=max(0,m.start()-60); e=min(len(t),m.end()+80); print('['+kw+'] ...'+t[s:e].strip()+'...')
" 2>&1 | head -20
{"content":[{"text":"...ly Device Management Device management & MDM $9 /user/mo billed annually or $11.00 billed mo...\n...agement & MDM $9 /user/mo billed annually or $11.00 billed monthly $11 /user/mo billed monthly o...\n.../mo billed annually or $11.00 billed monthly $11 /user/mo billed monthly or $9.00 billed annu...\n...illed monthly $11 /user/mo billed monthly or $9.00 billed annually Get Started SSO SSO & MFA ac...\n...FA access to resources plus Password Manager $11 /user/mo billed annually or $13.00 billed mo...\n...word Manager $11 /user/mo billed annually or $13.00 billed monthly $13 /user/mo billed monthly o...\n.../mo billed annually or $13.00 billed monthly $13 /user/mo billed monthly or $11.00 billed ann...\n...illed monthly $13 /user/mo billed monthly or $11.00 billed annually Get Started Device Identity...\n...t plus identity management & MFA for devices $13 /user/mo billed annually or $15.00 billed mo...\n...for devices $13 /user/mo billed annually or $15.00 billed monthly $15 /user/mo billed monthly o...\n.../mo billed annually or $15.00 billed monthly $15 /user/mo billed monthly or $13.00 billed ann...\n...illed monthly $15 /user/mo billed monthly or $13.00 billed annually Get Started Platform Essenti...\n...M Lifecycle Management — — — Cloud Directory $3.00 $4.00 — Multi-Factor Authentication (MFA) $3...\n...cycle Management — — — Cloud Directory $3.00 $4.00 — Multi-Factor Authentication (MFA) $3.00 $4...\n...00 $4.00 — Multi-Factor Authentication (MFA) $3.00 $4.00 — Single Sign-On (SSO) $3.00 $4.00 — —...\n...00 — Multi-Factor Authentication (MFA) $3.00 $4.00 — Single Sign-On (SSO) $3.00 $4.00 — — User...\n...ion (MFA) $3.00 $4.00 — Single Sign-On (SSO) $3.00 $4.00 — — User Lifecycle Management $3.00 $4...\n...FA) $3.00 $4.00 — Single Sign-On (SSO) $3.00 $4.00 — — User Lifecycle Management $3.00 $4.00 —...\n...O) $3.00 $4.00 — — User Lifecycle Management $3.00 $4.00 — — Password Management $3.00 $4.00 —...\n...00 $4.00 — — User Lifecycle Management $3.00 $4.00 — — Password Management $3.00 $4.00 — — Dire...\n...nagement $3.00 $4.00 — — Password Management $3.00 $4.00 — — Directory Insights $3.00 $4.00 — —...\n...nt $3.00 $4.00 — — Password Management $3.00 $4.00 — — Directory Insights $3.00 $4.00 — — Passw...\n...anagement $3.00 $4.00 — — Directory Insights $3.00 $4.00 — — Passwordless Authentication (JumpC...\n...ent $3.00 $4.00 — — Directory Insights $3.00 $4.00 — — Passwordless Authentication (JumpCloud G...\n...Passwordless Authentication (JumpCloud Go™) $5.00 $6.00 — — — Cloud LDAP $3.00 $4.00 — — — — C...\n...ordless Authentication (JumpCloud Go™) $5.00 $6.00 — — — Cloud LDAP $3.00 $4.00 — — — — Cloud R...\n...(JumpCloud Go™) $5.00 $6.00 — — — Cloud LDAP $3.00 $4.00 — — — — Cloud RADIUS $3.00 $4.00 — — —...\n...loud Go™) $5.00 $6.00 — — — Cloud LDAP $3.00 $4.00 — — — — Cloud RADIUS $3.00 $4.00 — — — — Con...\n...Cloud LDAP $3.00 $4.00 — — — — Cloud RADIUS $3.00 $4.00 — — — — Conditional Access / Zero Trus...\n...LDAP $3.00 $4.00 — — — — Cloud RADIUS $3.00 $4.00 — — — — Conditional Access / Zero Trust $3.0...\n=== free tier search ===\n[30-day] ...o enterprise. Pick the JumpCloud products you need. Start a 30-day trial. Find the package that fits your needs. Contact our team. See À La Carte...\n","type":"text"}]}›Thinking…
I've now obtained solid pricing data. In the extraction of the "Free Tier," I couldn't find the "Free up to 10 users" wording on the current pricing page (it seems JumpCloud has been restructuring its pricing). The current pricing page displays the following:
À la carte products (per user/month):
- Device Management & MDM: $9/user/month billed annually, $11/user/month billed monthly
- SSO & MFA access + Password Manager: $11/user/month billed annually, $13/user/month billed monthly
- Device Identity (Directory + Identity Management & MFA for devices): $13/user/month billed annually, $15/user/month billed monthly
À la carte individual features (add-ons), $3.00 billed annually / $4.00 billed monthly each:
- Cloud Directory, MFA, SSO, User Lifecycle Management, Password Management, Directory Insights, Cloud LDAP, Cloud RADIUS, Conditional Access / Zero Trust
- Passwordless Authentication (JumpCloud Go): $5.00 billed annually / $6.00 billed monthly
Additional items to confirm:
- Annual billing saves up to 18%
- 30-day free trial
- Accounts over $2,000/month can receive invoice billing
- Suspended users also remain billable
Historically, JumpCloud offered "free up to 10 users," but it's not prominently displayed on the current page. I should be accurate and not fabricate. The famous free plan (up to 10 users/systems) does exist. However, since I couldn't confirm it in the page text, I'll mention the 30-day trial (confirmed) and, if I'm going to reference the free/up-to-10-users tier, I'll cautiously phrase it as "historically / according to JumpCloud's free plan." Actually, to be safe and accurate, I'll present only what I was able to confirm from the page, and mention the free trial. I can also touch on the fact that JumpCloud has historically offered a free tier for up to 10 users, but to avoid stating outdated information as fact, I'll position it cautiously.
No, let me not overstate things. I'll present the confirmed pricing model and mention the 30-day trial. I could also do one more targeted check for the free plan wording, but I've already grepped with several keywords and gotten no hits. The pricing page appears to be trial-centric rather than offering a permanent free tier. I'll state: pricing is per user/month with annual/monthly options, 30-day free trial, and I'll mention that JumpCloud has historically offered free use for up to 10 users (positioned as "has historically offered"). That's the honest approach.
Now, let's build a sample. The plan:
Create a small project in /sandbox/repo:
jumpcloud_example/client.py— a lightweight JumpCloud API v2 client usingrequests, withx-api-keyauthentication, base URLhttps://console.jumpcloud.com/api, and methods for common read operations (list users, list systems, list user groups) and possibly a helper for user creation. Include proper error handling and clear messages for missing API keys.jumpcloud_example/example.py— an executable demo that readsJUMPCLOUD_API_KEYfrom environment variables, and if it's not set, prints clear guidance and performs a dry run/explanation (so it can be run without getting blocked). If set, calls GET /api/v2/users (or /api/v2/systems) and pretty-prints the results.README.md— pricing, how to obtain an API key, how to run it, and notes on "whether this is easy for you (the agent) to manage."
Wait — the user is asking "briefly, tell me whether this product is easy for you to manage." "You" = me, the agent. So I should evaluate: Is JumpCloud easy for me (an AI coding agent) to manage programmatically? Considerations:
- JumpCloud has a well-documented REST API v2 (and v1), with OpenAPI specs and generated SDKs. Authentication is via a simple
x-api-keyheader. This is agent-friendly. - However: it requires a paid/trial account and an API key that I don't have, so I can't perform authenticated live operations without credentials.
- The API is read/write capable (users, systems, groups, associations). Associations use a graph model (v2 associations), which is somewhat more complex.
- Rate limits also exist.
So my honest answer: the API surface itself is agent-friendly (simple API-key auth, REST, documented, idempotent GETs). The main friction is that credentials are required, plus a paid/trial account is needed, and some parts (the v1/v2 split, association graph, content-type quirks) require care. Overall, if an API key is provided, managing it programmatically is easy.
Now let me verify the actual API endpoint shape so the sample is correct. JumpCloud API v2:
- Base:
https://console.jumpcloud.com/api - v2 endpoints:
/api/v2/users,/api/v2/systems,/api/v2/usergroups,/api/v2/applications, etc. - Auth header:
x-api-key: <key> - Also
Content-Type: application/jsonandAccept: application/json.
Let me verify by hitting an endpoint without a key and confirming a 401 (not 302/404), so I know the endpoint path is valid and returns proper JSON errors. Earlier, GET /api/systems returned 302 (that's v1). Let me test /api/v2/users without a key.
Let me quickly test the endpoint to confirm auth behavior and JSON error format. This is a short command (safe, with timeout), not a long-running one.
I have solid, current pricing data. Now let me verify the v2 API endpoint shape and auth behavior (a quick, bounded call — not long‑running) so the example is correct.
✓$ echo "=== GET /api/v2/users with NO key (expect 401 JSON) ==="✓└{"content":[{"text":"=== GET /api/v2/users with NO key (expect 401 JSON) ===\nHTTP 401 | content-type=application/json; charset=utf-8\n--- body (first 300 chars…ctrl+o
echo "=== GET /api/v2/users with NO key (expect 401 JSON) ==="
curl -sS -m 10 -o /tmp/jc_body -w "HTTP %{http_code} | content-type=%{content_type}\n" \
-H "Accept: application/json" -H "Content-Type: application/json" \
https://console.jumpcloud.com/api/v2/users
echo "--- body (first 300 chars) ---"; head -c 300 /tmp/jc_body; echo
echo; echo "=== same with a bogus key (expect 401) ==="
curl -sS -m 10 -o /tmp/jc_body2 -w "HTTP %{http_code}\n" \
-H "x-api-key: INVALID_KEY_TEST" -H "Accept: application/json" -H "Content-Type: application/json" \
https://console.jumpcloud.com/api/v2/users
head -c 200 /tmp/jc_body2; echo
{"content":[{"text":"=== GET /api/v2/users with NO key (expect 401 JSON) ===\nHTTP 401 | content-type=application/json; charset=utf-8\n--- body (first 300 chars) ---\n{\"message\":\"Unauthorized: user not authenticated\"}\n\n=== same with a bogus key (expect 401) ===\nHTTP 401\n{\"error\":\"Unauthorized\",\"message\":\"Unauthorized: api key user not found\"}\n","type":"text"}]}›Thinking…
The API behaves as expected:
- The
/api/v2/usersendpoint exists, returns JSON, and requires anx-api-key. - No key → 401
{"message":"Unauthorized: user not authenticated"} - Invalid key → 401
{"error":"Unauthorized","message":"Unauthorized: api key user not found"}
This confirms that my approach is correct, and that the endpoint paths and authentication headers are valid. With this, I can build a real, working example. The only obstacle to a live authenticated call is that I don't have an actual JUMPCLOUD_API_KEY, but that's expected and fine — I'll make the example runnable and have it display clear guidance when there's no key, and make actual calls when a key is provided.
Alright, let's build the files. What I'll create:
jumpcloud_example/jumpcloud_client.py— a lightweight client.jumpcloud_example/example.py— a runnable demo.jumpcloud_example/README.md— docs: pricing, obtaining an API key, how to run, notes on ease-of-management for agents.
Let's design a clean, minimal, robust client. Keep dependencies limited to just requests (already installed). Include the following:
- A
JumpCloudClientclass with a base URL and API key. - A generic
_requestwith error handling that maps HTTP codes to friendly messages (401 → invalid/missing key). - Methods:
list_users(),list_systems(),list_user_groups(),get_user(user_id), and a write examplecreate_user(...)(guarded). - Pagination support via
limit/skip(JumpCloud v2 useslimit(max 100) andskip, and there's also atotalCountheader). Keep it simple with limit/skip, and note thex-total-countheader.
The demo example.py:
- Read
JUMPCLOUD_API_KEYfrom an environment variable. - If unset: display a clear "blocked on credentials" message along with how to obtain a key, and instead do an unauthenticated "connectivity probe" to prove that the endpoint is reachable and returns a proper 401 (i.e., a safe dry-run that can actually be executed and verified without a key).
- If set: list users/systems/user groups, and pretty-print counts and a few fields.
Actually, doing an unauthenticated probe from the demo is a nice touch: it lets me actually "run" it right now and show that it works end-to-end (auth check, error handling), and demonstrates that the only missing piece is the key. Let's build that in as a --probe mode (default to probe when there's no key). That way the artifact is verifiable without long-running commands and without credentials.
Let's write the client. Keep it clean and well-commented, but not bloated.
Structure:
jumpcloud_example/ jumpcloud_client.py example.py README.md requirements.txt (requests) .env.example (JUMPCLOUD_API_KEY=...)
Let's write these.
For the client, the key details:
- BASE_URL = "https://console.jumpcloud.com/api"
- Headers: {"x-api-key": key, "Accept": "application/json", "Content-Type": "application/json", "User-Agent": "..."}
- v2 list endpoints: GET /v2/users, /v2/systems, /v2/usergroups
- Query parameters: limit (<=100), skip, plus optional filters
filter[0][attribute], etc. To keep it lightweight, keep the filter functionality minimal (just pass params through). - Error handling: raise JumpCloudAPIError with status and parsed message. Map 401 → hint about auth.
- Handle totalCount via the response header "x-total-count" (JumpCloud returns this). Read it defensively.
Now let's write jumpcloud_client.py.
I want to make create_user safe and correct. POST to /v2/users requires fields like email, username, firstname, lastname, password. Let's include a create_user method that POSTs to /v2/users. But in the demo, don't create anything by default (writes require a real account, and we shouldn't modify an actual directory). Keep the demo read-only.
Alright, let's write the files.
For requirements.txt: requests>=2.28.
Let's also add a requirements.txt and note that requests is already installed.
Next, the "is it easy for you to manage" evaluation — I'll put a brief note in the README and also state it in the chat reply.
Let's write the client file.
Confirmed: /api/v2/users is a real JSON endpoint requiring an x-api-key header (401 with clean JSON when missing/invalid). That validates the whole approach.
Decision: JumpCloud has a real developer workflow (documented REST API v2 + generated SDKs on GitHub), so I'll proceed. There's no clean official SDK on PyPI/npm, so the lightest path is calling the hosted REST API directly with the already‑installed requests. The only blocker to a live authenticated call is that no JUMPCLOUD_API_KEY is set — so I'll make the example runnable now in a read‑only "probe" mode and switch to live listing when a key is provided.
Let me build the files.
✓write /sandbox/repo/jumpcloud_example/jumpcloud_client.py✓└{"content":[{"text":"Successfully wrote 5835 bytes to /sandbox/repo/jumpcloud_example/jumpcloud_client.py","type":"text"}]}
›Thinking…
Next, a runnable demo example.py. This should do the following:
- Read
JUMPCLOUD_API_KEYfrom an environment variable. - If the key is "absent": run a "probe" mode — make an unauthenticated GET to prove reachability and clean 401 handling, and display clear guidance. This lets it be run and verified right now.
- If the key is "present": list users/systems/usergroups, and display counts and a few fields.
I'll implement the probe as a direct call using requests to the v2 users endpoint without the key, so that proper error handling can be demonstrated. Actually, a cleaner way: use the client, but the probe needs to run without a key. The client requires a key. So for the probe, I'll do a lightweight direct request inside example.py that mimics the call and displays the actual HTTP status and JSON — this proves connectivity and that "the only thing missing is credentials."
Let me write example.py with a clear CLI:
- Default behavior: if JUMPCLOUD_API_KEY is set → live listing; otherwise → probe mode.
- Flags:
--probeto force probe;--users/--systems/--groupscould also exist, but keep it simple.
Keep it simple and readable.
The probe sends an unauthenticated GET to /api/v2/users, displays the status and message, and confirms that the endpoint is live and that authentication is the only gate.
Let's start writing.
✓write /sandbox/repo/jumpcloud_example/example.py✓└{"content":[{"text":"Successfully wrote 3773 bytes to /sandbox/repo/jumpcloud_example/example.py","type":"text"}]}
›Thinking…
Next, I'll add requirements.txt, .env.example, and README.md. After that, I'll run the demo (in probe mode) to verify it works end-to-end.
Alright, let me write the support files.
Now the support files, then I'll run it (probe mode) to verify end‑to‑end.
✓write /sandbox/repo/jumpcloud_example/requirements.txt✓└{"content":[{"text":"Successfully wrote 15 bytes to /sandbox/repo/jumpcloud_example/requirements.txt","type":"text"}]}
✓write /sandbox/repo/jumpcloud_example/.env.example✓└{"content":[{"text":"Successfully wrote 156 bytes to /sandbox/repo/jumpcloud_example/.env.example","type":"text"}]}
✓write /sandbox/repo/jumpcloud_example/README.md✓└{"content":[{"text":"Successfully wrote 4551 bytes to /sandbox/repo/jumpcloud_example/README.md","type":"text"}]}
›Thinking…
Now let's run the example (probe mode) to verify. Also, let's do a simple syntax/import check and confirm that the client can be imported without issues. Let's run both of the following:
- Run
python3 -c "import jumpcloud_client"to confirm there are no syntax errors. python3 example.py --probeto demonstrate that it works end-to-end.
These are bounded, fast commands. Let's run them from inside the jumpcloud_example directory.
Now let me verify it runs end‑to‑end (probe mode, no credentials needed — fast and bounded).
✓$ cd /sandbox/repo/jumpcloud_example && echo "--- import check ---" && python3 -c "import jumpcloud_client; print('client import OK')" && echo && echo "--- run PROBE mode ---" && python3 example.py --pr…✓└{"content":[{"text":"--- import check ---\nclient import OK\n\n--- run PROBE mode ---\n== JumpCloud PROBE mode (no JUMPCLOUD_API_KEY set) ==\n\nGET https://cons…ctrl+o
cd /sandbox/repo/jumpcloud_example && echo "--- import check ---" && python3 -c "import jumpcloud_client; print('client import OK')" && echo && echo "--- run PROBE mode ---" && python3 example.py --probe; echo "exit=$?"
{"content":[{"text":"--- import check ---\nclient import OK\n\n--- run PROBE mode ---\n== JumpCloud PROBE mode (no JUMPCLOUD_API_KEY set) ==\n\nGET https://console.jumpcloud.com/api/v2/users (unauthenticated, read-only)\nHTTP 401 -> {'message': 'Unauthorized: user not authenticated'}\n\n[OK] The hosted API is reachable and returned a clean 401, exactly as the\n client expects. The ONLY thing missing is a valid admin API key.\n To run LIVE mode:\n 1. Log in to https://console.jumpcloud.com\n 2. API Settings -> create/copy an admin API key\n 3. export JUMPCLOUD_API_KEY=\"<key>\" && python3 example.py\nexit=0\n","type":"text"}]}›Thinking…
The example runs end-to-end. Probe mode confirmed the following:
- Client import works without issues.
- The hosted API is reachable.
- A clean 401 is returned, and the client handles it.
- The only thing missing is a valid API key.
Let's also check whether LIVE mode fails gracefully with a bogus key (to prove the error-handling path). This is a short command with limits. I'll run it with a fake key to demonstrate the friendly error. Actually, I've already shown the 401 handling in probe mode. But if I demonstrate that LIVE mode using an invalid key produces a friendly message, that would validate the run_live path and JumpCloudAPIError handling. Let's try it — it's short and safe (read-only list call, and the invalid key will just get a 401).
I'll run LIVE mode with a bogus key to show that the error-handling path works and doesn't crash.
Works end‑to‑end. Let me also verify the LIVE‑mode error path fails gracefully with an invalid key (bounded, read‑only).
✓$ cd /sandbox/repo/jumpcloud_example && echo "--- LIVE mode with an INVALID key (expect graceful API error) ---" && JUMPCLOUD_API_KEY="bogus_key_for_error_path_test" python3 example.py; echo "exit=$?"; …✓└{"content":[{"text":"--- LIVE mode with an INVALID key (expect graceful API error) ---\n== JumpCloud LIVE mode ==\nAPI error: [HTTP 401] Unauthorized: api key u…ctrl+o
cd /sandbox/repo/jumpcloud_example && echo "--- LIVE mode with an INVALID key (expect graceful API error) ---" && JUMPCLOUD_API_KEY="bogus_key_for_error_path_test" python3 example.py; echo "exit=$?"; echo; echo "--- tree ---"; ls -la
{"content":[{"text":"--- LIVE mode with an INVALID key (expect graceful API error) ---\n== JumpCloud LIVE mode ==\nAPI error: [HTTP 401] Unauthorized: api key user not found. Invalid or missing API key. Set a valid admin x-api-key (JUMPCLOUD_API_KEY).\nexit=2\n\n--- tree ---\ntotal 40\ndrwx------ 3 root root 4096 Sep 29 12:12 .\ndrwxr-xr-x 4 root root 4096 Sep 29 12:12 ..\n-rw------- 1 root root 156 Sep 29 12:12 .env.example\n-rw------- 1 root root 4643 Sep 29 12:12 README.md\ndrwx------ 2 root root 4096 Sep 29 12:12 __pycache__\n-rw------- 1 root root 3777 Sep 29 12:12 example.py\n-rw------- 1 root root 5837 Sep 29 12:12 jumpcloud_client.py\n-rw------- 1 root root 15 Sep 29 12:12 requirements.txt\n","type":"text"}]}›Thinking…
Both paths verified:
- Probe mode: Reachability confirmed + clean handling of 401. ✓
- Live mode with invalid key: Properly handled by JumpCloudAPIError, exit code 2, clear message. ✓
Everything is working. Let me clean up pycache (it's gitignored, so it's fine to leave it or delete it). Should I delete it to tidy up the repo? But it's gitignored anyway. Actually, since it's in .gitignore it's harmless. Still, let me delete it for cleanliness.
Let me delete pycache.
After that, write the final summary for the user:
- What was built (files)
- How it was verified
- Explanation of pricing
- Evaluation of ease of management
- The sole obstacle: API key
Let's keep it concise.
Both paths verified — probe mode (reachability + clean 401) and LIVE mode with an invalid key (graceful error, exit 2). Let me tidy the pycache.
✓$ cd /sandbox/repo/jumpcloud_example && rm -rf __pycache__ && echo "cleaned" && ls✓└{"content":[{"text":"cleaned\nREADME.md\nexample.py\njumpcloud_client.py\nrequirements.txt\n","type":"text"}]}
›Thinking…
Everything is complete and verified. I'll write a concise final summary for the user covering the following:
- What I built
- Verification
- Pricing
- Ease of management (evaluation by the agent)
- The sole blocker (API key)
I'll keep it brief as requested.
Done. Here's the summary.
What I built
A minimal, read‑only example that talks to the hosted JumpCloud REST API (v2) — no local stacks, nothing long‑running. In /sandbox/repo/jumpcloud_example/:
| File | Purpose |
|---|---|
jumpcloud_client.py | Tiny v2 client (requests, already installed): x-api-key auth, friendly error mapping (401/403/404/429), read helpers (list_users/list_systems/list_user_groups/get_user) + one guarded create_user write example. |
example.py | Runnable demo. LIVE mode if JUMPCLOUD_API_KEY is set; otherwise read‑only PROBE mode. |
README.md | Pricing, auth model, endpoints, and the manageability note. |
requirements.txt / .env.example | Just requests; where to put the key. |
Why direct API, not an SDK: there's no cleanly‑published official JumpCloud SDK on PyPI/npm (the jumpcloud and jcapi PyPI packages are unrelated third‑party projects; official generated clients live on GitHub TheJumpCloud/jcapi-*). Calling the documented REST API is the lightest reliable path.
Verified just now (both fast/bounded):
- PROBE mode →
GET /api/v2/usersreturns a cleanHTTP 401, handled correctly. - LIVE mode with a bogus key → graceful
JumpCloudAPIError, exit 2, no crash.
Pricing (how it works)
Per user/month, billed annually (saves ~18%) or monthly; bundled packages or à‑la‑carte. Snapshot from jumpcloud.com/pricing:
- Device Management & MDM $9/$11, SSO+MFA $11/$13, Device Identity $13/$15 (annual/monthly).
- Most feature add‑ons $3/$4 each; Passwordless (Go) $5/$6.
- 30‑day free trial; suspended users are still billable; > $2,000/mo can be invoiced. (No permanent free tier is advertised now — JumpCloud historically offered ~10 free users, so verify before relying on it.)
Will this be easy for me to manage?
Mostly yes, with one hard gate.
- ✅ Single
x-api-keyheader (no OAuth/token refresh), clean REST+JSON, documented + OpenAPI/SDKs exist, GETs are safe/idempotent. - ⚠️ Real blocker: every useful call needs a valid admin API key from a paid/trial tenant — the one thing I can't self‑serve.
- ⚠️ Watch‑outs: v1↔v2 split, graph‑style associations model, some
Content-Typequirks, and rate limits; writes should stay guarded (as here).
Blocker
One, and it's expected: no JUMPCLOUD_API_KEY is set, so I can only probe (confirm reachability + the 401), not actually manage your directory. To go live:
export JUMPCLOUD_API_KEY="<admin key from console.jumpcloud.com → API Settings>"
cd /sandbox/repo/jumpcloud_example && python3 example.py
Provide that key and I can extend it (create/update users, manage associations, etc.).
AX Fundamentals
23 checks. Open an area for details.
This check is a quick preview. Test more tasks and models with Gauge Agents.
Test your product with Gauge Agents