Conversation
Self-contained plugin for the owner's private Gett account via the mobile app surface (b2cgateway.gett.com); the official Business API is gated on a per-company 'order' entitlement. - headless connect flow: phone + SMS OTP + card-digits MFA (trusted-device shortcut skips MFA); refresh token + saved card persisted via ctx.updateConnection; card auto-discovered on connect - reads: whoami, find_place, price, nearby_drivers, ride_status - gated writes: book_ride (priced preview -> confirm places a real order on the saved card), cancel_ride — behind allowOrdering + confirm:true - access annotations on all 8 actions + ACCESS_CHECKLIST row + icon + README
- refresh() forces a token rotation
- connect status returns a keepalive hint { every: '10m', prompt: 'call gett.refresh()' }
- Gett's access token is ~15 min and refresh needs a live access token, so the
cadence MUST be under 15 min; a missed window forces an SMS re-login. Documented
the constraint (confirmed live: expires_in=900, all bearer variants 400).
connect() only stripped separators from the phone; a national number like 0526471797 (or 052-647-1797) stayed as-is while the challenge body hardcodes country_phone_prefix:972. Gett then returns otp_sent but silently drops the SMS. Add normPhone(): 00-exit/national-0/bare-local all map to 972XXXXXXXXX, idempotent for already-international input. Schema descriptions note local digits are accepted.
The challenge endpoint returns HTTP 200 even when Gett refuses to send the SMS (rc:3 status:"blocked" after too many attempts, with a blocked_until minute count). connect() only checked the HTTP status, so it reported step:"otp_sent" and the caller waited for a code that never came. Inspect the body verdict: on rc!=0 / status!=success return step:"blocked"|"error" with retry_after_minutes and the reason, so the agent tells the user to wait rather than ask for a code.
Both /auth/token calls (the accessToken refresh and the finishTokens IL→GL conversion) now carry ?lc=en. Without the query param Gett returns a bare 400 (empty body) — this, not the ~15-min access-token TTL, was the real lockout. Proven end-to-end 2026-08-11: routed the engine through mitmproxy, diffed our bytes against the app's successful conversion, and a live probe isolated ?lc=en as the sole cause (session token, x-user-location, bearer casing all irrelevant — GL→GL refresh returns 200 with just ?lc=en and no session token). Verified a full cold cycle: SMS onboarding → IL→GL → GL/GL tokens → refresh → real order booked + cancelled, all 200, both via proxy and direct. Consequently the session is long-lived/unattended: dropped the incorrect 'schedule refresh every <15 min or you're locked out' guidance from the refresh action, connectStatus keepalive hint, and docblock — the refresh token lasts ~90d and a stored session survives with no keepalive schedule.
Author
|
Update: the token-refresh limitation flagged above is resolved ( |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a gett plugin: search places, price rides, and book/cancel real taxis on the owner's own Gett account.
Why the consumer surface (not the Business API)
Gett's official
business-api.gett.comis gated on a per-companyorderentitlement that isn't self-serve (proven server-side: the portal's ownbusiness_api_clients/scopesreturns onlyfinance,employee). So this plugin rides the same JSON REST surface the phone app uses (b2cgateway.gett.com), reverse-engineered from an owner-driven capture.Shape (follows the repo conventions)
packages/runline-plugins/gett/src/index.ts, directfetch, no external deps.inputSchema/setConnectionSchemalike the other plugins.ctx.updateConnection(same pattern as gmail/googleCalendar).accesson every action + anACCESS_CHECKLIST.mdrow + icon + README table row.Actions (8)
Reads:
whoami,find_place,price,nearby_drivers,ride_statusWrites:
connect(owner login: phone → SMS OTP → card-digits MFA; a trusted device skips MFA),book_ride,cancel_rideSafety
Purchase-eligible by design — booking a ride spends money and summons a real car.
book_ridereturns a priced preview +requiresConfirmationand only places a real order when the connection setsallowOrdering: trueand the caller passesconfirm: true.cancel_rideis likewise gated. Single-tenant: one account per connection.Verification
bun --filter runline buildpasses;tsc --noEmitclean for the plugin.price→ real order booked (101764175, driver assigned) → tracked (Routing → Confirmed) → cancelled inside the free window (no charge) →refreshrotated the token on demand. Every call returned200, verified both through mitmproxy and direct.Token refresh (resolved)
An earlier revision suspected a ~15-min access-token TTL forced periodic re-login. That was wrong. The real cause of the
400s was a missing?lc=enquery param on/auth/token— the app sends it on every call and the server returns a bare400(empty body) without it. With?lc=enon both/auth/tokencalls (the refresh and the initial IL→GL conversion), refresh is fully headless and the session is long-lived and unattended: the GL refresh token lasts ~90 days and the grant does not need a live access token (a bearer expired by days still refreshes), so no keepalive schedule is required. Isolated via a controlled live probe — session token,x-user-location, and bearer casing were all irrelevant;?lc=enalone flips400 → 200.