Skip to main content

bookai-cli

Command-line client for the bookai group-sales back office API — manage venue pricing, offerings and their showings, and view and cancel orders from the terminal or a script, instead of clicking through the admin web app.

This is a thin HTTP client: it talks only to the public, authenticated JSON API and contains no business logic or backend code.

Install

pip install bookai-cli

Authenticate

bookai login

Opens your browser to authorize this machine, then saves the key locally (your OS keychain, or a 0600 file under your user config dir if no keychain is available) — no copy-pasting a raw key required. The environment you just logged into also becomes your default for every later command that doesn't explicitly pass --env/--base-url (see Environments below) — run bookai login again any time to re-authorize, switch accounts, or switch which environment is your default.

Check what's currently active any time with:

bookai whoami

For scripting/CI, skip login and use a key directly instead — mint one from the back office's API Keys page and set it as an environment variable:

export GROUPSALES_API_KEY=gsk_...

--api-key (or GROUPSALES_API_KEY) always takes priority over a bookai login-saved key when both are present.

bookai logout removes the locally saved key (add --all to clear every environment at once). This only forgets the key on this machine — it stays valid until you revoke it from the back office's API Keys page.

Environments

This project runs three environments:

--env Base URL
prod https://b2b.bookai.now
sandbox https://b2b-sandbox.bookai.now
local http://localhost:8001

You don't need to pass --env on every command. bookai login sets the environment you just authorized as your default (saved to a small local config file, separate from the key itself) — so once you've run bookai --env sandbox login, every later bookai venues list / bookai pricing ... targets sandbox automatically, with no flags needed. Run bookai whoami any time to check which environment and key are currently active.

--env <name> (or --base-url <url>/GROUPSALES_BASE_URL for a fully custom URL not in the table above) overrides your default for that one command only — it doesn't change what bookai login set as your default. bookai login saves a separate key per base URL, so logging into sandbox and prod don't clobber each other; switching your default just means running bookai login again against the other one.

Before your first bookai login, the default is prod if nothing else is set.

Global options (--api-key, --base-url, --env, --json) go before the subcommand: bookai --json venues list, not bookai venues list --json.

Interactive shell

Run bookai with no command to get a prompt — commands run without the leading bookai, and your environment/key from that shell's startup (or from a login/--env typed mid-session) stays in effect line to line:

$ bookai
bookai interactive shell -- commands run without the leading `bookai` (e.g. `venues list`).
Type `help` for the command list, `whoami` for your current env/key, `exit` to quit.

bookai (sandbox)> venues list
...
bookai (sandbox)> exit

exit/quit/Ctrl-D leaves the shell. This is purely a convenience layer — every line is dispatched through the exact same commands as one-shot usage, so anything in Usage below works here too.

Usage

bookai venues list
bookai venues create                            # guided prompts -- creates a brand-new venue + your account, no key needed yet
bookai venues import <meetings page URL> -o draft.json   # read your website into a draft (writes nothing)
bookai venues import <home URL> <tickets URL> -o draft.json  # several pages of one site (museums, attractions)
bookai venues import --apply draft.json          # import the edited draft: spaces, events, tickets, brand, logo, address

bookai contacts list <venue_id>
bookai contacts get <venue_id> <contact_id>
bookai contacts add <venue_id> --first-name Jamie --last-name Rivera --email jamie@example.com --role Owner
bookai contacts update <venue_id> <contact_id> --first-name Jamie --last-name Rivera --role "Events Manager"
bookai contacts delete <venue_id> <contact_id>
bookai contacts invite <venue_id> <contact_id>   # email them a link to create their own login for this venue

bookai pricing list <venue_id>
bookai pricing get <venue_id> <rule_id>
bookai pricing set <venue_id> --min-group 10 --max-group 50 --min-price 20 --max-price 30
bookai pricing set <venue_id> --min-group 10 --max-group 50 --min-price 20 --max-price 30 \
    --source acme-isv --external-id acme-rule-42   # tag a rule as synced from an external system
bookai pricing update <venue_id> <rule_id> --min-group 10 --max-group 50 --min-price 18 --max-price 28
bookai pricing delete <venue_id> <rule_id>

bookai offerings create --name "Learn-to-Ski Package" --price 229      # an all-day product
bookai offerings create --name "Glow Night Tubing" --price 40 \
    --times 17:00,18:00,19:00 --days fri,sat --capacity 30             # timed, venue's local time
bookai offerings create --file products.json                           # a whole catalog
bookai offerings update <offering_id> --price 95 --description "..."
bookai offerings update <offering_id> --status cancelled               # stop offering it
bookai offerings rm <offering_id>                                      # delete (refused once booked)
bookai offerings list
bookai offerings show <offering_id>
bookai offerings extend <offering_id> --to 2027-03-31    # run it for longer
bookai offerings extend <offering_id> --by 3m            # ...or just push the end date out

bookai offerings slots list <offering_id>
bookai offerings slots add <offering_id> --date 2026-11-19 --time 19:00 --capacity 400
bookai offerings slots add <offering_id> --date 2026-11-19 --time 19:00 --capacity 400 \
    --duration 4 --repeat-weekly 3                       # lay out a four-week run in one go
bookai offerings slots set <offering_id> <slot_id> --time 14:00    # move it, keeping its length
bookai offerings slots set <offering_id> <slot_id> --capacity 250
bookai offerings slots rm <offering_id> <slot_id>

bookai orders list
bookai orders list --page 2
bookai orders cancel <order_id>                       # kept, marked cancelled, for the record; asks first (--yes skips)
bookai orders fnb <order_id> --total 155.50            # final food & beverage after the event (or --quantity N); never below the confirmed amount

bookai conversations list                             # recent conversations and their pipeline stage
bookai conversations delete <id>                      # with its quotes and offers; asks first (--yes skips)

bookai customers list                                 # individuals and organizations, lead or booked
bookai customers list --stage lead --kind organization --sort name --order asc
bookai customers show <customer_id>                   # contact, stage, notes, orders and value
bookai customers add --email pat@acme.com --first-name Pat --notes "May trip, 40 people"
bookai customers add --email old@school.org --booked  # someone who has booked with you before
bookai customers update <customer_id> --phone "(615) 555-0100" --consent
bookai customers delete <customer_id>                 # a lead added by mistake; asks first (--yes skips)
bookai customers import leads.csv                     # CSV or Excel: previews, writes nothing
bookai customers import leads.csv --apply             # writes the valid rows, lists the rest
bookai customers export --stage booked --format xlsx  # in the columns import reads
bookai customers template                             # an empty file with the import's columns
bookai customers quote <customer_id> --offering <id> --size 40 --date 2026-11-10
bookai customers send-link <customer_id> --quote <quote_id>   # emails them a link into your booking chat
bookai customers links <customer_id>                  # sent, opened, expired or revoked
bookai customers revoke-link <customer_id> <link_id>

bookai organizations list                             # schools, companies, nonprofits that booked with you
bookai organizations list --type school --registration outdated
bookai organizations show <organization_id>           # registration answers, members, bookings

bookai forms list                                     # one registration form per organization type
bookai forms show school                              # the live questions (--draft for the draft)
bookai forms publish school                           # shows what changes and who it affects, then asks

bookai search acme                                    # every record at your venue: guests, deals, setup
bookai search where do coaches park                   # matches meaning, not just exact words
bookai search jane@school.org --type offer --type quote
bookai --json search "school trip" --limit 5          # the API's response, for scripts

bookai ask which offers need my approval               # ask in plain words; it looks it up
bookai ask -c and which of those are over 50 people    # follow up on your last conversation
bookai ask                                             # a conversation, one question per line
bookai ask --history                                   # your recent conversations

Ask

bookai ask puts a question to the back office's Ask agent, the same one behind the Ask panel in the web app. It searches and reads your venue's records (guests and their conversations, offers, quotes, orders, offerings and showings, policies, pricing, payment terms, contacts), shows each lookup as it runs, and answers with numbered links to the records it used. It can only read. Nothing it does changes anything.

  • -c / --continue follows up on your last conversation in that environment, and --session ID follows up on any of them (IDs from --history).
  • With no question it opens a conversation in the terminal: one question per line, and an empty line or Ctrl-D finishes. A question can also come on stdin: echo "who went quiet after a quote?" | bookai ask.
  • --json prints the final answer with its citations and steps, for scripts.
  • Quote questions containing ? or ! if your shell expands them.

Products

offerings create makes something guests can book, in the words you'd use to describe it -- no offering types, price bands or time zones to know:

  • --type: ticket (the default), lesson, camp or school-trip.
  • --price is the price per guest. Add --price-range 69-99 to let the booking agent quote anywhere in that range, or --tier 20-99:79-89 --tier 100-500:69-79 to price by group size.
  • Without --times it's an all-day product (add --daily-capacity for a limit). With --times 10:00,14:00 it's timed: every listed time on --days (default every day), --capacity seats each, --duration 90m long, from --from to --to (default: today for a year), at the venue's own local time.
  • Some types ask for details, passed as --attr key=value: camps need age_range; lessons take skill_level; school trips take grade_level and chaperone_ratio. If one is missing the API says which.
  • --dry-run shows what would be created without creating it.

--file products.json creates a whole catalog in one go, which is the quick way to build a demo venue. The file is a list of products with the same fields as the options (price_range, daily_capacity and booking_scope take underscores; attributes is an object). Products whose name already exists are skipped, so you can add to the file and run it again:

[
  {"name": "Learn-to-Ski Package", "price": 229, "from": "2026-10-30", "to": "2027-05-02",
   "description": "Lift ticket, rental and a half-day group lesson."},
  {"name": "Group Ski Lesson", "type": "lesson", "price": 149, "booking_scope": "per_session",
   "attributes": {"skill_level": "beginner to advanced"}},
  {"name": "Glow Night Tubing", "price": 40, "times": ["17:00", "18:00", "19:00"],
   "days": ["fri", "sat"], "duration": "60m", "capacity": 30}
]

Showings

offerings slots manages the individual showings of a timed offering — the dates and times people actually book. --repeat-weekly is there because a season is usually a repeating shape rather than a list of one-off dates: --repeat-weekly 3 creates the showing plus three weekly copies, four in total.

The API keeps you from doing the things that would quietly break bookings, and the CLI reports its reason rather than swallowing it:

  • a showing with seats already sold can't be removed, and its capacity can't drop below what's sold
  • a showing outside the offering's run is refused, rather than sitting on the calendar looking bookable — extend the run first
  • narrowing a run past showings that already exist is refused for the same reason: they'd stay on the calendar while quietly dropping out of availability

offerings extend is exactly that "extend the run first" step. It's a plain update of the offering's end date — --to for an exact date, --by 3m (also 6w, 30d) to push it out from wherever it currently ends.

Import from your website

bookai venues import reads your venue's own website into a draft and saves it as JSON. Nothing is written to your venue yet. It reads:

  • Branding and address — brand name, logo and street address (from any page).
  • Hotels — event spaces with size, capacity and setups, from the meetings page.
  • Museums and attractions — admission tickets, general admission or timed entry, with the prices the site states (adult, senior, child, group...) and the entry times it lists, from the tickets or groups page.
  • Dated events on the page.

Give up to 6 pages of the same site in one go, e.g. the home page for the logo and address and the tickets page for prices:

bookai venues import https://museum.example/ https://museum.example/visit/tickets -o draft.json

Edit the file, then apply it. Each item lists what it still needs under missing:

  • include picks which items to import. A page listing more than 25 spaces includes the 25 largest; calendar events found on an attraction's site start out excluded.
  • Spaces and events: base_price_per_person must be set on each included one, or passed once with --default-price. A website never states group rates for them, so the import never guesses one. Spaces are priced per guest.
  • Tickets: the price is the group or adult rate the site states, and every tier goes in the offering's description. A price is kept only if that amount appears on the page, so check it's the one you want — walk-up rates are often higher than a group rate.
  • Timed tickets need slot_capacity (guests per entry time), which sites rarely state: set it, pass --default-capacity, or change admission_type to "ga". Entry times are created for the next four weeks; add more with bookai offerings slots add.
  • branding.logo_url is the logo it will use, and logo_candidates lists the others it found. Set branding.apply to false to leave your branding alone.
  • address replaces your venue's street address (and, in the US, its timezone). Set address.apply to false to keep yours.
  • Items are bookable for a year from today unless the item or --valid-from/--valid-to says otherwise.

Applying again updates what an earlier apply imported instead of duplicating it, so the same draft can be rehearsed on --env sandbox and then applied to production. If a site blocks automated reads, save each page from your browser and pass it with --html, once per URL in the same order (--html home.html --html tickets.html); the URLs are still needed so links resolve. A page that can't be read is skipped with a note, as long as one can. Pages with no structured data are read by an AI extractor. Check its figures against the site before applying, and use --no-ai to turn it off.

bookai venues create is the one command that works with no API key at all — it's how a brand-new venue's very first account gets created in the first place (same as signing up in the browser). It asks for the venue's details and your own name/email/password one at a time, confirms before submitting, then tells you to run bookai login next.

Add --json before the command for machine-readable output instead of a table (bookai --json orders list) — useful for piping into jq or scripting in CI.

Development

pip install -e ".[dev]"
pytest

Tests are fully offline (HTTP is mocked via respx) — no server or database required.

Metadata

Release files for bookai-cli 0.12.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for bookai-cli 0.12.1
File Size Uploaded
bookai_cli-0.12.1.tar.gz 49.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for bookai-cli 0.12.1
File Interpreter ABI Platform
bookai_cli-0.12.1-py3-none-any.whl Python 3 none any Details

Total release size: 95.1 kB

Release files / bookai_cli-0.12.1.tar.gz

Download URL bookai_cli-0.12.1.tar.gz
Size 49.8 kB
Tags Source
SHA-256 checksum
How to use checksums
cbbeb42dc16a9f044ca620f6e5e5d9765dfb33011f8ab8d8c8c6d0c1e128bfa9
BLAKE2b-256 checksum
How to use checksums
c710621ac68f7d9400e92235b5ecb7e46fc7720e6cf5c875b8022259e8784391
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.

Transparency log

Release files / bookai_cli-0.12.1-py3-none-any.whl

Download URL bookai_cli-0.12.1-py3-none-any.whl
Size 45.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9c680960d22b2c8a1bff4708f136e81c49245ba0d05d88596525a51d899b881f
BLAKE2b-256 checksum
How to use checksums
23cc1d2ad28542b5c6953210542761f278ca8b10446e891555a7ae573eb65f8b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.12.1 This release

2 release files

0.12.0

2 release files

0.11.0

2 release files

0.10.0

2 release files

0.9.0

2 release files

0.8.1

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page