Edits a Concierge router and republishes it live. Only the fields you supply change; omitted fields (and config dimensions Edge doesn't model, e.g. router-link enrichment waterfalls and CRM-upsert settings) are preserved. Supplying name re-derives the URL slug. Each dimension you send is a full replace, except branding which merges per sub-field (see below). Triggers are a product of optional kinds: a webform (form OR thirdPartyForm: mutually exclusive), inAppButton, and routerLink each replace only their own kind: writing one never destroys the others. Call concierge-router-get first to inspect the current config. - routing (opt): when present, sets the routing matrix; when omitted, the current routing is kept. Each row's rule, when it matches, runs that row's `outcome`; the catch-all `outcome` runs when no row matches: {routes: [{ruleId, outcome}], catchAll?: outcome} outcome (one of): {type: "Schedule", assignment, meetingTypeId, timeout?, crmActions?} {type: "Redirect", url} Schedule assigns the lead and books a meeting type. assignment is {type: "Distribution", distributionId} or {type: "User", userId}. timeout (opt) {minutes, onTimeout} sets the no-show fallback; onTimeout is {type: "Landing"} or {type: "Url", url}; omit timeout for the default (10 min → Landing). crmActions (opt) is an ordered post-booking chain, each {type: "ConvertLead"}, {type: "Notify", slackChannel?} (omit slackChannel to notify the assigned host instead of a named channel), {type: "AddToCampaign", campaignId, memberStatus} (add the matched Salesforce lead/contact to a campaign with that member status; find campaignId with campaign-list / campaign-search), {type: "SalesforceUpdateFields", contact:[{object,field,value}], lead:[{field,value}]} (write field values onto the matched Salesforce contact/lead), {type: "HubspotUpdateFields", contact:[{object,field,value}]} (write property values onto the matched HubSpot record), {type: "SalesforceUpsertRecord", settings:{noMatch,whenMatch}} (create/update the matched Salesforce lead/contact), or {type: "HubspotUpsertRecord", settings:{noMatch,whenMatch}} (create/update the matched HubSpot contact), {type: "SalesforceUpdateOwnership", contact:[{object,field}], lead:[{field}]} (set the record owner to the booked host), or {type: "HubspotUpdateOwnership", contact:[{object,field}]} (set the record owner to the booked host). Redirect sends the lead to a URL instead of booking. ruleId is required on every row; an always-match route is the catchAll. routes may be empty (then only the catchAll applies). Note: catchAll is OPTIONAL on update: omit it to keep the router's current catch-all unchanged (a targeted edit of the rows only), including keeping a router that has no catch-all catch-all-less. Supply it to replace (or add) the catch-all outcome. - form (opt): when present, fully REPLACES the webform with a Chili form built from these fields (the in-app-button / router-link triggers, if any, are preserved); MUST include the email field (PersonEmail). If the router's current webform is a third-party form this CONVERTS it to a Chili form. Mutually exclusive with thirdPartyForm. Omit to keep the current webform: [{dataField, label, description?, required?, hidden?}] Note: dataField is a CRM data-field reference: a default field name (e.g. PersonEmail, PersonFirstName) or a custom-field UUID; a made-up name is rejected (400). label is the field's display name; required toggles whether the guest must fill it. hidden (opt) is a PREFILLED value (a string) stored on the field but NOT shown to the guest: it is a value, not a show/hide flag; omit it for a normal visible field. - thirdPartyForm (opt): when present, fully REPLACES the webform with a THIRD-PARTY (external) form: the mapping from each external form field name to a CP data field; MUST include the email field (PersonEmail). If the router's current webform is a Chili form this CONVERTS it to a third-party form. Mutually exclusive with form. Omit to keep the current webform: [{formFieldName, dataField, label?}] Note: formFieldName is the external form field's submitted name (e.g. "0-1/email"); dataField/label are as for form. An existing per-field enrichment waterfall is preserved (matched by formFieldName) across the replace, as is the automapped container URL; neither is settable via the API. - inAppButton (opt): when present, fully REPLACES the in-app-button trigger's fields (the form/router-link triggers, if any, are preserved); MUST include the email field (PersonEmail). Omit to keep the current button: [{dataField}] - routerLink (opt): when present, fully REPLACES the router-link trigger's fields (the form/in-app-button triggers, if any, are preserved); MUST include the email field (PersonEmail). Omit to keep the current link: [{dataField, label, required?, hidden?}] Note: a router-link field's enrichment waterfall is not settable via the API; an existing one is preserved (matched by dataField) across the replace. - branding (opt): the cover/heading/language. Merged PER SUB-FIELD: a sub-field you supply is replaced; one you omit is PRESERVED (so a partial {headingText} does not wipe coverImage/language). localizations are preserved. To clear a sub-field entirely, edit the router in the Concierge app.: {coverImage?, headingText?, language?} - localizations (opt): when present, fully REPLACES the per-language overrides (preserving branding): {"<lang-tag>": {"<key>": "<text>"}} → {id, workspaceId, name?, slug?, routing: {known, representable, rows: [{ruleId?, ruleType?, outcome}], catchAll?: {outcome}}, form?, thirdPartyForm?, inAppButton?, routerLink?, branding?, localizations?} Note: the returned routing is the lossy per-row summary (same shape as concierge-router-get), not the matrix you sent ⚠ full-replace + publishes live immediately: supplying routing/form/thirdPartyForm/inAppButton/routerLink/localizations replaces that ENTIRE dimension, not a partial merge (branding is the exception: it merges per sub-field, see above) ⚠ routing REJECTED (409) when the router's existing routing: its DRAFT tree or its PUBLISHED tree: isn't representable in this simplified model (advanced routing built in the Concierge app: owner-assign, contact-options / multiple-choice, call-rep, multiple assignees per row, CRM actions beyond convert-lead / Slack-notify, enrichment or spam-check steps, etc.): to avoid silently destroying it, edit those routers in the Concierge app instead. Check routing.representable via concierge-router-get first. ⚠ form and thirdPartyForm are mutually exclusive (a router has a single webform): supplying both is rejected (400). Supplying form on a third-party-webform router (or thirdPartyForm on a Chili-webform router) CONVERTS the webform to the supplied kind, replacing the previous mapping. branding/localizations are always accepted. A name-only update always succeeds. ⚠ every update publishes the router's current DRAFT: if the draft carries unpublished edits made in the Concierge app, those go live as a side effect, even on a name-only patch ⚠ if the final publish step fails, the changes are saved on an UNPUBLISHED draft and a typed 422 error is returned: fix or delete the draft in the Concierge app see: concierge-router-get (check routing.representable / form.representable before replacing), rule-list (find ruleIds), distribution-list (find distributionIds), user-find (find userIds), meeting-type-list (find meetingTypeIds)
Parameters