TypeScript Types
The @qariyb/js package includes full TypeScript definitions. Import types directly from the package.
import type { QariybEvent, Order, Cart } from '@qariyb/js';
API Response Types
QariybEvent
Event data returned from the API.
interface QariybEvent {
/** ULID (26-char alphanumeric) */
id: string;
title: string;
slug: string;
/** Summary (max 200 chars) or truncated description */
summary: string | null;
/** Full HTML description */
description: string | null;
pricing_model: PricingModel;
/** 3-letter ISO 4217 code, uppercase. Never null — free events fall back. */
currency: string;
/** YYYY-MM-DD */
start_date: string | null;
/** HH:MM:SS */
start_time: string | null;
end_date: string | null;
end_time: string | null;
/** IANA identifier, e.g. 'Europe/London'. Defaults to 'UTC'. */
timezone: string;
/** Full ISO 8601 datetime in UTC */
start_datetime_utc: string | null;
end_datetime_utc: string | null;
is_online: boolean;
virtual_platform: string | null;
address: EventAddress | null;
has_tickets: boolean;
requires_registration: boolean;
requires_approval: boolean;
registration_open: boolean;
is_sold_out: boolean;
category: EventCategory | null;
organization: EventOrganization | null;
cover_image: EventCoverImage;
/** Only ticket types that are active and currently available */
ticket_types: TicketType[];
features: EventFeature[];
/** Full URL to the event's public discovery page */
public_url: string;
}
type PricingModel = 'free' | 'paid' | 'external';
The public event payload is deliberately narrow. It carries no internal database IDs, no organizer contact details, no exact venue coordinates, and no draft-state fields — a publishable key is exposed in the browser, so the response only contains what is safe to publish.
Custom questions are not on the event. They arrive from
CheckoutInitResponse.custom_questions, because they depend on the checkout
being initialised.
EventAddress
interface EventAddress {
venue_name: string | null;
city: string | null;
state: string | null;
country: string | null;
/** Venue, city, state, country joined with ', ' — empty parts dropped */
display_address: string;
}
Street lines, postal code and coordinates are withheld from the public API for
privacy. Use display_address for rendering; if you need to plot a map, link
out to event.public_url.
EventCategory
interface EventCategory {
name: string;
slug: string;
}
EventOrganization
interface EventOrganization {
name: string;
slug: string;
/** Logo URL, or null */
logo: string | null;
is_verified: boolean;
}
EventCoverImage
interface EventCoverImage {
url: string;
alt_text: string;
}
TicketType
interface TicketType {
/** ULID */
id: string;
name: string;
description: string | null;
/** Price in minor units (e.g. cents/pence) */
price_cents: number;
currency: string;
/**
* Units a buyer can actually purchase right now. Already excludes stock held
* in other shoppers' live carts, so it can be lower than physical remaining
* inventory.
*
* Null when the ticket type is uncapped: that means "no limit", not "none
* left". Do not render null as a count and do not read it as sold out —
* only max_per_order bounds an uncapped type.
*/
quantity_available: number | null;
/** Defaults to 10 when the organizer sets no cap */
max_per_order: number;
/** Defaults to 1 */
min_per_order: number;
/** True when price_cents is 0 */
is_free: boolean;
}
Only ticket types that are active and currently on sale are returned, so
there is no is_available flag and no sale-window fields — an unavailable
ticket type is simply absent from the array.
EventFeature
interface EventFeature {
name: string;
slug: string;
category: string | null;
}
EventAvailabilityResponse
Response from GET /v1/public/events/{ulid}/availability. Only available and
reason are guaranteed. The rest are populated only on success paths and
omitted when reason is 'event_not_found' or 'event_not_available'.
interface EventAvailabilityResponse {
available: boolean;
reason: 'event_not_found' | 'event_not_available' | 'sold_out' | 'registration_closed' | null;
event_id?: string;
registration_open?: boolean;
has_tickets?: boolean;
is_sold_out?: boolean;
total_tickets_available?: number;
}
OrganizationEventsResponse
Response from GET /v1/public/organizations/{ulid}/events. Flat array of
events using the same shape as QariybEvent.
type OrganizationEventsResponse = QariybEvent[];
Checkout Types
CheckoutInitResponse
Response from the checkout initialize endpoint.
interface CheckoutInitResponse {
cart_id: string;
/** null for free events, which have no payment to make */
stripe: StripeCredentials | null;
amount: number;
/** 3-letter ISO 4217 currency code, uppercase (e.g. 'USD'). */
currency: string;
is_free_event: boolean;
custom_questions: CustomQuestion[];
expires_at: string;
/** Phone field display mode resolved from event registration settings. */
phone_field_type: 'required' | 'optional' | 'off';
}
StripeCredentials
interface StripeCredentials {
/** Stripe publishable key (pk_live_…) */
publishable_key: string;
/** PaymentIntent client secret (pi_…_secret_…) */
client_secret: string;
/** Connected account the PaymentIntent lives on, or null */
connected_account_id: string | null;
}
When connected_account_id is non-null the organizer is on Stripe Standard and
the PaymentIntent lives on their connected account, not the platform. You
must initialise Stripe.js as loadStripe(publishable_key, { stripeAccount })
— the intent is invisible to the platform account, so confirming without it
fails with a 404 after the buyer has already entered their card.
It is null for destination charges, where the intent is on the platform.
CheckoutConfirmResponse
Response from the checkout confirm endpoint.
interface CheckoutConfirmResponse {
order: Order;
tickets: OrderTicket[];
requires_approval: boolean;
}
Order
interface Order {
/** ULID — the stable key, not the reference a buyer quotes */
id: string;
/** Human-readable order number, e.g. 'ORD2026HTP9PWGC'. Show this one. */
number: string;
status: OrderStatus;
/** Ticket total before any discount, in minor units */
subtotal: number;
/** Amount taken off by a discount code, in minor units; 0 when none */
discount_amount: number;
total: number;
/** 3-letter ISO 4217 currency code, uppercase (e.g. 'USD'). */
currency: string;
billing_name: string;
billing_email: string;
requires_approval: boolean;
/** ISO 8601 datetime the order was placed */
created_at: string;
}
type OrderStatus =
| 'pending'
| 'completed'
| 'cancelled'
| 'refunded'
| 'failed'
| 'refund_pending';
OrderTicket
interface OrderTicket {
id: string;
/** Human-readable ticket number, e.g. 'TKZHHQ6RD8E4VQ' */
number: string;
ticket_type: string;
status: TicketStatus;
attendee_name: string | null;
}
type TicketStatus =
| 'purchased'
| 'used'
| 'cancelled'
| 'refunded'
| 'transferred'
| 'pending_approval';
CustomQuestion
interface CustomQuestion {
id: string;
question: string;
type: CustomQuestionType;
required: boolean;
/** Options for select/checkbox/radio; null for text */
options: string[] | null;
display_order: number;
}
type CustomQuestionType = 'text' | 'select' | 'checkbox' | 'radio';
ApplyDiscountRequest
Request body for the discount endpoint.
interface ApplyDiscountRequest {
/** Cart ULID from checkout initialize */
cart_id: string;
/** The code the buyer typed */
code: string;
/** Stripe PaymentIntent id — see paymentIntentIdFromSecret() */
payment_intent_id: string;
}
DiscountApplication
A discount that has been applied to the checkout's PaymentIntent. The server has
already repriced the intent when this resolves, so new_total is what the card
will actually be charged.
interface DiscountApplication {
/** Canonical code as stored — may differ in case from what was typed */
code: string;
discount_type: DiscountType;
/** Readable form of discount_type: 'percentage' or 'fixed_amount' */
discount_type_name: string;
/** Whole percentage points when type is 2, minor units when type is 1 */
discount_value: number;
/** Display-ready value, e.g. '20%' or '£5.00' */
formatted_value: string;
/** Amount taken off, in minor units */
discount_amount: number;
/** New charge amount, in minor units */
new_total: number;
currency: string;
}
/** 1 = fixed amount, 2 = percentage */
type DiscountType = 1 | 2;
export const DISCOUNT_TYPE_FIXED_AMOUNT = 1;
export const DISCOUNT_TYPE_PERCENTAGE = 2;
discount_type arrives as a number, not a word — the API's DiscountType
enum is int-backed and serialises by value. Prefer formatted_value for
display; it is already localised and carries the currency symbol or per-cent
sign.
EventTicketsResponse
Response from GET /v1/public/events/{ulid}/tickets.
interface EventTicketsResponse {
event_id: string;
currency: string;
ticket_types: TicketType[];
registration_open: boolean;
is_sold_out: boolean;
}
OrganizationEventsPage
A page of organization events together with the window it came from. Returned by
QariybApiClient.getOrganizationEventsPage().
interface OrganizationEventsPage {
events: QariybEvent[];
/** Total matching events, or null when the header is unreadable */
total: number | null;
/** Echoed window, or null when the headers are unreadable */
limit: number | null;
offset: number | null;
}
total, limit and offset are read from the X-Total-Count, X-Limit and
X-Offset response headers, not the body. A cross-origin caller can only read
them if the API lists them in Access-Control-Expose-Headers. Treat null as
unknown, not as zero.
ValidationErrors
/** Field name → list of error messages */
type ValidationErrors = Record<string, string[]>;
RSVP Types
RsvpRegistration
Response body from the RSVP endpoint. This shape is documented for direct API
callers — @qariyb/js does not export it as a type, because the SDK's
components do not drive RSVP.
interface RsvpRegistration {
registration: {
id: string;
status: 'confirmed' | 'pending_approval';
name: string;
email: string;
requires_approval: boolean;
};
}
Cart Types
Cart
interface Cart {
items: CartItem[];
totalCents: number;
totalQuantity: number;
currency: string;
}
CartItem
interface CartItem {
ticketTypeId: string;
ticketTypeName: string;
quantity: number;
priceCents: number;
currency: string;
}
Configuration Types
QariybConfig
interface QariybConfig {
// API Configuration
publishableKey?: string;
apiBaseUrl?: string;
debug?: boolean;
// Layer 1: Theme Preset
theme?: ThemePreset;
// Layer 2: Variable Overrides
variables?: ThemeVariables | ThemeVariableOverrides;
// Layer 3: Component Rules
rules?: ComponentRules;
// Feature Flags
features?: FeatureFlags;
// Internationalization
locale?: string;
labels?: Partial<Labels>;
}
ThemePreset
type ThemePreset = 'light' | 'dark' | 'flat' | 'minimal';
ThemeVariableOverrides
interface ThemeVariableOverrides {
colorPrimary?: string;
colorPrimaryText?: string;
colorBackground?: string;
colorBackgroundSecondary?: string;
colorText?: string;
colorTextSecondary?: string;
colorSuccess?: string;
colorError?: string;
colorWarning?: string;
colorBorder?: string;
colorIcon?: string;
fontFamily?: string;
borderRadius?: string;
buttonHeight?: string;
inputHeight?: string;
spacingUnit?: string;
}
FeatureFlags
interface FeatureFlags {
showBranding?: boolean; // Default: true
showPaymentIcons?: boolean; // Default: true
showSecurityBadge?: boolean; // Default: true
skeletonLoading?: boolean; // Default: true
}
ComponentRules
interface ComponentRules {
'.Container'?: CSSProperties;
'.Section'?: CSSProperties;
'.Button'?: CSSProperties;
'.Button--primary'?: CSSProperties;
'.Button--secondary'?: CSSProperties;
'.Input'?: CSSProperties;
'.Label'?: CSSProperties;
'.TicketRow'?: CSSProperties;
'.TicketRow--selected'?: CSSProperties;
'.QuantityControl'?: CSSProperties;
'.OrderSummary'?: CSSProperties;
'.Modal'?: CSSProperties;
'.EventCard'?: CSSProperties;
// ... and more
[key: string]: CSSProperties | undefined;
}
Component State Types
CheckoutStep
type CheckoutStep =
| 'loading'
| 'tickets'
| 'details'
| 'payment'
| 'processing'
| 'success'
| 'error';
CheckoutState
interface CheckoutState {
step: CheckoutStep;
event: QariybEvent | null;
cart: Cart;
cartId: string | null;
clientSecret: string | null;
publishableKey: string | null;
/** Connected account the PaymentIntent lives on (direct charges), or null */
connectedAccountId: string | null;
customQuestions: CustomQuestion[];
order: Order | null;
tickets: OrderTicket[];
error: string | null;
requiresApproval: boolean;
/** Field-level validation errors from the server */
fieldErrors: ValidationErrors;
/** Whether a form submission is in progress */
isSubmitting: boolean;
/** Typed contact details, kept across re-renders so the form is not cleared */
contactDetails: { name: string; email: string; phone: string };
/** Phone field display mode from checkout initialize */
phoneFieldType: 'required' | 'optional' | 'off';
/** Discount code currently entered by the user */
discountCode: string;
/**
* Discount the server has applied to the PaymentIntent, or null. Non-null
* means the card will be charged `appliedDiscount.new_total` rather than
* `cart.totalCents`.
*/
appliedDiscount: DiscountApplication | null;
/** Message from the last rejected discount attempt */
discountError: string | null;
/** Whether a discount request is in flight */
isApplyingDiscount: boolean;
}
Event Detail Types
QariybEventDetail
Base detail interface for all events.
interface QariybEventDetail<T = unknown> {
timestamp: number; // Unix timestamp
component: string; // 'checkout', 'tickets', 'button', etc.
action: string; // 'success', 'error', 'ready', etc.
data: T; // Event-specific payload
}
QariybCustomEvent
Type for CustomEvent with proper detail typing.
type QariybCustomEvent<T = unknown> = CustomEvent<QariybEventDetail<T>>;
Checkout Event Details
interface CheckoutReadyDetail {
eventId: string;
}
interface CheckoutEventLoadedDetail {
event: QariybEvent;
}
interface CheckoutEventErrorDetail {
error: string;
eventId: string;
}
interface CheckoutStepChangedDetail {
from: CheckoutStep;
to: CheckoutStep;
eventId: string;
}
interface CheckoutCartUpdatedDetail {
cart: Cart;
action: 'add' | 'remove' | 'clear';
ticketId?: string;
ticketName?: string;
}
interface CheckoutDetailsSubmittedDetail {
email: string;
name: string;
phone?: string;
}
interface CheckoutPaymentStartedDetail {
cartId: string;
amount: number;
currency: string;
}
interface CheckoutPaymentProcessingDetail {
paymentIntentId?: string;
}
interface CheckoutSuccessDetail {
order: Order;
tickets: OrderTicket[];
requiresApproval: boolean;
}
interface CheckoutDiscountAppliedDetail {
discount: DiscountApplication;
/** Total before the discount, in minor units */
previousTotal: number;
}
interface CheckoutDiscountFailedDetail {
code: string;
/** Human-readable reason from the server */
error: string;
}
interface CheckoutErrorDetail {
error: string;
code?: string;
step?: CheckoutStep;
}
interface CheckoutValidationErrorDetail {
errors: ValidationErrors;
step: CheckoutStep;
}
Tickets Event Details
interface TicketsReadyDetail {
eventId: string;
}
interface TicketsLoadedDetail {
tickets: TicketType[];
event: QariybEvent;
}
interface TicketsQuantityChangedDetail {
ticketId: string;
ticketName: string;
quantity: number;
previousQuantity: number;
price: number;
currency: string;
}
interface TicketsSelectedDetail {
cart: Cart;
eventId: string;
}
interface TicketsErrorDetail {
error: string;
eventId: string;
}
Button Event Details
interface ButtonReadyDetail {
eventId: string;
}
interface ButtonModalOpenedDetail {
eventId: string;
}
interface ButtonModalClosedDetail {
eventId: string;
reason: 'success' | 'cancel' | 'escape' | 'overlay';
}
Card Event Details
interface CardReadyDetail {
eventId: string;
}
interface CardLoadedDetail {
event: QariybEvent;
}
interface CardClickedDetail {
event: QariybEvent;
action: 'view' | 'tickets';
}
interface CardErrorDetail {
error: string;
eventId: string;
}
List Event Details
interface ListReadyDetail {
organizationId: string;
}
interface ListLoadedDetail {
events: QariybEvent[];
total: number;
hasMore: boolean;
}
interface ListErrorDetail {
error: string;
organizationId: string;
}
Importing Types
// API types
import type {
QariybEvent,
TicketType,
EventAddress,
EventCategory,
EventOrganization,
EventFeature,
Order,
OrderTicket,
CustomQuestion,
} from '@qariyb/js';
// RSVP types
import type { RsvpRegistration } from '@qariyb/js';
// Cart types
import type { Cart, CartItem } from '@qariyb/js';
// Config types
import type {
QariybConfig,
ThemePreset,
ThemeVariableOverrides,
FeatureFlags,
ComponentRules,
} from '@qariyb/js';
// State types
import type { CheckoutStep, CheckoutState } from '@qariyb/js';
// Event types
import type {
QariybEventDetail,
QariybCustomEvent,
CheckoutSuccessDetail,
CheckoutErrorDetail,
TicketsSelectedDetail,
// ... etc.
} from '@qariyb/js';