Skip to content

Create an extension

This page is for developers. An extension is described by a JSON manifest: what it declares (permissions, columns, blocks, rules) is validated by Sweescape when you save it. Its interface is an HTML page hosted by Sweescape and displayed in an iframe isolated from the ticketing page.

Any account can create extensions and use them on its own events. Publishing on the marketplace is reserved to the Sweescape team.

  1. Open your account menu, click Extensions, then Create extension.

  2. Fill in the form:

    • Name: the name shown in your lists and in the page editor.
    • Package name: the unique id of the extension, in reverse-DNS notation and lower case, for example com.subsol.seatmap. It cannot be changed after creation and must be free across all of Sweescape.
    • Description: optional.
  3. Click Create. The window moves to the Write the manifest step, with a prefilled example manifest.

Under the manifest editor, the Upload the UI file(s), then copy their URL into the manifest field sends your files to Sweescape.

  • Accepted formats: html, js, mjs, css, json, svg, png, jpg, jpeg, gif, webp, ico, woff, woff2, ttf, map, txt.
  • 5 MB maximum per file, 50 files maximum per upload.
  • Each uploaded file appears with its public URL, a button to copy the URL and a cross to delete it.
Manifest editor of the com.sweescape.subsol-seatmap extension (name “Plan de salle Subsol”, version 1.1.0, scopes ui:render, ticket:read and participant:write), the Upload the UI file(s) area, two files seatmap.html and seatmap-1.1.0.html with their URL and a copy button, Cancel and Save buttons

A minimal manifest that displays a block on the ticketing page:

{
"id": "com.subsol.seatmap",
"apiVersion": 1,
"version": "1.0.0",
"name": "SUBSOL seating plan",
"description": "Pick your seat before buying.",
"scopes": ["ui:render", "ticket:read"],
"contributes": {
"uiExtensions": [
{
"surface": "page.block",
"entry": "https://…/copied-file-url",
"sandbox": { "allowedDomains": [] },
"descriptor": {
"name": "SeatMap",
"category": "media",
"description": "Seating plan",
"fields": {
"title": { "type": "text", "description": "Block title" },
"ticket": { "type": "event_ticket", "description": "Ticket sold" }
},
"defaultProps": { "title": "Pick your seat", "ticket": "" }
}
}
]
}
}
Key Role
id Same as the package name.
apiVersion Version of the extension contract. Only 1 is accepted.
version Your extension’s version in semver format (1.2.0).
name, description Required.
scopes The declared permissions.
contributes What the extension adds: resourceFields, blocks, uiExtensions, rules.
configSchema Optional: settings described at the extension level.

The author field is filled in automatically with your account name: no need to write it.

A permission is written resource:action. Resources are event, ticket, participant, order, payment, ticket_code, audience, campaign, automation, contact, invitation, invoice, analytics, ticket_page, badge. Actions are read, write, create, act, subscribe. Two special permissions complete the list: ui:render and net:fetch.

Each contribution requires its permission, otherwise saving fails:

Contribution Required permission
A block (blocks) or an interface (uiExtensions) ui:render
An interface with allowedDomains net:fetch
A participant column (resourceFields) participant:write
A rule triggered by order.created (for example) order:subscribe
An adjust_price, reject or assign_ticket action order:act
A webhook action net:fetch
A set_field action on a resource resource:write

An interface’s surface says where it shows. Today:

  • checkout.confirmation shows on the confirmation page, after a successful payment;
  • all other surfaces (page.block, checkout.step…) appear as a block, under the extension’s name, in the last category of the page editor, currently labelled OTHER.

There are two kinds of blocks:

  • blocks reuses an existing page editor block, named by baseComponent (for example Card), with your default values in descriptor.defaultProps. No third-party code runs; the settings are those of the original block.
  • uiExtensions displays your own interface (the file given in entry).

For an interface, the fields of the descriptor become the block settings in the page editor. Each field’s description is used as its label. Recognized types:

Type Setting displayed
text (and any unknown type) Text field.
textarea Text area.
number Number field.
boolean Yes / No choice.
color Color picker.
select, radio List of the declared options.
array List of items whose sub-fields are described in arrayFields.
event_ticket List of the event’s tickets. The value is the ticket id.

The values entered by the organizer are passed to your interface at startup (see below). defaultProps gives the default values.

resourceFields adds columns to the event’s attendees, which your interface fills in:

"resourceFields": [
{
"resource": "participant",
"column": { "name": "seat", "type": "text", "required": true, "source": "ui", "unique": true }
}
]
  • name: lower case, digits and _, starting with a letter. firstname, lastname and email are reserved.
  • type: text, number, date, boolean or select (with options).
  • source: "ui": the value comes from your interface, never from the checkout form.
  • unique: true: the value can only belong to one attendee of the event (a seat, a time slot). Sweescape refuses an order whose value is already taken or held by a cart in progress.

These columns show in the attendee list as long as the extension is active on the event.

Your interface runs in an iframe with sandbox="allow-scripts" on an isolated origin. It receives no token and talks to the page only through postMessage.

Message sent by the iframe Effect
{ type: "sweescape:ready" } Asks to start. The page answers sweescape:init with config (the block settings) and context.
{ type: "sweescape:resize", height } Adjusts the iframe height, in pixels.
{ type: "sweescape:set-field", field, value } Saves a participant column value for the current purchase.
{ type: "sweescape:checkout", ticketId, fields } Opens the purchase window on this ticket, quantity 1, with these column values.
{ type: "sweescape:checkout", items: [ { ticketId, quantity, units } ] } Opens the purchase window on several tickets. units gives the column values of each ticket.
{ type: "sweescape:request", requestId, method, params } Calls a page method, which answers { type: "sweescape:response", requestId, ok, data } or error.

Add closeOnBack: true to a sweescape:checkout message so that the purchase window’s back button closes it instead of showing the ticket selection.

Methods available with sweescape:request:

Method Returns
context.get The event (id, name, startDate, endDate, status, type, taxRate), the tickets on sale (id, title, price before tax, stock, minQuantity, maxQuantity) and the extension’s columns.
column.takenValues With params: { column }: the list of values already taken in one of your unique columns.
participant.current The column values already entered for the current purchase.
ticketCode.unlock With params: { code }: applies an access code and returns the unlocked tickets and the remaining quota.
order.current On the checkout.confirmation surface only: id, total, currency and ticketCount of the paid order.

rules describes logic without code, evaluated by Sweescape. A rule has an id, a label, a trigger event on (order.created, order.confirmed, participant.created…), branches evaluated in order (the first one whose when condition is true applies) and an optional else.

Possible actions:

  • reject: refuses the order with a message, before anything is written;
  • adjust_price: proposes a price adjustment, which Sweescape recalculates and clamps between bounds.minCents and bounds.maxCents;
  • set_field: writes a value in one of your extension’s columns;
  • assign_ticket: chooses the ticket assigned to the attendee;
  • webhook: sends a POST to an https URL, with only your columns and non-personal order fields (order_id, event_id, participant_id, ticket_id, total_amount, currency, status).

Rules are validated when the manifest is saved: a rule without the <resource>:subscribe permission of its event, or an action without its permission, is refused.

Click Save. The message “Extension saved” confirms the validation. Otherwise:

Message Cause
“The manifest is not valid JSON” JSON syntax error (extra comma, missing quote).
“The manifest is invalid” A key is missing or has a refused value: malformed id, non-semver version, unknown surface or type, reserved column…
“The manifest uses a capability it doesn’t declare in “scopes”” Add the permission required by a contribution.
“The manifest “id” must match the package name” The id differs from the package name entered at creation.
“This package name is already taken” At creation: choose another package name.
  1. Open one of your events, Extensions tab, and click Activate next to your extension. It is listed even if it is not published, as soon as its manifest is saved.

  2. Open the page editor, drag the block from the last category of the list (OTHER) and fill in its settings.

  3. Check the result with the editor’s Preview button, then on the published page.

To edit the extension, click the pencil icon next to it in My extensions: the Edit extension window reopens the manifest and the files. The new manifest applies as soon as it is saved, on every event where the extension is active.

  • Status. A new extension shows the Private badge: only you can see it. Publishing on the marketplace (badge Published) is done by the Sweescape team; the Publish button does not appear for other accounts.
  • Delete. The trash icon deletes the extension and its files, with no confirmation. If it is still active on events, the Cannot delete extension window lists them: deactivate it on each one first.