morning API v2 | OAuth 2.0 auth | Interactive REPL | Onboarding wizard | JSON envelopes for AI agents | Hebrew error messages
Built by JangoAI using the cli-anything methodology | README בעברית
Why this exists
I'm Maor, a solo developer running JangoAI — a small AI automation studio in Israel. I use morning's API daily for my own business and my clients', and I got tired of writing the same httpx + JWT boilerplate in every project. So I built a proper CLI around it.
This started as a personal tool, but there's no reason to keep it private — if you work with morning's API, you'll save time with this. I'm sharing it with the Israeli dev community because I think we deserve better tooling for our local platforms. If it helps you, I'd love to hear about it.
v0.2.0 — API v2 ready. morning rewrote their developer docs at developers.morning.co (OpenAPI 2.0.0): OAuth 2.0 token endpoint on dedicated IDP hosts, a new presigned-S3 expense upload flow, Basic-auth partners endpoints, and reference data staying on the shared cache host. This release tracks all of it, with automatic fallback to the legacy token endpoint where the new IDP isn't deployed. See the CHANGELOG.
Install
pip install morning-cli
Get started in 30 seconds
# 1. Run the interactive wizard — connects your morning account
morning-cli auth init
# 2. Start the REPL
morning-cli
# 3. Or use one-shot commands
morning-cli --json auth whoami
morning-cli --json document types --lang he
morning-cli --json client search
What does auth init look like?
╭──────────────────────────────────────────────────╮
│ morning-cli │
│ setup wizard │
│ │
│ Connect your morning account. │
│ You'll be up and running in under a minute.│
╰──────────────────────────────────────────────────╯
>> Step 1/4 Choose environment
╭──────────────────────────────────────────────────╮
│ Where do you want to connect? │
│ [1] sandbox Safe testing, no real money │
│ [2] production Live business data │
╰──────────────────────────────────────────────────╯
Enter 1 or 2 [1]:
OK Step 1/4 Choose environment
>> Step 2/4 Get your API keys
╭─ Open in browser ────────────────────────────────╮
│ https://app.greeninvoice.co.il/settings/developers/api
│ Settings > Advanced > Developers > Create API Key│
╰──────────────────────────────────────────────────╯
>> Step 3/4 Enter credentials
API Key ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
API Key Secret: (hidden as you type)
>> Step 4/4 Verify connection
Connecting to morning API...
╭─ All set ────────────────────────────────────────╮
│ Connected successfully! │
│ Business Your Business Name │
│ Env SANDBOX │
│ Saved to ~/.greeninvoice/credentials.json │
╰──────────────────────────────────────────────────╯
Commands
| Group | Endpoints | Highlights |
|---|---|---|
| auth | local | init (wizard), login, logout, whoami, refresh |
| session | local | show, reset, history |
| business | 10 (legacy) | list, current, get, update, numbering, footer, types, file-upload — removed from the v2 docs, still served |
| client | 8 | add, get, update, delete, search, assoc, merge, balance |
| supplier | 6 | add, get, update, delete, search, merge |
| item | 5 | add, get, update, delete, search |
| document | 13 | create, preview, get, search, close, open, download, types, statuses |
| expense | 13 | CRUD + open/close + upload (presigned-S3 flow) + drafts-search/draft-delete |
| payment | 3 | form, tokens-search, charge |
| partner | 3 | users, connect, disconnect (HTTP Basic) |
| tools | 4 | occupations, countries, cities, currencies — shared cache host, no auth |
Usage examples
Create a proforma invoice (חשבון עסקה)
cat > /tmp/proforma.json <<'JSON'
{
"description": "ריטיינר חודשי",
"type": 300,
"lang": "he",
"currency": "ILS",
"vatType": 0,
"client": {"name": "Acme Ltd", "emails": ["ap@acme.com"], "country": "IL"},
"income": [
{"description": "שירותי ייעוץ", "quantity": 10, "price": 300, "currency": "ILS", "vatType": 0}
]
}
JSON
morning-cli --json document create --file /tmp/proforma.json
Search recent clients
morning-cli --json client search --data '{"page":1,"pageSize":10}'
Get PDF download link for a document
morning-cli --json document download <document_id>
Upload an expense receipt (API v2 presigned-S3 flow)
morning-cli --json expense upload receipt.pdf # new expense draft
morning-cli --json expense upload receipt.pdf --id <expense_id> # attach to expense
morning-cli --json expense drafts-search # parsed draft appears here
JSON output for AI agents
Every --json command returns a consistent envelope:
{"ok": true, "op": "document.create", "data": {"id": "...", "number": 12345}}
Errors include the morning errorCode and Hebrew errorMessage:
{"ok": false, "op": "document.create", "error": {"code": 1110, "message": "מחיר לא תקין.", "http_status": 400}}
| Exit code | Meaning |
|---|---|
0 |
Success |
1 |
Unexpected internal error / aborted confirmation |
2 |
Usage error, local config error (e.g. missing credentials), or API error (4xx) |
3 |
Server error (5xx) / network failure |
Success envelopes go to stdout; error envelopes go to stderr (agents: capture both streams).
Common morning API error codes
| Code | Meaning |
|---|---|
401 |
Token expired (CLI auto-refreshes) |
1003 |
No active business in the account |
1006 |
Subscription expired |
1007 |
Missing permission |
1012 |
Feature requires a higher plan |
1110 |
Invalid price in a line item |
2002 |
Wrong email or password |
2102 |
Can't add more businesses on this plan |
2403 |
Document type not supported for this business type |
Environment variables
| Variable | Purpose | Default |
|---|---|---|
MORNING_API_KEY_ID |
API key ID | — |
MORNING_API_KEY_SECRET |
API key secret | — |
MORNING_ENV |
sandbox or production |
sandbox |
MORNING_BASE_URL |
Override the core REST base URL | auto |
MORNING_GATEWAY_URL |
Override the OAuth IDP + file-upload hosts (proxies/custom deploys) | auto |
MORNING_AUTH_MODE |
auto (OAuth with legacy fallback), oauth (no fallback), legacy (skip IDP) |
auto |
How auth works (v0.2.0+): the CLI obtains a 1-hour access token via OAuth 2.0
client_credentials from the morning IDP (POST /idp/v1/oauth/token on
api.morning.co / api.sandbox.morning.dev), and falls back to the legacy
POST /account/token automatically if the IDP isn't available for your
environment. Refresh on 401 is automatic either way. Reference data (tools
group) is served from the shared cache.greeninvoice.co.il host, no auth needed.
Tests — 85 tests, including 23 live E2E (sandbox or production via MORNING_E2E_ENV)
pip install -e ".[test]"
# Unit tests — no network
pytest cli_anything/greeninvoice/tests/test_core.py -v
# Full suite with live sandbox
export MORNING_SANDBOX_ID=<your-id>
export MORNING_SANDBOX_SECRET=<your-secret>
CLI_ANYTHING_FORCE_INSTALLED=1 pytest cli_anything/greeninvoice/tests/ -v
Coverage:
- 52 unit tests — credentials + per-service host resolution, OAuth token
acquisition (camelCase/snake_case shapes, legacy fallback, unreachable-host
fallback, TLS errors surfaced, no-fallback on bad keys,
MORNING_AUTH_MODEoverrides, RFC 6749 error strings), wizard verification (gateway override, core-API rejection propagates), Basic-auth partners, presigned-S3 upload flow (field ordering, no-auth on S3), session locking, payload parsing - 10 offline E2E — help, version, error envelopes,
--json auth initstream purity, REPL smoke, env-var CI path - 23 live sandbox E2E — read-only smoke per resource group, paginated searches, item/supplier mutation round-trips, invoice lifecycle, proforma preview with Hebrew content, expense file upload
- 3 real bugs caught during development (late-binding, type 305 gate, Tools host/locale)
For AI agents — SKILL.md auto-discovery
morning-cli ships a SKILL.md file
auto-discovered by the REPL banner and Claude Code / Cursor. It contains:
- Full command reference with examples
- Error code table
- Agent-specific guidance (always use
--json, sandbox defaults, token refresh) - Non-interactive
auth initfor CI
If you're an agent reading this, start with the SKILL.md.
Methodology — cli-anything 7-phase SOP
Built following the cli-anything 7-phase pipeline:
- Codebase analysis — parsed the Apiary spec into a 66-endpoint map
- Architecture — REPL-first,
--jsonenvelopes, session locking, sandbox-first - Implementation — PEP 420 namespace package
cli_anything.greeninvoice - Test planning — TEST.md written before tests
- Test implementation — unit + live E2E
- Test documentation — results appended to TEST.md
- PyPI publishing —
pip install morning-cli
Full SOP: GREENINVOICE.md
Contributing
PRs welcome! Run the tests before submitting:
pip install -e ".[test]"
pytest cli_anything/greeninvoice/tests/test_core.py -v
See open issues for good first contributions.
JangoAI — AI automation for Israeli businesses
Website · GitHub · morning API docs
MIT License · morning-cli is a community project and is not officially affiliated with morning Ltd.
Release files for morning-cli 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| morning_cli-0.2.0.tar.gz | 51.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| morning_cli-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size:103.9 kB
Release files / morning_cli-0.2.0.tar.gz
| Download URL | morning_cli-0.2.0.tar.gz |
|---|---|
| Size | 51.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
36d2930c2c68e158b038a0555cefe8c114e784a501a05f4219e589249153f811
|
|
BLAKE2b-256 checksum How to use checksums |
ef242d0598847a4e4c0f3aa81524957ab6179cf86e2650294f4fd12cacadb2d8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.6
|
Release files / morning_cli-0.2.0-py3-none-any.whl
| Download URL | morning_cli-0.2.0-py3-none-any.whl |
|---|---|
| Size | 52.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a9bd7e06c699dc3d74deeab12603ea1b77d6bd0908f51a009e23889735bfe4f8
|
|
BLAKE2b-256 checksum How to use checksums |
f4952e4a278194100031bd0fa4dc658b323aa321aca12ff407aaa5664615caf4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.6
|