ibexa/rest
Adds a REST remote API to Ibexa DXP and Ibexa Open Source, letting applications manage content, users, and repositories over HTTP. Useful for building integrations, headless frontends, and third-party clients against Ibexa.
ibexa/rest is not a client SDK — it is the server-side bundle that exposes the REST API of an Ibexa DXP / Ibexa OSS installation. Day-to-day, a developer either (a) consumes the API from an external app (middleware, SPA, mobile, ERP sync), or (b) extends the API surface for a project. The bundle itself is almost always already installed by ibexa/oss / ibexa/dxp, so "installation" is really a question of verifying it is wired up and reachable.
Minimal steps:
composer show ibexa/rest
php bin/console debug:router | grep ibexa.rest
The canonical base path is /api/ibexa/v2/. If you see nothing, the bundle is not enabled in config/bundles.php or the firewall is missing (ibexa.rest firewall, reworked onto Symfony's authenticator system in 5.0).https://ezsystems.github.io/ezplatform-rest-reference/) before the source. It is a generated, per-endpoint reference with example request files; the bundle README only points there.# 1. create a session
curl -i -X POST https://example.com/api/ibexa/v2/user/sessions \
-H "Content-Type: application/vnd.ibexa.api.SessionInput+json" \
-H "Accept: application/vnd.ibexa.api.Session+json" \
-d '{"SessionInput":{"login":"admin","password":"publish"}}'
# capture the session cookie AND the X-CSRF-Token response header
# 2. read content
curl -i https://example.com/api/ibexa/v2/content/objects/1 \
-H "Accept: application/vnd.ibexa.api.ContentInfo+json" \
-b "IBX_SESSIONID=..."
Server/Router/Resources/config/routing* for the route table, Server/Controller for endpoint behaviour, Server/Output/ValueObjectVisitor for response shapes, and Server/Input/Parser (+ Criterion, SortClause processors) for request shapes. Those four directories answer 90% of "why does my payload look like this" questions.Realistic first-day scope: session handling + content read + a View (search) query. Creating/publishing content, locations, users/roles and trash operations is a second pass, because each has its own media type and response-code contract.
Session lifecycle is the core pattern. Ibexa REST is cookie/session based, not stateless. A sane integration:
X-CSRF-Token header value.X-CSRF-Token on every unsafe method (POST/PATCH/PUT/DELETE); its absence is one of the most common 401/403 causes.GET /api/ibexa/v2/user/sessions/current (new in 5.0) lets you probe a session cheaply instead of guessing. Note ibexa.rest.refresh_session is deprecated in favour of ibexa.rest.check_session, and 5.0.8 stopped reusing the auth token after logout — always discard cached credentials on logout.X-Expected-User (5.0+) so a mismatch fails loudly instead of silently writing as the wrong user.Always pin the vendor media type. Requests and responses use versioned media types, not plain JSON:
Accept: application/vnd.ibexa.api.Content+json
Content-Type: application/vnd.ibexa.api.ContentUpdate+json
Appending +json selects the JSON visitor; the XML visitor is the historical default in several endpoints. Build a thin client wrapper that sets Accept/Content-Type per operation so callers never hand-write these strings. The supported_media_types flag (5.0.1 / 4.6.23) allows finer media-type granulation — useful if you need to distinguish client generations on the same route.
Content write workflow. The everyday sequence is: create draft → (optionally update draft) → publish, or create with publish folded in. The idiomatic endpoints, and the ones that were explicitly reworked to be OpenAPI-compatible in 5.0 (create draft from current version / from version, publish content version, publish content type, publish role, move/copy/swap location, trash/restore), should be preferred — they have cleaner, spec-matching status codes than the legacy ones. For bulk imports, expect per-item round trips; there is no batch endpoint. Pipeline it, and be aware publishing triggers workflows and URL alias regeneration, so throughput is bound by the domain, not HTTP.
Search via Views. Queries go through POST /api/ibexa/v2/views with a ViewInput containing identifier, public, and a ContentQuery with Criteria, SortClauses, limit, offset. Criterion and sort-clause names come from the input parsers registered in the bundle (ContentTypeIdentifier, FullText, ContentName, ContentTypeGroupName, Image, FileSize, IsBookmarked, …). Two things worth knowing:
dataKey (5.0) lets you identify a sort clause from the request, which is the supported way to map inbound sort names to domain sort clauses instead of matching on class name.Extending the API. For project-specific endpoints:
Ibexa\Rest\Server\Controller, register as a service, keep the vendor media-type convention so clients use one negotiation path.ValueObjectVisitor tagged ibexa.rest.output.value_object.visitor.ibexa.rest.input.parser (the RequestParser interface and its implementations are deprecated since 5.0 — do not build new code on them).BaseCriterionProcessor / BaseSortClauseProcessor rather than writing a parser from scratch; this is the intended extension seam introduced in 5.0.Integration tip: inside the same PHP application, do not call your own REST API. Use the public API repositories (ContentService, LocationService, SearchService). REST is a boundary for remote consumers, and looping through HTTP inside the app doubles latency and adds auth/CSRF failure modes for no benefit.
Content-Type: application/json gives you 415; Accept: application/json gives you 406 or an XML body you didn't expect. Diagnose with curl -i and read the Accept-Post/error payload, which usually names the supported types.X-CSRF-Token. Session auth without the token produces failures that look like permission problems. Log the token alongside the cookie, and treat both as one credential.var/log for the underlying exception. X-Debug-Token in the response will point you at the profiler entry when kernel.debug is on.x-ibexa-example-file header convention (5.0.7) used by the reference example request files when exercising uploads.ENCODER_CONTEXT leaked into nested objects until 5.0.4 — if you are on an older patch, strip it client-side before persisting API responses into your own store.redirectCurrentVersionRelations could loop infinitely before 5.0.1 / 4.6.22. If a client hangs on relation redirects, check your patch level first.ibexa.rest firewall with authenticator-manager security (5.0). Project security config that "just works" for the site front end (custom user checkers, SSO listeners) will not automatically apply to API requests — re-verify against /api/ibexa/v2/user/sessions.X-CSRF-Token header makes preflight mandatory.Vary on Cookie/Accept and a clear story for the session cookie.NOASSERTION in metadata. If you are redistributing or building a product on top, get the actual license text from Ibexa rather than trusting the repo metadata — and note the GPL branch is what you get without a DXP subscription.BaseCriterionProcessor, BaseSortClauseProcessor, tagged visitors/parsers) over monkey-patching controllers, so future 5.x upgrades stay cheap.How can I help you explore Laravel packages today?