Drupal is a registered trademark of Dries Buytaert
Release: Leaflet 10.4.11 Minor update available for module leaflet (10.4.11). Release: Session Inspector 1.0.8 Minor update available for module session_inspector (1.0.8). Release: Migrate QA 2.0.4 Minor update available for module migrate_qa (2.0.4). Release: CKEditor Description List 3.0.0 Major update available for module ckeditor_descriptionlist (3.0.0). Release: FlowDrop 2.4.0 Minor update available for module flowdrop (2.4.0). Release: JWT Token Refresh 1.0.4 Minor update available for module jwt_token_refresh (1.0.4). Release: ConReg 1.0.0-beta1 First beta version released for module conreg (1.0.0-beta1). Release: AI Image Studio 1.0.0-beta8 New beta version released for module ai_image_studio (1.0.0-beta8). Usage Milestone: Role Theme Switcher Module role_theme_switcher crossed 1,000 active installs. Module Revived: Decoupled Router 2.0.7 Module decoupled_router updated after 11 months of inactivity (2.0.7).

Yoyaku is a resource booking system that prevents overbooking by safely managing capacity, even with simultaneous requests. It allows you to define bookable resources, publish available time slots, and manage bookings, with optional modules for UI, calendar views, webform integration, ordering, and payments.

Yoyaku is a lightweight, concurrency-safe resource booking and availability API for Drupal. It gives any module a small set of entities and a service API to define bookable resources, publish availability slots, and take bookings without ever overbooking, even under concurrent requests.

It models everything from a single room booked by the hour to a ticketed venue with numbered seats, without changing the core: every axis of variation lives behind a named seam with a shipped default.

Why Yoyaku

Most booking solutions decide availability by counting rows, which races under load and double-books the last place. Yoyaku treats capacity as a first-class, concurrency-safe concern: every hold checks and reserves capacity atomically inside a database transaction with a row lock on the slot, so two simultaneous requests can never overbook. Holds carry a time-to-live and expire automatically, releasing capacity when a reservation is abandoned.

Performance

A booking opening is the one moment a booking site is judged on. A party is seated under the very lock that takes its seats, so nobody is offered a seat another booker is already taking, and a booker is refused only once the house is genuinely gone. What a hold holds does not grow with the hall: a stadium of 80,000 seats in eighty parts sells at the rate of one arena of 8,000, whether its bookers pick seats themselves or take a part of the house and are seated inside it. The harness that measures this ships with the module.

Core concepts

  • Resource: a bookable item (room, equipment, production) with a default capacity and a booking window.
  • Slot: a concrete time window, with an optional slot-wide capacity cap.
  • Tariff: what a resource offers a booking at, with its own quota and price.
  • Slot tariff: one session's departure from a tariff, for a different quota, price or allotment on that date alone.
  • Tariff class: the audience a tariff is offered under (Adult, Child, Subscriber).
  • Allotment: a named slice of a session's capacity that given tariffs draw from. Twenty places held for the schools, or the front row held by name.
  • Booking: capacity consumption, following a held-to-confirmed lifecycle.
  • Tenant: the realm rows belong to; a multi-tenant install keeps them isolated.

Features

  • Bookable rules: constraint plugins enforced at hold time, plus constraint policies attached and configured per resource, resource type or booking channel.
  • Tariffs: tariff classes, per-session overrides, and presets that let a grid of tariffs and allocations be typed once and stamped onto every production that runs it.
  • Allotments: hold part of a session's capacity under a name, released on a deadline or held until somebody takes it.
  • Numbered and pooled places: a venue map, places held by name for an allotment, seating a party together, and booking units for what a place means in a given hall.
  • Booking channels: which surface may offer what, resolved from the domain being served.
  • Booking fees: what a front charges on top of what the booking costs, computed by plugins a channel attaches and sums, so the same place can carry a fee online and none at the counter.
  • Built for a rush: the calendar and the seat map answer thousands of simultaneous visitors from one calculation, while every hold still re-checks capacity under the slot lock.
  • Cart and checkout: one basket across surfaces, and a booker who abandons checkout is returned to where they left off.
  • Payments: payment-gated confirmation and a guarantee lifecycle.
  • Cancellation: self-service, with deadline and refund policies.
  • Tickets and check-in: PDF tickets with QR codes, and scanning at the door.
  • Recurrence: generate a season's slots from a rule.
  • Lifecycle workflow: via Orchestra integration.
  • Multi-tenancy and delegated administration.
  • Built to extend: lifecycle events and hooks throughout.
  • Translated: a French interface translation is included.

What is included

The core module is headless and dependency-free (nothing beyond Drupal core). Presentation, ticketing, workflow and payment live in optional submodules you enable as needed:

  • Yoyaku UI: admin screens for resources, slots, categories and bookings, with generation and bulk tools.
  • Yoyaku Calendar: a public calendar element to pick a slot and place a booking, as a block or field formatter.
  • Yoyaku Placement: venues, sections, place grades, numbered or pooled places, and the graphical place map.
  • Yoyaku Cart: the cross-surface basket and checkout.
  • Yoyaku Node: bind a bookable resource to a node and show its calendar on the node.
  • Yoyaku Webform: use a Webform as the booking form step.
  • Yoyaku Order: group the bookings of one submission into a persistent order, and attach constraint policies.
  • Yoyaku Payment: guarantees, refunds and payment-gated confirmation, over a Kessai gateway.
  • Yoyaku Booking Fee: what a front charges on top of what the booking costs, configured per booking channel. Ships under Yoyaku Payment; a site that never charges one never enables it.
  • Yoyaku Ticket: PDF tickets with a QR code, and the check-in screen that scans them.
  • Yoyaku Orchestra: drive the full booking lifecycle as an Orchestra workflow.
  • Yoyaku Manager: scoped administration by resource, resource type or tenant.
  • Yoyaku Domain: resolve the booking tenant from the domain being served.
  • Yoyaku Views: expose bookings, resources, slots, orders and payments to Views.
  • Yoyaku API: a transport-agnostic client contract, with an in-process implementation.

Requirements

  • Drupal 11.3 or newer
  • PHP 8.3 or newer
  • MySQL or MariaDB, not SQLite. Not overbooking is the whole promise, and what keeps it is a row lock: a hold reads what a session has already taken with SELECT ... FOR UPDATE, so a second request waits for the first to commit instead of reading a stale answer beside it. Drupal's SQLite driver drops that clause silently, which leaves the locking read an ordinary read and the guarantee unenforced: the site looks like it works and hands two bookers the same seat under a rush. PostgreSQL implements the clause and should work, though the project has not been run against it.
  • The booking, calendar, placement, cart and order features stand on their own. Payments require Kessai, the lifecycle workflow requires Orchestra, and domain-based tenancy requires Domain.
  • PDF tickets additionally need two Composer libraries: composer require dompdf/dompdf endroid/qr-code.

Documentation

Full documentation, covering the concepts, a no-code getting-started guide, the calendar, placement, tickets, check-in, constraints, allotments, booking fees, multi-tenancy and the API reference, is published at project.pages.drupalcode.org/yoyaku.

Project status

Yoyaku is under active development and has not yet reached a stable release. Interfaces may still change before a 1.0 release, and no database update hooks are provided between pre-releases, so moving between pre-releases means reinstalling rather than upgrading in place. Issues and merge requests are welcome.

Activity

Tracked releases
3
Tracked since
Jul 2026
Latest release
3 weeks ago
Releases (12 mo)
3 ▲ from 0
Maintenance
Active

Release Timeline

Releases

Version Type Release date
1.0.0-alpha2 Pre-release Jul 30, 2026
1.0.0-alpha1 Pre-release Jul 12, 2026
1.x-dev Dev Jul 8, 2026