Command-line client for Innago's sanctioned Open API, with an optional browser-session adapter for capabilities that exist only in Innago's landlord portal. It authenticates the OpenAPI with service credentials, caches and refreshes OAuth tokens, and exposes 57 sanctioned operations from Innago's live Swagger spec plus the documented health endpoint.
- Read operations verified live: properties, units, leases, tenants, invoices, invoice payments, individual payments, maintenance, and expenses.
- Write operations are mapped but must only be exercised against an approved real property-management job.
- Known Innago issue: filtered
GET /v1/paymentsmay return association/server errors; invoice-specific payment reads work. - Innago's ReadMe omits live lease create/edit and application/applicant operations. The CLI includes them from
/openapi/swagger/v1/swagger.json. - The sanctioned OpenAPI does not expose invoice update or delete operations. The optional
portalnamespace can reach the same private endpoints used by Innago's UI.
ln -sf "$PWD/bin/innago" "$HOME/bin/innago"The sanctioned OpenAPI commands have no third-party runtime dependencies. Python 3.9+ is sufficient. Portal login/capture additionally requires Microsoft's playwright-cli; portal requests themselves remain standard-library-only.
Set these environment variables:
INNAGO_CLIENT_IDINNAGO_CLIENT_SECRETINNAGO_X_API_KEY
export INNAGO_CLIENT_ID="..."
export INNAGO_CLIENT_SECRET="..."
export INNAGO_X_API_KEY="..."If agent-vault is installed, set INNAGO_AGENT_VAULT or create ~/.config/innago/config.json:
{
"agent_vault": "your-vault-name"
}Environment variables take precedence. Credentials never live in this repository. The access and refresh-token cache is stored at ~/.cache/innago/token.json with mode 0600.
OpenAPI credentials are not self-service in the Innago dashboard. Email support@innago.com with the subject API Key Request and ask them to enable OpenAPI access for your property-owner account.
Ask for the complete credential set and current integration guide:
- Client ID
- Client Secret
- X-Api-Key
- Current OpenAPI/PDF integration guide
In the account used to develop this CLI, the initial request went to support@innago.com; support representative Deepanshu Monga escalated it internally and returned the credentials from that same support address. Treat the shared support inbox as the durable contact rather than relying on a specific representative.
Do not send credentials back over email or commit them to a repository. Store them in environment variables or a secret manager as described above.
Innago's integration guide uses a service-account password grant:
username = client_id
password = client_secret
client_id = client_id
client_secret = client_secret
grant_type = password
The PDF shows Authorization: bearer <token>. That fails with HTTP 401 because Innago incorrectly treats the auth scheme as case-sensitive. Requests must use uppercase:
Authorization: Bearer <token>
See docs/solutions/integration-issues/innago-lowercase-bearer-authorization-20260716.md.
innago auth
innago token # status only
innago token --show # deliberately print bearer token
innago health
innago properties
innago units <propertyUid>
innago leases --property <propertyUid> --page 1
innago tenants --lease <leaseUid>
innago invoices --lease <leaseUid> --tenant <tenantUid>
innago invoice-payments <invoiceUid>
innago maintenance --property <propertyUid> --page 1
innago expensesRun innago --help for the full command surface.
Innago's landlord web app exposes useful operations that are absent from its sanctioned OpenAPI. The portal namespace isolates these private, undocumented endpoints from the stable command surface.
No username or password is accepted or stored by this CLI. Login happens in Innago's real headed browser flow:
innago portal login
# Complete Innago/Auth0 login in the Chrome window, then:
innago portal capture
innago portal authcapture reads only Innago's AuthorizationToken_prod and APIToken_prod cookies from that Playwright session. It does not save the browser's full storage state or unrelated Google cookies. The sanitized portal cache lives at ~/.cache/innago/portal.json with mode 0600 and expires with Innago's browser token.
Existing Playwright storage state can also be imported. Only the two required Innago cookies are retained:
innago portal import-state ~/.playwright-auth/innago.jsoninnago portal invoice-get 12345678
innago portal invoice-delete 12345678 --confirm 12345678
innago portal raw GET /api/some/private/path
innago portal raw POST /api/some/private/path --json '{...}' --confirm-writeInvoice deletion mirrors Innago's own portal behavior. Bizarrely, its private endpoint uses an HTTP GET for the destructive action. The exact numeric invoice ID must be repeated with --confirm.
Private endpoints are not official, versioned, or promised stable by Innago. They may change without notice. Keep scripts on the sanctioned OpenAPI whenever it supports the required operation, and use portal only for the gaps.
Commands that create, alter, record, reject, cancel, sync, or delete data are real production operations. Do not use them as synthetic tests. Validate writes only against an actual approved job, confirm the payload against current API docs or observed portal behavior, execute once, then read the resulting resource back.
Dedicated delete commands require repeating the target ID with --confirm. Generic raw commands require --confirm-write for non-read HTTP methods. Known invoice-delete portal paths are blocked from portal raw entirely so they cannot bypass the stronger confirmation check.
A portable agent skill ships in skills/innago/SKILL.md. It teaches agents to prefer sanctioned OpenAPI, use portal endpoints only for gaps, confirm writes, read changes back, and avoid Innago-specific traps such as month-to-month invoice regeneration.
Copy the skill into your agent's skill directory, or point your agent framework at this repository's skills/innago/ folder. Will's live installation is maintained from the canonical wv-agent-skills repository and mirrored here for CLI users.
python3 -m unittest discover -s tests -v
python3 -m py_compile bin/innago