Skip to main content

Sequenzy CLI

The Sequenzy CLI lets you manage subscribers, run campaigns, send emails, manage your team, triage inbox replies, operate outbound webhooks, and view analytics directly from your terminal. It also exposes read-only localization data for companies and templates.

Installation

# Using npx (no install needed)
npx @sequenzy/cli --help

# Using Bun (no install needed)
bunx @sequenzy/cli --help

# Or install globally
npm install -g @sequenzy/cli
Use the scoped package name for one-off runs: npx @sequenzy/cli ... or bunx @sequenzy/cli .... The unscoped sequenzy package is the TypeScript API library and does not expose a CLI binary.

Using the CLI with AI agents

If an AI agent will run the CLI for you, also install the Sequenzy skill. It gives your agent a versioned workflow guide for operating the CLI safely:
npx skills add Sequenzy/skills --skill sequenzy
Learn more in the Skills documentation.

Authentication

Login

sequenzy login
This prints a login URL and approval code in the terminal. Open the link in any browser, approve the session, and keep the terminal open until the CLI stores your API key. This flow also works in headless or agent-driven environments where the CLI cannot launch a browser for you.

Check login status

sequenzy whoami

Logout

sequenzy logout

Commands

Destructive commands (campaigns delete, ab-tests delete, ab-tests delete-variant, lists delete, segments delete, tags delete, webhooks delete, and team cancel-invitation) ask for confirmation before running. Pass --yes (or -y) to skip the prompt. When stdin is not interactive - in scripts, CI, or agent-driven runs - --yes is required and the command fails without it.

Subscribers

# List subscribers
sequenzy subscribers list
sequenzy subscribers list --tag vip
sequenzy subscribers list --segment active-users
sequenzy subscribers list --list "Master List" --json

# Add a subscriber
sequenzy subscribers add user@example.com
sequenzy subscribers add user@example.com --tag premium --attr name=John
sequenzy subscribers add user@example.com --skip-sequences

# Get subscriber details
sequenzy subscribers get user@example.com

# Remove a subscriber
sequenzy subscribers remove user@example.com
sequenzy subscribers remove user@example.com --hard  # permanent delete

Lists

# Create a list
sequenzy lists create "Monday Batch 01" --private

# Add subscribers to a list from an array
sequenzy lists add-subscribers list_123 --email one@example.com two@example.com

# Add subscribers to a list from JSON or CSV
sequenzy lists add-subscribers list_123 --emails-json '["one@example.com","two@example.com"]'
sequenzy lists add-subscribers list_123 --emails-file ./batch-001.csv
sequenzy lists import list_123 --emails-file ./batch-001.csv

# Update a list
sequenzy lists update list_123 --name "Weekly Newsletter" --private
sequenzy lists update list_123 --description "Sent every Monday" --no-private

# Remove subscribers from a list
sequenzy lists remove-subscribers list_123 --email one@example.com two@example.com
sequenzy lists remove-subscribers list_123 --emails-file ./churned.csv

# Delete a list
sequenzy lists delete list_123 --yes
The CLI splits large files into API-safe batches automatically. CSV files can use an email, e-mail, email address, or mail header; if no email header exists, the first column is used. Use this command instead of looping over subscribers add; standard API rate limits are 100 requests per minute per API key and 20 requests per second burst. lists remove-subscribers accepts the same email inputs as add-subscribers (--email, --emails-json, or --emails-file) and only removes list memberships; the subscribers stay in your audience. Emails that do not match a subscriber are reported as not found. Deleting a list removes all of its memberships but keeps the subscribers.

Send Email

Send transactional emails to single recipients:
# Using a template
sequenzy send user@example.com --template welcome --var name=John

# With nested array data for repeat blocks
sequenzy send user@example.com --template order-confirmation --vars-json '{"event":{"items":[{"title":"Pro plan","description":"Monthly subscription"}]}}'

# Using raw HTML
sequenzy send user@example.com --subject "Hello" --html "<h1>Hi!</h1>"

# From a file
sequenzy send user@example.com --subject "Report" --html-file ./email.html

Statistics

# Overview stats
sequenzy stats
sequenzy stats --period 30d

# Campaign stats
sequenzy stats --campaign camp_abc123

# Sequence stats
sequenzy stats --sequence seq_xyz789

Campaigns

# List campaigns
sequenzy campaigns list
sequenzy campaigns list --status draft

# Get campaign details
sequenzy campaigns get camp_abc123

# Update a draft campaign reply-to
sequenzy campaigns update camp_abc123 --reply-to support@example.com

# Create a draft campaign
sequenzy campaigns create "Launch" --subject "Big News!" --html-file ./launch.html
sequenzy campaigns create "Launch" --subject "Big News!" --blocks-file ./launch-blocks.json

# Schedule a campaign
sequenzy campaigns schedule camp_abc123 --at "2026-06-01T14:00:00Z"

# Send test email
sequenzy campaigns test camp_abc123 --to me@example.com

# Cancel a scheduled, paused, or sending campaign
sequenzy campaigns cancel camp_abc123

# Pause and resume delivery
sequenzy campaigns pause camp_abc123
sequenzy campaigns resume camp_abc123
sequenzy campaigns resume camp_abc123 --spread-over-hours 6

# Duplicate a campaign as a new draft
sequenzy campaigns duplicate camp_abc123
sequenzy campaigns duplicate camp_abc123 --mode ab_test
sequenzy campaigns duplicate camp_abc123 --mode variant --variant-id var_b

# Delete a campaign
sequenzy campaigns delete camp_abc123 --yes
Scheduling requires a future ISO timestamp and a verified sending domain.
campaigns create and campaigns update accept either raw HTML or Sequenzy block JSON via --blocks-json or --blocks-file. Use block input when you need editor-compatible content, conditional blocks, or repeat blocks. campaigns cancel stops scheduled, paused, waiting-approval, and actively sending campaigns immediately. It skips the confirmation prompt on purpose so you can stop a bad send fast, and it cannot be undone. Only sending campaigns can be paused, and only paused campaigns can be resumed; pass --spread-over-hours (1-72) to spread the remaining delivery over a longer window. Sending, scheduled, and paused campaigns must be cancelled before they can be deleted. campaigns duplicate defaults to --mode campaign, which copies the campaign and its email. Use --mode ab_test to also copy the campaign’s A/B test with all variants, or --mode variant with --variant-id to copy a single variant’s content as the new campaign email.

Landing Pages

# List landing pages
sequenzy landing-pages list
sequenzy landing-pages list --json

# Create a draft from a built-in template
sequenzy landing-pages create "Product Waitlist" --template waitlist
sequenzy landing-pages create "Launch Page" --template launch --slug launch

# Get or edit a page
sequenzy landing-pages get lp_abc123
sequenzy landing-pages update lp_abc123 --name "Updated Waitlist" --slug waitlist

# Publish or unpublish
sequenzy landing-pages publish lp_abc123
sequenzy landing-pages unpublish lp_abc123

# Connect or verify a custom landing page domain
sequenzy landing-pages connect-domain pages.example.com
sequenzy landing-pages update-domain-settings --verify

# Delete a page
sequenzy landing-pages delete lp_abc123
landing-pages create, update, publish, and unpublish can accept full builder JSON with --content-json or --content-file. Built-in template keys include from-scratch, waitlist, lead-magnet, launch, demo-request, webinar, newsletter, product-hunt, pricing-offer, agency-lead-gen, and feature-announcement. Custom landing page domains need a CNAME record pointing to pages.sequenzydns.com; run update-domain-settings --verify after DNS propagates.

A/B Tests

# List A/B tests, optionally scoped to a sequence
sequenzy ab-tests list
sequenzy ab-tests list --sequence seq_abc123

# Get variants and localization status
sequenzy ab-tests get ab_abc123

# Get aggregate and per-variant stats
sequenzy ab-tests stats ab_abc123 --period 30d

# Update a draft variant
sequenzy ab-tests update-variant ab_abc123 var_b --subject "Better subject"
sequenzy ab-tests update-variant ab_abc123 var_b --html-file ./variant-b.html
sequenzy ab-tests update-variant ab_abc123 var_b --blocks-file ./variant-b-blocks.json

# Create an A/B test for a draft campaign
sequenzy ab-tests create camp_abc123
sequenzy ab-tests create camp_abc123 --test-percentage 30 --duration-minutes 120 --winner-criteria click_rate
sequenzy ab-tests create camp_abc123 --variants-json '[{"subject":"Alternative subject"}]'

# Add a variant to a draft campaign A/B test
sequenzy ab-tests add-variant ab_abc123 --subject "Alternative subject"
sequenzy ab-tests add-variant ab_abc123 --subject "Alternative subject" --blocks-file ./variant.json

# Remove a variant from a draft campaign A/B test
sequenzy ab-tests delete-variant ab_abc123 var_b --yes

# Delete a campaign A/B test
sequenzy ab-tests delete ab_abc123 --yes
Only draft A/B tests can be edited. Use get first to discover variant IDs, then update the target variant with a subject, preview text, HTML, or Sequenzy blocks. ab-tests create works on campaigns in draft or rejected status that do not already have an A/B test. Control variant A is created automatically from the campaign’s current email; extra variants come from --variants-json or --variants-file (each entry takes subject, optional previewText, and optional blocks). The test percentage covers 5-50% of the audience (default 20), the duration runs 15-1440 minutes (default 240), and the winner criteria is open_rate (default) or click_rate. Variants can only be added or removed while the test is in draft status, variant A is the control and cannot be deleted, and running tests cannot be deleted.

Sequences

# List sequences
sequenzy sequences list

# Get sequence details
sequenzy sequences get seq_abc123

# Create a purchase sequence scoped to one product (event property filters)
sequenzy sequences create deliver-ebook --trigger event_received \
  --event-name ecommerce.order_placed \
  --property-filters-json '[{"path":"lineItems[].providerProductId","operator":"equals","value":"prod_123"}]' \
  --steps-file ./steps.json

# Enable/disable
sequenzy sequences enable seq_abc123
sequenzy sequences disable seq_abc123

# Manually enroll subscribers in a sequence
sequenzy sequences enroll seq_abc123 --email one@example.com two@example.com
sequenzy sequences enroll seq_abc123 --emails-file ./vips.csv
sequenzy sequences enroll seq_abc123 --emails-json '["one@example.com"]' --target-node-id node_123

# Dry-run cancellation for enrollments with matching entry event values
sequenzy sequences cancel-enrollments seq_abc123 --field-path order.id --field-values ord_123,ord_456

# Apply cancellation for one subscriber enrollment
sequenzy sequences cancel-enrollments seq_abc123 --subscriber-id sub_abc123 --apply
sequences enroll takes the same email inputs as lists add-subscribers (--email, --emails-json, or --emails-file, up to 500 emails per call) and only enrolls active subscribers: unknown emails are reported as not found, and inactive or already enrolled subscribers are skipped. Enrollment starts at the first step after the trigger unless you pass --target-node-id, and the sequence must be accepting entrants (enabled and not paused for enrollment).

Templates

# List templates
sequenzy templates list
sequenzy templates list --company comp_abc123
sequenzy templates list --json

# Get template
sequenzy templates get tmpl_abc123
sequenzy templates get tmpl_abc123 --company comp_abc123 --json

# Create or update with HTML
sequenzy templates create welcome --subject "Welcome" --html-file ./welcome.html
sequenzy templates update tmpl_abc123 --subject "Updated" --html-file ./welcome-v2.html

# Create or update with Sequenzy blocks
sequenzy templates create welcome --subject "Welcome" --blocks-file ./welcome-blocks.json
sequenzy templates update tmpl_abc123 --blocks-file ./welcome-v2-blocks.json
templates list includes localization sync status by locale. templates get includes the full localized variants and the effective company localization config. When you pass blocks JSON, each block can include a condition object for recipient-specific content, for example:
[
  {
    "id": "intro",
    "type": "text",
    "content": "<p>Hello there</p>",
    "variant": "paragraph"
  },
  {
    "id": "pro-offer",
    "type": "text",
    "content": "<p>Your Pro upgrade is ready.</p>",
    "variant": "paragraph",
    "condition": {
      "variable": "plan",
      "operator": "equals",
      "value": "pro"
    }
  }
]
Use merge-tag variable names without {{ }} inside condition.variable.

Companies

sequenzy companies list
sequenzy companies get comp_abc123
sequenzy companies get comp_abc123 --json
companies get includes the effective email localization settings for that company.

Segments

# List saved segments
sequenzy segments list

# Preview how many subscribers are in a segment
sequenzy segments count seg_abc123

# Create a Stripe-product segment
sequenzy segments create --name "Bought Pro" --stripe-product prod_pro

# Create a threshold-based Stripe-product segment
sequenzy segments create --name "3+ Pro Payments" \
  --stripe-product prod_pro \
  --purchase-operator at-least \
  --payments 3

# Create a purchased-product segment (Shopify, WooCommerce, or Commerce API orders)
sequenzy segments create --name "Starter Kit Buyers" --commerce-product api:prod-starter-kit

# Create a repeat-buyer segment by order count
sequenzy segments create --name "Repeat Kit Buyers" \
  --commerce-product api:prod-starter-kit \
  --purchase-operator at-least \
  --orders 2

# Create a segment that matches any filter instead of all filters
sequenzy segments create --name "VIP Or Gmail" \
  --match any \
  --filter-json '[{"field":"tag","operator":"contains","value":"vip"},{"field":"email","operator":"contains","value":"@gmail.com"}]'

# Create a segment from raw filter JSON
sequenzy segments create --name "Custom Filter" \
  --filter-json '[{"field":"stripeProduct","operator":"is","value":"prod_pro"}]'

# Combine campaign-specific engagement filters (bounced A but not B)
sequenzy segments create --name "Bounced A Not B" \
  --filter-json '[{"field":"emailBounced","operator":"is","value":"campaign:cmp_abc"},{"field":"emailBounced","operator":"is_not","value":"campaign:cmp_xyz"}]'

# Create a nested segment with an event filter
sequenzy segments create --name "Active Non Buyers" \
  --filter-json '{"root":{"kind":"group","joinOperator":"and","children":[{"kind":"filter","field":"attribute","operator":"lte","value":"last_login_days_ago:90"},{"kind":"group","joinOperator":"or","children":[{"kind":"filter","field":"event","operator":"is_not","value":"saas.purchase:30d"},{"kind":"filter","field":"segment","operator":"is_not","value":"seg_paying_customers"}]}]}}'

# Update a segment's name, filters, or join operator
sequenzy segments update seg_abc123 --name "Churn Risk"
sequenzy segments update seg_abc123 --filters-json '[{"field":"tag","operator":"contains","value":"vip"}]'
sequenzy segments update seg_abc123 --join-operator or

# Delete a segment
sequenzy segments delete seg_abc123 --yes
For Stripe product segments, use the Stripe product ID, not the product name. The CLI maps:
  • bought -> field: "stripeProduct", operator: "is", value: "prod_xxx"
  • didnt-buy -> field: "stripeProduct", operator: "is_not", value: "prod_xxx"
  • at-least -> field: "stripeProduct", operator: "at_least", value: "prod_xxx:3"
  • less-than -> field: "stripeProduct", operator: "less_than_count", value: "prod_xxx:3"
For purchased-product segments (--commerce-product), use provider:productId where the provider is shopify, woocommerce, or api and the product ID is the one your orders carry in their line items. Product IDs are provider-scoped (Shopify product 42 and WooCommerce product 42 are different products); a bare ID without a provider prefix matches the ID on any provider. The CLI maps:
  • bought -> field: "commerceProduct", operator: "is", value: "shopify:42"
  • didnt-buy -> field: "commerceProduct", operator: "is_not", value: "shopify:42"
  • at-least -> field: "commerceProduct", operator: "at_least", value: "shopify:42:2" (use --orders)
  • less-than -> field: "commerceProduct", operator: "less_than_count", value: "shopify:42:2" (use --orders)
For trial timing, pass --filter-json directly:
  • {"field":"stripeTrialProduct","operator":"is","value":"prod_xxx:is_canceled"}
  • {"field":"stripeTrialProduct","operator":"gte","value":"prod_xxx:start_at:7 days ago"}
  • {"field":"stripeTrialProduct","operator":"is","value":"prod_xxx:end_at:2026-05-26"}
Engagement filters (emailSent, emailOpened, emailClicked, emailBounced, emailComplained) accept either a rolling time window (7d, 30d, 90d, 180d, all) or a specific sent campaign (campaign:<campaign_id>). Combine two campaign-specific filters with the default --match all to express rules like “bounced campaign A but not campaign B”. Look up campaign IDs with sequenzy campaigns list. --filter-json accepts the same filter shape used by the API and MCP. Pass a JSON array for legacy flat filters, or an object with a nested root group for v2 nested logic. If you omit filter or group id values, the CLI fills them in automatically. Event filters use field: "event" with values like saas.purchase:30d, saas.purchase:all, or saas.purchase:5:30d for count-based operators. Segment filters use field: "segment" with the saved segment ID as the value. By default, segments create matches all filters with AND logic. Pass --match any to save the segment with OR logic instead. segments count returns the number of active subscribers who currently match the segment. In the dashboard you may also see a broader matched-contact count, but campaigns only send to active subscribers. segments update accepts the same filter shapes as segments create via --filters-json or --filters-file (a flat array or an object with a nested root group). Provided filters replace the segment’s existing rules, and missing filter IDs are filled in automatically. lists import is an alias for lists add-subscribers.

Audience Syncs

Push segments to Meta custom audiences for Facebook and Instagram retargeting. Requires the Meta Ads integration to be connected in the dashboard (Settings → Integrations).
# List audience syncs with schedule and status
sequenzy audience-syncs list

# List the connected Meta ad accounts
sequenzy audience-syncs ad-accounts

# Create a sync from a ready-made segment template
sequenzy audience-syncs create --template recent-buyers \
  --ad-account act_1234567890 \
  --name "Sequenzy - Recent buyers"

# Create a sync from an existing segment, refreshed hourly
sequenzy audience-syncs create --segment seg_abc123 \
  --ad-account act_1234567890 \
  --name "Sequenzy - VIPs" \
  --frequency hourly

# Pause, resume, or change the schedule
sequenzy audience-syncs update sync_abc123 --active false
sequenzy audience-syncs update sync_abc123 --frequency weekly

# Trigger an immediate run
sequenzy audience-syncs sync sync_abc123

# Remove a sync (the Meta audience itself is kept)
sequenzy audience-syncs delete sync_abc123
--template accepts ready-made segment IDs like zero-ltv, no-purchase-1y, recent-buyers, high-spenders-ecom, non-buyers, and engaged; the segment is created automatically on first use. Audiences are add-only: subscribers who leave the segment stay in the Meta audience.

Tags

# List tag definitions (bare `sequenzy tags` also lists)
sequenzy tags list

# Create a tag
sequenzy tags create vip
sequenzy tags create "VIP Customer" --color purple

# Update a tag's color
sequenzy tags update tag_abc123 --color red

# Delete a tag
sequenzy tags delete tag_abc123 --yes
Tag names are normalized to lowercase with hyphens, so VIP Customer becomes vip-customer. Colors include values like gray (the default), red, green, blue, and purple. System tags cannot be updated or deleted, and tags used by sequences cannot be deleted until those sequences stop referencing them. Deleting a tag removes it from every subscriber.

Team

# List team members and pending invitations
sequenzy team list

# Invite a team member
sequenzy team invite teammate@example.com --role admin
sequenzy team invite finance@example.com --role viewer --billing-access

# Cancel a pending invitation
sequenzy team cancel-invitation inv_abc123 --yes
Existing Sequenzy users are added to the team immediately; everyone else receives an email invitation. Inviting and cancelling invitations requires owner or admin access, and --billing-access can only be granted by the company owner. Use team list to find invitation IDs.

Inbox

# List conversations
sequenzy inbox list
sequenzy inbox list --status open --unread
sequenzy inbox list --search "refund" --limit 50

# Get a conversation with its full message history
sequenzy inbox get conv_abc123

# Reply to a conversation
sequenzy inbox reply conv_abc123 --text "Thanks for reaching out!"
sequenzy inbox reply conv_abc123 --html-file ./reply.html --subject "Re: your question"

# Add an internal note instead of emailing the subscriber
sequenzy inbox reply conv_abc123 --text "Customer asked for a refund" --note

# Triage
sequenzy inbox close conv_abc123
sequenzy inbox reopen conv_abc123
sequenzy inbox mark-read conv_abc123
The inbox collects subscriber replies to campaigns, sequences, and transactional email. Provide a reply body with --text and/or --html-file. Outbound replies are emailed to the subscriber and reopen closed conversations; messages sent with --note are internal-only and never reach the subscriber.

Webhooks

# List webhook endpoints
sequenzy webhooks list

# Create a webhook endpoint
sequenzy webhooks create --name CI --url https://example.com/hook --event email.bounced
sequenzy webhooks create --name "All events" --url https://example.com/hook

# Update a webhook endpoint
sequenzy webhooks update wh_abc123 --url https://example.com/new-hook
sequenzy webhooks update wh_abc123 --event email.bounced email.complained
sequenzy webhooks update wh_abc123 --disable

# Delete a webhook endpoint
sequenzy webhooks delete wh_abc123 --yes

# Test and inspect deliveries
sequenzy webhooks test wh_abc123
sequenzy webhooks deliveries wh_abc123 --limit 50
sequenzy webhooks replay wh_abc123 del_456
Webhook payloads are signed. webhooks create prints the signing secret once at creation time; it cannot be retrieved later, so store it immediately to verify webhook signatures. Valid --event values cover email.*, subscriber.*, and sequence.* event types; omit --event to subscribe to the default event set. On webhooks update, --event replaces the existing event list, and changing the URL or re-enabling with --enable resets the failure circuit breaker. Use webhooks deliveries to find delivery IDs before running webhooks replay.

Products

# List synced products (Stripe, Shopify, WooCommerce, api)
sequenzy products list --provider stripe

# Queue a Stripe product catalog sync
sequenzy products sync

# Create or update a product (Commerce API, keyed by your productId)
# and attach its deliverable file in the same command
sequenzy products upsert my-ebook --title "The Ebook" --price-cents 1900 --currency USD --file ./ebook.pdf

# Bulk upsert products from a JSON file (up to 100)
sequenzy products upsert --products-file ./products.json

# Delete a product pushed via the Commerce API
sequenzy products delete my-ebook

# Upload a local file and attach it as the product's deliverable
sequenzy products attach-file prod_abc --file ./guide.pdf

# Attach an externally hosted file instead
sequenzy products attach-file prod_abc --url https://example.com/template.zip --name template.zip

# Remove the attached file
sequenzy products detach-file prod_abc
attach-file --file (and upsert --file) uploads the file to Sequenzy storage (PDF, ePub, ZIP, images, audio, video, or text, up to 100MB) and attaches it in one step. attach-file and detach-file accept the product ID from products list or, for Commerce API products, your own productId (e.g. sequenzy products attach-file my-ebook --file ./ebook.pdf). After attaching, purchases of the product enrich the saas.purchase event with download.url and download.name, so purchase sequences can deliver the file with {{event.download.url}}. See Digital Product Delivery. upsert writes to the platform-agnostic Commerce API catalog: products are keyed by your own productId, and the same IDs are matched against order line items for purchase sequences and product filters.

Account

sequenzy account
sequenzy account --json
sequenzy websites

AI Generation

# Generate email
sequenzy generate email "Welcome email for new SaaS trial users"
sequenzy generate email "Product launch announcement" --style branded --tone professional

# Generate sequence
sequenzy generate sequence "Onboarding for SaaS trial users"
sequenzy generate sequence "Re-engagement for inactive users" --count 3 --days 7

# Generate subject lines
sequenzy generate subjects "Black Friday sale" --count 5
Generated content is returned as draft content for review. Sequence generation supports up to 10 emails.

Environment Variables

VariableDescriptionDefault
SEQUENZY_API_URLAPI server URLhttps://api.sequenzy.com
SEQUENZY_APP_URLApp URL for authhttps://sequenzy.com

Config Location

The CLI stores configuration in:
  • macOS/Linux: ~/.config/sequenzy/config.json
  • Windows: %APPDATA%\sequenzy\config.json

Scripting

The CLI is designed to work well in scripts:
#!/bin/bash

# Import subscribers from CSV into a list
sequenzy lists import list_123 --emails-file subscribers.csv

# Check if logged in
if ! sequenzy whoami > /dev/null 2>&1; then
  echo "Not logged in"
  exit 1
fi

Exit Codes

CodeMeaning
0Success
1Error

Troubleshooting

CLI failures now include a short human explanation, a suggested next step, and a direct docs link so agents and scripts can recover faster.

”could not determine executable to run for package sequenzy”

Use the CLI package explicitly:
bunx @sequenzy/cli login
bunx sequenzy login installs the unscoped TypeScript API library package, which does not include the sequenzy executable.

”Not logged in”

Run sequenzy login to authenticate.

”API error: 401”

Your session may have expired. Run sequenzy login again.

Browser doesn’t open

sequenzy login always prints the approval link. Open the URL shown in the terminal to complete authentication.