Solanasis Credential Setup Guide
Last updated: 2026-03-23
ERPNext API Access
From this server (localhost)
ERPNext runs on http://localhost:8080. API user: claude-bot@solanasis.com.
# Token auth (preferred)
curl -H "Authorization: token $ERPNEXT_API_KEY:$ERPNEXT_API_SECRET" \
http://localhost:8080/api/method/frappe.auth.get_logged_user
# Password auth (fallback)
curl -c /tmp/cookies -H "Content-Type: application/json" \
-d '{"usr":"claude-bot@solanasis.com","pwd":"<password>"}' \
http://localhost:8080/api/method/loginFrom a second machine (Claude Code)
-
Clone solanasis-scripts:
gh repo clone dzinreach/solanasis-scripts -
Run the setup script:
python solanasis-scripts/scripts/setup_erpnext_env.py -
Enter the API key and secret when prompted (get these from a team member securely — Signal, in-person, etc.)
-
The script creates
~/.config/solanasis/.env(restricted permissions) -
After restarting your shell, Claude Code can access:
$ERPNEXT_URL— the ERPNext endpoint$ERPNEXT_API_KEY— API key$ERPNEXT_API_SECRET— API secret
-
Test:
curl -s -H "Authorization: token $ERPNEXT_API_KEY:$ERPNEXT_API_SECRET" \ $ERPNEXT_URL/api/method/frappe.auth.get_logged_user
In GitHub Actions / CI
Secrets are pre-configured on these repos: solanasis_crm, solanasis_core, solanasis-scripts
# In a workflow:
env:
ERPNEXT_URL: ${{ secrets.ERPNEXT_URL }}
ERPNEXT_API_KEY: ${{ secrets.ERPNEXT_API_KEY }}
ERPNEXT_API_SECRET: ${{ secrets.ERPNEXT_API_SECRET }}Regenerating ERPNext API Keys
If keys are compromised or need rotation:
# Generate new keys (inside Docker container)
docker exec frappe_docker-backend-1 bench --site db.solanasis.com execute \
frappe.core.doctype.user.user.generate_keys --args '["claude-bot@solanasis.com"]'
# IMPORTANT: Capture the api_secret from the output — shown only once
# Get the new api_key:
docker exec frappe_docker-backend-1 bench --site db.solanasis.com execute \
frappe.client.get_value --kwargs '{"doctype":"User","filters":"claude-bot@solanasis.com","fieldname":"api_key"}'
# Update GitHub Secrets:
for repo in solanasis_crm solanasis_core solanasis-scripts; do
gh secret set ERPNEXT_API_KEY --repo dzinreach/$repo --body "<new_key>"
gh secret set ERPNEXT_API_SECRET --repo dzinreach/$repo --body "<new_secret>"
done
# Update local env on any machines that have it:
# Edit ~/.config/solanasis/.env with new valuesSyncing Local .env to GitHub Secrets
Use the sync script (LOCAL → GITHUB only, not reverse):
cd solanasis-scripts
# Sync a single repo's .env to GitHub Secrets
python sync_env_secrets.py ../solanasis-site dzinreach/solanasis-site
# Sync all repos at once
python sync_env_secrets.py ../solanasis-docs dzinreach/solanasis-docs && ^
python sync_env_secrets.py ../solanasis-site dzinreach/solanasis-site && ^
python sync_env_secrets.py . dzinreach/solanasis-scripts
Important: GitHub Secrets are write-only. You cannot read them back via the API. They are a backup, not a sync target. To restore, re-enter values manually or retrieve from the original service dashboards.
Baserow API Access
Self-hosted instance (https://baserow.solanasis.com)
Two auth methods available:
| Method | Header | Expires? | Use for |
|---|---|---|---|
| DB Token | Authorization: Token {key} | Never | Row CRUD (scripts, automation) |
| JWT | Authorization: JWT {token} | 10 min access / 7 day refresh | Schema operations (create tables, fields) |
DB Token auth (preferred for scripts)
curl -H "Authorization: Token $BASEROW_DB_TOKEN" \
-H "Host: baserow.solanasis.com" \
http://localhost:8880/api/database/rows/table/{TABLE_ID}/Note: When calling from the server (localhost:8880), you MUST include Host: baserow.solanasis.com header. Through the tunnel URL, this isn’t needed but Cloudflare may block automated requests (error 1010).
JWT auth (for admin/schema operations)
import requests
# Step 1: Get JWT token
resp = requests.post("http://localhost:8880/api/user/token-auth/",
json={"email": BASEROW_EMAIL, "password": BASEROW_PASSWORD},
headers={"Host": "baserow.solanasis.com"})
access_token = resp.json()["access_token"]
# Step 2: Use token
resp = requests.get("http://localhost:8880/api/database/tables/database/54/",
headers={"Authorization": f"JWT {access_token}", "Host": "baserow.solanasis.com"})Environment variables
Stored in solanasis-scripts/.env:
| Variable | Purpose |
|---|---|
BASEROW_BASE_URL | https://baserow.solanasis.com |
BASEROW_DB_TOKEN | Database token (claude-bot, full CRUD) |
BASEROW_EMAIL | Admin email (ds@solanasis.com) |
BASEROW_PASSWORD | Admin password |
BASEROW_DATABASE_ID | 54 |
Regenerating Baserow DB Token
# Via JWT auth — create a new token
import requests
resp = requests.post("http://localhost:8880/api/user/token-auth/",
json={"email": BASEROW_EMAIL, "password": BASEROW_PASSWORD},
headers={"Host": "baserow.solanasis.com"})
jwt = resp.json()["access_token"]
resp = requests.post("http://localhost:8880/api/database/tokens/",
json={"name": "claude-bot-v2", "workspace": 45,
"permissions": [{"type": "create", "value": True}, {"type": "read", "value": True},
{"type": "update", "value": True}, {"type": "delete", "value": True}]},
headers={"Authorization": f"JWT {jwt}", "Host": "baserow.solanasis.com"})
print(resp.json()["key"]) # New tokenThen update .env and GitHub Secrets (gh secret set BASEROW_DB_TOKEN --repo dzinreach/solanasis-scripts --body "NEW_TOKEN").
Cloudflare Credentials
For Cloudflare Pages (solanasis-site deployment)
Stored in GitHub Secrets on solanasis-site repo:
CLOUDFLARE_ACCOUNT_ID— Solanasis Cloudflare accountCLOUDFLARE_API_TOKEN— Pages deployment permissions
For Cloudflare Tunnel (ACTIVE)
Tunnel solanasis (ID: c57c4d9c-e408-4e43-b0d5-190baa70568e) uses locally-managed credentials:
| File | Purpose |
|---|---|
~/.cloudflared/cert.pem | Account cert for solanasis.com zone (from cloudflared login) |
~/.cloudflared/c57c4d9c-...json | Tunnel-specific credentials (auto-generated on tunnel create) |
~/.cloudflared/config.yml | Ingress routing rules |
To re-authenticate (e.g., cert expired): Move cert.pem out of the way, run cloudflared login, select solanasis.com zone.
To recreate the tunnel (e.g., credentials compromised): Delete the tunnel (cloudflared tunnel delete solanasis), create a new one, update config.yml with new UUID, update DNS routes.
Credential Storage Architecture
Tier 1 — Local Development
├── ~/.config/solanasis/.env (chmod 600) — ERPNext API creds
├── _solanasis/frappe_docker/.env (gitignored) — ERPNext Docker config
├── _solanasis/solanasis-site/.env (gitignored) — Website dev config
├── ~/.cloudflared/cert.pem — Solanasis account cert (cloudflared login)
├── ~/.cloudflared/<UUID>.json — Tunnel credentials (cloudflared tunnel create)
└── ~/.cloudflared/config.yml — Tunnel ingress routing rules
Tier 2 — CI/CD (GitHub Secrets)
├── solanasis_crm: ERPNEXT_URL, ERPNEXT_API_KEY, ERPNEXT_API_SECRET
├── solanasis_core: ERPNEXT_URL, ERPNEXT_API_KEY, ERPNEXT_API_SECRET
├── solanasis-scripts: ERPNEXT_*, BASEROW_*, GOOGLE_AI_*, SHORT_IO_*
└── solanasis-site: CLOUDFLARE_*, BREVO_*, TURNSTILE_*, SITE_*
Tier 3 — Production (Cloudflare Worker Secrets)
└── Set via: wrangler pages secret put <NAME>
Security Rules
- NEVER commit
.env,.env.*, or.dev.varsto git - NEVER hardcode credentials in source files
- All
.envfiles must be in.gitignore - Local credential files must be
chmod 600 - If credentials are accidentally committed, follow:
solanasis-docs/solanasis-credentials-security-playbook.md