smsh / ticketing-bridge
SmartShanghai bridge for SolidSource ticketing external identity login.
Package info
github.com/alexw27/smsh-ticketing-bridge
Type:symfony-bundle
pkg:composer/smsh/ticketing-bridge
Requires
- php: >=8.4
- symfony/config: ^7.4 || ^8.0
- symfony/dependency-injection: ^7.4 || ^8.0
- symfony/framework-bundle: ^7.4 || ^8.0
- symfony/http-client: ^7.4 || ^8.0
- symfony/http-client-contracts: ^3.5
- symfony/routing: ^7.4 || ^8.0
- symfony/yaml: ^7.4 || ^8.0
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Private Symfony bundle for plugging SmartShanghai into the SolidSource ticketing external identity system.
Package name:
"smsh/ticketing-bridge": "*"
What It Provides
- Integration provider key:
smartshanghai - Admin integration provider:
SmartShanghai - External identity provider button for
/loginand/register - Authentication handler for
/connect/smartshanghai/check - WeChat Scanner sales channel publisher (
wechat_scanner) — generates scanner Mini Program QR codes when an event is published - WeChat Mini Program QR codes on discount campaigns (admin campaign form)
- WeChat Mini Program QR codes on event affiliates (admin event → Affiliates, and
GET /api/v1/promoter/affiliates/...) - WeChat Mini Program QR codes on event access links (admin event → Access links) — consumer MiniProgram
pages/ticketingSchedule/ticketingSchedulewithaccessscene - WeChat Mini Program QR codes on organizations (admin organization form) — join QR for
pages/org/orgon the scanner MiniProgram (wechat-scanner) - SmartShanghai event listing sync on publish — links SMSH listings via report access token and imports thumbnail
POST /api/v1/me/organizations— add the signed-in user to an organization (promoter / scanner membership)POST /api/v1/auth/external/wechat-market/phone— exchange a WeChatgetPhoneNumbercode for the signed-in user's verified phone- WeChat Mini Program subscription messages for communication-flow notification type
wechat_subscribe
WeChat Scanner event QR codes
On first event publish, the bridge generates a Mini Program QR for the wechat_scanner sales channel.
- Credentials: enabled WeChat integration with slug
wechat-scanner(System → API / Integrations). - Page:
pages/scanner/scannerwith sceneid={eventId}.
WeChat campaign Mini Program QR codes
When a campaign is saved, the bridge generates a Mini Program QR for each targeted event and shows it on the campaign admin form (below the web share QR). Global and venue-only campaigns are skipped until an event (or price-category) target is added.
- Credentials: WeChat Pay MiniProgram App ID + App Secret by default (same as MiniProgram checkout). Override with SmartShanghai setting MiniProgram WeChat connection slug. Do not use
wechat-scannerunless the QR should open the door MiniProgram. - Page:
pages/smtkEvent/smtkEvent. - Scene:
id={eventId}&aci={campaignId}(SmartTicket event id and campaign id, e.g.id=5614&aci=99). MiniProgram checkout sendsaciasaffiliate_campaign_id.
Generation failure is logged and does not block saving the campaign.
WeChat event-affiliate Mini Program QR codes
When an event affiliate is saved, the bridge generates a Mini Program QR and shows it on the affiliate admin form (below the web share QR). The same QR is attached to promoter affiliate JSON as wechat_miniprogram_qr on GET /api/v1/promoter/affiliates/{token} and GET /api/v1/promoter/affiliates/{affiliateId}/{token} (and on create).
- Credentials: same consumer WeChat MiniProgram as campaign QRs (WeChat Pay by default).
- Page:
pages/smtkEvent/smtkEvent. - Scene:
id={eventId},ea={affiliateId}(e.g.id=5753,ea=14). WeChatgetwxacodeunlimitrejects&in scene, so pairs are comma-separated. MiniProgram checkout sendseaasevent_affiliate_id.
Generation failure is logged and does not block saving the affiliate.
WeChat event access-link Mini Program QR codes
When an event access link is saved, the bridge generates a Mini Program QR and shows it on the access-link admin edit form. This opens the SmartShanghai consumer MiniProgram (not the door scanner).
- Credentials: same consumer WeChat MiniProgram as campaign/affiliate QRs (WeChat Pay by default, e.g. App ID
wx7242d750b44505ed). - Page: SmartShanghai
miniprogram_event_pagewhen set, otherwisepages/ticketingSchedule/ticketingSchedule. - Scene:
id={eventId},access={slug}(e.g.id=5952,access=vip). WeChatgetwxacodeunlimitrejects&and limits scene to 32 characters — keep slugs short. The MiniProgram should load the event API with?access={slug}.
Generation failure is logged and does not block saving the access link.
WeChat organization Mini Program QR codes
When an organization is opened in admin, the bridge generates a Mini Program QR and shows it on the organization form (below the details form). Scanning it opens the MiniProgram join page so a signed-in user can be added to that organization via POST /api/v1/me/organizations.
- Credentials: same scanner MiniProgram as event sales-channel QR codes — enabled WeChat integration with slug
wechat-scanner. - Page:
pages/org/org. - Scene:
id={organizationId}(e.g.id=14).
Generation failure is logged and does not hide the rest of the organization form.
SmartShanghai event listing sync
When an event is published, the bridge:
- Creates a promoter report access token (label:
SmartShanghai listing sync). - Calls
PATCH {api_base_url}/api2/admin/smtk-event-bridge/{event_id}?key={api_token}with{ "access_token": "<raw token>" }—{event_id}is the ticketing event id (same assmtk_idon SmartShanghai). - Downloads
data.thumbnail_pathfrom the response and sets it as the event thumbnail (admin → Media).
Requires an enabled SmartShanghai integration with api_base_url and api_token. Optional setting Event bridge API path (default /api2/admin/smtk-event-bridge/{event_id}).
Buyer refund cancellation message
When an admin refund succeeds and Notify buyer is checked (single-order refund or event refund batch), the bridge also tells SmartShanghai to message that buyer.
The call runs only when the order's user has a SmartShanghai external identity. The {user_id} is that identity's provider user id, not the ticketing user id. Guest orders and buyers without a SmartShanghai login are skipped. A failed call is logged and does not fail the refund.
POST {api_base_url}/api2/messages/{user_id}/sendTicketingCancellation?key={api_token} Content-Type: application/json { "message": "Reason shown to buyers", "orderNumber": "A-100", "orderUrl": "https://api.smartticket.cn/orders/access/…", "orderId": 1126264 }
message is the refund reason note. orderId is the ticketing order id. orderUrl is the public order portal URL. The attempt is stored in log_outbound_message with channel smartshanghai.
WeChat Mini Program subscription messages
Communication-flow notification types with channel wechat_subscribe are sent by WeChatMiniProgramSubscribeMessageSender.
The sender loads the Mini Program access token from the selected WeChat integration (default slug wechat-market) and calls:
POST https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=ACCESS_TOKEN
touser is the buyer openid resolved by the host app (checkout payment metadata, then the WeChat external identity). The template ID and keyword values come from the notification type. The Mini Program must call wx.requestSubscribeMessage for that template before WeChat will deliver it. A rejected send is returned to the host as a failed outbound log and does not fail the rest of the communication flow.
Join the signed-in user to an organization
SmartShanghai promoter and scanner clients can add the current JWT user to an organization:
POST /api/v1/me/organizations Authorization: Bearer <access-token> Content-Type: application/json {"organizationId": 12}
Send one of organizationId / organization_id, slug, or code. The call is idempotent: a user who is already a member gets 200 with alreadyMember: true; a new membership returns 201. Inactive or unknown organizations return 404 with organization_not_found. API keys cannot call this endpoint — it requires a signed-in user (ROLE_USER).
WeChat Market phone number
SmartShanghai MiniProgram clients can send the getPhoneNumber dynamic token after the user agrees:
POST /api/v1/auth/external/wechat-market/phone Authorization: Bearer <access-token> Content-Type: application/json {"code":"<getPhoneNumber code>","access_token":"<optional wechat miniprogram token>"}
code is required (5-minute, single-use WeChat token — not the wx.login() code). access_token is the MiniProgram client-credential token used by phonenumber.getPhoneNumber. When omitted, the bridge fetches one from the enabled WeChat integration with slug wechat-market.
On success the user's phone is replaced with WeChat's verified number and phoneVerifiedAt is stamped. An auth.phone_verified audit event is written.
The host app must import the bundle routes (once per installation):
# config/routes/smsh_ticketing_bridge.yaml smsh_ticketing_bridge: resource: '@SmshTicketingBridgeBundle/config/routes.yaml'
Expected SmartShanghai Flow
- User clicks
Continue with SmartShanghai. - The ticketing app redirects to the configured SmartShanghai
login_url. - The bridge appends
callback_url=<absolute /connect/smartshanghai/check URL>. - SmartShanghai authenticates the user and redirects back with a short-lived JWT:
/connect/smartshanghai/check?jwt=<smartshanghai-jwt>
The callback also accepts token=<jwt> or an Authorization: Bearer <jwt> header.
The JWT payload should contain an external user id as either:
user_idsub
The bridge decodes the JWT only to read that user id for the verify API path. JWT validity is checked by SmartShanghai's API, not locally.
Integration Settings
Configure these under System -> API / Integrations -> SmartShanghai:
login_url: SmartShanghai login URL.api_base_url: SmartShanghai API base URL.api_token: partner API key sent as thekeyquery parameter on every SmartShanghai API call.verify_user_path: optional path, defaults to/api2/ticketing/users/{user_id}.email_match_path: optional path, defaults to/api2/ticketing/users/{user_id}/email-matches.miniprogram_event_page: used for access-link QRs (defaultpages/ticketingSchedule/ticketingSchedulewhen empty). Unused for campaign and event-affiliate QRs (those always usepages/smtkEvent/smtkEvent).miniprogram_wechat_connection_slug: optional WeChat integration slug for campaign/affiliate/access-link QRs. Empty uses WeChat Pay MiniProgram credentials.event_bridge_path: optional path, defaults to/api2/admin/smtk-event-bridge/{event_id}.
Verify User API Contract (login)
The bridge calls:
GET {api_base_url}{verify_user_path}?key=<api_token>
Authorization: Bearer <smartshanghai-jwt>
Example default URL:
GET https://smsh.solidsource.software/api2/ticketing/users/123?key=...
Expected successful response:
{
"valid": true,
"email": "user@example.com"
}
email is optional. The ticketing app can create a local user with only the linked external identity.
Any non-2xx response or "valid": false rejects login.
Email match API Contract (checkout)
When trusted checkout customer payload is enabled and a SmartShanghai-linked buyer submits customer.email, the bridge asks SmartShanghai whether that email belongs to the linked user. This uses the partner API key only (no client JWT) and returns a boolean — it must not expose the stored email.
POST {api_base_url}{email_match_path}?key=<api_token>
Content-Type: application/json
{"email":"user@example.com"}
Example default URL:
POST https://smsh.solidsource.software/api2/ticketing/users/123/email-matches?key=...
Expected successful response:
{
"match": true
}
matches: true|false is also accepted. Non-2xx or an unexpected payload fails checkout with customer_email_verification_failed. match: false fails with customer_email_mismatch.