Skip to content

TicketMap SDK

The TicketMap SDK lets you sell tickets for your AnyBiz events directly on your own website. It renders an interactive seat map (pan, zoom, seat selection), keeps availability in sync, and hands the visitor off to the hosted payment page — all from a single script tag.

The widget mounts inside a Shadow DOM, so your site’s CSS cannot break the map and the map’s styles never leak into your page. The only global it exposes is window.TicketMap.

Before you can integrate, your organization needs SDK access configured in the AnyBiz app under Settings → SDK:

  • Site key — a publishable key (e.g. sdk_pub_...) that identifies your organization. It is safe to include in public HTML.
  • Allowed origins — the list of website origins (e.g. https://www.example.com) permitted to use the key. An empty list allows any origin; set it in production.
  • Return URL — the page on your website where visitors land after payment (see Checkout return flow).

You will also need:

  • The SDK script (ticketmap.min.js) — the URL is provided together with your site key.
  • The API base URL: https://api.anybiz.rs/api/events/sdk. Always pass it explicitly — if omitted, the SDK assumes the API lives on your own origin.

A minimal embed: authenticate with your site key, mount the map, and check out the visitor’s selection.

<div id="ticket-map"></div>
<button id="checkoutBtn" disabled>Checkout</button>
<script src="https://<sdk-host>/ticketmap.min.js"></script>
<script>
(async () => {
const API_BASE = 'https://api.anybiz.rs/api/events/sdk';
// 1. Exchange your publishable site key for a short-lived auth token
const auth = await TicketMap.authenticate({
siteKey: 'sdk_pub_your_key',
apiBaseUrl: API_BASE,
});
// 2. Mount the seat map for one event display
const sdk = await TicketMap.init({
container: '#ticket-map',
apiBaseUrl: API_BASE,
eventId: 'evt_123',
displayId: 'disp_456',
authToken: auth.authToken,
lang: 'en',
onSelectionChange: (selection) => {
const btn = document.getElementById('checkoutBtn');
btn.disabled = selection.items.length === 0;
btn.textContent = selection.items.length
? `Checkout (${selection.items.length}) — ${selection.total} ${selection.currency ?? ''}`
: 'Checkout';
},
onError: (error) => console.error('TicketMap:', error.message),
});
// 3. Reserve the selected seats and redirect to the payment page
document.getElementById('checkoutBtn').addEventListener('click', () => {
sdk.checkout({
customerEmail: 'buyer@example.com', // recommended: ticket delivery + payment receipt
});
});
})();
</script>

checkout() reserves the selected seats, creates a checkout session, and redirects the browser to the hosted payment page. When payment completes, the visitor is sent back to your configured return URL.

If you don’t want to hard-code eventId/displayId, list them with the same auth token:

const events = await TicketMap.listEvents({ authToken, apiBaseUrl: API_BASE });
// [{ id, name, description, archived, createdAt, updatedAt }, ...]
const displays = await TicketMap.listDisplays({
authToken,
eventId: events[0].id,
apiBaseUrl: API_BASE,
});
// [{ id, eventId, startTime, status: 'draft' | 'active' | 'closed', salesStartTime, salesEndTime, ... }, ...]

Only displays with seat sales open can be sold through the SDK; use status and the sales window fields to decide what to show.

The SDK is local-selection first: tapping a seat only changes the visual selection in the browser. Nothing is reserved on the server until you call hold() or checkout().

Two integration styles:

  • One-shot — the visitor picks seats, then your Checkout button calls sdk.checkout(). The SDK reserves the seats and immediately redirects to payment. Simplest, and enough for most sites.
  • Staged cart — call sdk.hold() to reserve the current selection on the server (default hold: 10 minutes) without paying. The visitor can keep adding seats and calling hold() again; each call merges new reservation ids into the cart. A later sdk.checkout() pays for all held reservations (and clears the cart). Use releaseHeldReservation(id) to give a hold back.

Seat colors reflect live availability: available (gray), selected (blue), held by this visitor (orange), reserved by someone else (red), sold (dark gray). Availability refreshes automatically every 10 seconds unless you disable polling.

Required:

OptionTypeDescription
containerstring | HTMLElementCSS selector or element where the widget mounts.
eventIdstringAnyBiz event id.
displayIdstringDisplay id belonging to that event.
authTokenstringToken from TicketMap.authenticate({ siteKey }).

Optional:

OptionTypeDefaultDescription
apiBaseUrlstringcurrent origin + /api/events/sdkAlways set to https://api.anybiz.rs/api/events/sdk.
lang'en' | 'sr''en'Language of built-in UI texts.
labelsPartial<SdkLabels>—Override individual UI strings (status texts, legend, error messages).
holdMinutesnumber10Server hold duration used by hold() / one-shot checkout().
pollMsnumber10000Availability polling interval in milliseconds.
autoPollAvailabilitybooleantrueSet false to disable polling and call refreshAvailability() yourself.
customerName / customerEmail / customerPhonestring—Default buyer details sent with checkout (a checkout() call can override them).
promoCodestring | null—Default promo code applied at checkout.
reservationHolderName / reservationHolderEmail / reservationHolderPhonestring—Optional holder details stored on seat holds made by hold().

Callbacks:

CallbackFires
onSeatClick(detail)Only when the visitor taps a seat. detail is { seatId, action: 'select' | 'deselect', seat, selection }.
onSelectionChange(selection)After every availability sync — initial load, polling, and seat taps. Receives a selection snapshot.
onSeatSelect(selection)Same payload and timing as onSelectionChange (kept for compatibility; use either).
onCheckoutStart(checkoutId)When a checkout session is created, before the payment redirect.
onCheckoutResult(status)With the initial checkout status returned by the API.
onError(error)On any SDK error (failed request, invalid selection, …).

Drive your cart UI from onSelectionChange; use onSeatClick when you need tap-only behavior — for example calling sdk.hold() immediately on each tap.

onSelectionChange / onSeatSelect / getSelectionSnapshot() provide:

{
seatIds: string[];
items: Array<{
seatId: string;
sectionId: string;
sectionTitle: string | null;
seatRow: string;
seatNumber: string;
effectivePrice: string; // decimal string, e.g. "1200.00"
currency: string;
availability: 'available' | 'reserved' | 'sold';
reservationId: string | null; // reservation group id when the seat is held
heldByMe: boolean; // true when held by this visitor's session
reservedUntil: string | null; // ISO hold expiry
}>;
total: string; // sum of effectivePrice, e.g. "3600.00"
currency: string | null;
}

TicketMap.init() resolves to an instance with:

MethodDescription
checkout(options?)If holds exist: pays for the held reservations. Otherwise: reserves the current selection, then redirects to payment. options can override customerName, customerEmail, customerPhone, promoCode per call.
hold(options?)Reserves the current selection on the server and adds the reservation ids to the cart. Returns all held ids. options can override holdMinutes and holder details.
releaseHeldReservation(id)Releases one held reservation group.
getHeldReservationIds()Reservation ids currently in the cart.
refreshAvailability()Reloads seat availability on demand.
getSelectionSnapshot() / getSelectedItems()Current selection (snapshot / items only).
zoomIn(step?) / zoomOut(step?) / fitToScreen()Map controls, e.g. for your own toolbar buttons.
destroy()Unmounts the widget and stops polling. Call before re-initializing in the same container.

Payment happens on the hosted payment page (MSU), not on your site:

  1. checkout() redirects the browser to the payment page.
  2. After payment, the gateway calls the AnyBiz API, which verifies the transaction and finalizes the checkout (tickets are issued on success).
  3. The API then redirects the visitor to the Return URL from your SDK settings — for successful, declined, and cancelled payments alike — appending the result as query parameters:
    • responseCode — gateway response code (00 = approved, 99 = declined)
    • responseMsg — human-readable gateway message
    • merchantPaymentId — payment reference
    • checkoutId — the checkout session id
    • msuAccepted — 1 when the callback was matched and processed, 0 otherwise; this is not a payment-success flag — read responseCode for the outcome

The same parameters are also duplicated in the URL fragment (after #), as a fallback for intermediaries that strip query strings.

Build a payment-result page at that URL that reads the parameters and shows success or failure. Payment verification has already happened server-side by the time the visitor arrives — the parameters are for display, not for deciding whether to hand over goods.

To re-check a result from the browser (for example if the visitor refreshes the page), call POST /checkout/status with the SDK session token and checkoutId; it returns the verified status: created, pending, paid, failed, or cancelled.

  • TicketMap.authenticate({ siteKey }) exchanges the publishable site key for an auth token valid for 30 minutes. The request’s browser origin must be in your key’s allowed-origins list.
  • TicketMap.init() exchanges the auth token for a per-visitor session token, also valid for 30 minutes, scoped to one event display.
  • On expiry, requests fail with an error surfaced through onError — re-run authenticate() and init() to recover. For long-lived pages, re-authenticate before calling init() again rather than caching tokens across visits.

Built-in texts (status line, legend, hints, error messages) ship in English (lang: 'en') and Serbian (lang: 'sr'). Any string can be overridden:

await TicketMap.init({
// ...
lang: 'sr',
labels: {
statusReady: 'Izaberite svoja mesta',
errorSelectAtLeastOneSeat: 'Prvo izaberite mesto na mapi',
},
});

The SDK is a thin client over the public SDK endpoint family under https://api.anybiz.rs/api/events/sdk. All are POST with JSON bodies:

EndpointPurpose
/authExchange site key for an auth token.
/events, /displaysList sellable events / displays.
/sessionCreate a per-visitor session for one display.
/initLoad the seat map payload.
/availabilityLive seat availability.
/reserve, /releaseHold / release seat reservations (ids are reservation group ids).
/checkoutCreate a checkout session and payment redirect URL.
/checkout/statusVerified payment status for a checkout.

Request and response schemas for each endpoint are in the API Reference sidebar — you only need them if you are building a custom client instead of using the SDK.

Calling the API directly (without the SDK)

Section titled “Calling the API directly (without the SDK)”

For server-side integrations — syncing events into your CMS, rendering your own event list — call the same endpoints over plain HTTP. Authentication is a site-key exchange; no user account, API key header, or cookie is involved.

1. Exchange the site key for an auth token:

Terminal window
curl -X POST https://api.anybiz.rs/api/events/sdk/auth \
-H "Content-Type: application/json" \
-d '{"siteKey":"sdk_pub_your_key","origin":"https://www.example.com"}'
{ "authToken": "eyJqdGkiOi...", "expiresAt": "2026-09-14T12:30:00.000Z" }

The origin rules follow your key’s allowed-origins list: if the list is empty, any origin passes and you may omit the field; if the list is set, you must send one of the listed origins or the request fails with 403. Browsers send their own origin automatically via the SDK.

2. List events with the token:

Terminal window
curl -X POST https://api.anybiz.rs/api/events/sdk/events \
-H "Content-Type: application/json" \
-d '{"authToken":"<token-from-step-1>"}'
[
{
"id": "evt_123",
"name": "Summer Concert",
"description": null,
"archived": false,
"createdAt": "2026-06-01T10:00:00.000Z",
"updatedAt": "2026-06-10T09:00:00.000Z"
}
]

3. List displays for an event:

Terminal window
curl -X POST https://api.anybiz.rs/api/events/sdk/displays \
-H "Content-Type: application/json" \
-d '{"authToken":"<token>","eventId":"evt_123"}'

The auth token expires after 30 minutes — re-run step 1 when you get an expiry error instead of caching the token long-term.

The remaining endpoints (/session, /init, /availability, /reserve, /checkout) require a per-visitor session token scoped to one event display and are designed to be driven by the SDK in the buyer’s browser. If you are building a fully custom checkout client, follow the schemas in the API Reference.

  • TicketMap request failed (403) on authenticate — your page’s origin is not in the site key’s allowed-origins list, or the key is wrong.
  • Map renders but every seat is red/gray — seats are reserved or sold, or the display’s sales window is closed. Check the display’s salesStartTime/salesEndTime and status.
  • Select at least one seat before checkout — checkout() was called with no selection and no held reservations.
  • Nothing appears in the container — the container element must exist before init() runs, and must have a width; the map sizes itself to the container.