Changelog
Every contract-visible change, newest first. Deprecations additionally go to each key's integration contact by email — see the handbook for the policy.
Pre-release. The API below is implemented and under test but not yet
generally available to members. Entries describe the v1 surface as it is being built;
the GA announcement will appear here.
2026-11-12 — v1 development: metadata endpoints and the error catalogue
- Added
GET /v1/meta/status— per-caller status: yourkey_id,environment(live|test),api_version,server_time, resolvedprovider_ids,scopes, and arate_limitblock mirroring the response headers. PlusGET /v1/meta/scopes— every scope with a description — andGET /v1/meta/schemas, the OpenAPI 3.0 Schema Object for each public resource (OpenAPI 3.0 Schema Objects, not standard JSON Schema) for dynamic UI generation. Authentication only; no extra scope. - Added
RateLimit-Limit,RateLimit-RemainingandRateLimit-Reseton every rate-limited response; a429additionally carriesRetry-After.GET /v1/meta/statusreports the same budget in its body, so headers and body never disagree. - Added the error catalogue at /errors/ — every RFC 9457
typeURL resolves to a page documenting the status and its machinecode. Machine codes:bad_request,unauthorized,forbidden,not_found,conflict,precondition_failed,unprocessable,rate_limited,internal_error, plusclient_error— the fallback for any other4xxnot individually listed.
2026-11-09 — v1 development: price types and items
- Added
GET /v1/price-typesandGET /v1/price-types/{id}— the pricing templates your key's providers use, scoped through the provider → price-type link. Cursor-paginated;filter[status]=active|inactive; sort byid,titleorcreated_at.expand=itemsinlines the items asembeds.items.data. Scopebilling:read. - Added
GET /v1/price-types/{id}/items— the price items on the type for your providers:code,amount,currency(ISO 4217, never an id),price_item_type,threshold,threshold_type,price_instance_status,created_at,updated_at. This is the list an ERP mapping needs to turn the price item codes a provider bills with into GL accounts. Returned complete — this collection is not paginated. - Note a price type shared by several providers returns only the items
priced by your key's providers; another provider's items on the same type are never
visible. Items on inactive price instances are included and tagged
price_instance_status: inactive, so filter them out if you only bill active prices.
2026-09-22 — v1 development: the project-plan use cases
Built from the member use cases collected in the Public API project plan (asset sync, chatbot directory, ELN linkage, directory sync, proposal-form projects, door access, usage entries). Every change is additive. Preview spec bumped to preview-v13; contracts proposal v10.
- Added
GET /v1/usersandGET /v1/users/{id}— users of the organizations your key's providers trust, withfilter[email](andfilter[email][in]),organization_id,is_disabled,is_verified. This is the lookup a directory sync needs beforePOST /v1/groups/{id}/members: it turns an institutional identity into theuser_idthe write takes. Never carries credentials. Scopeusers:read. - Added
GET /v1/providers,…/{id}— your key's facilities: name, contacts, location, usage policy, timezone, currency. AndGET /v1/resource-types,…/{id}— the types in use by your providers' resources plus their parents (parent_id), so everyresource_type_idresolves. Scoperesources:read. - Added
POST /v1/resources— provision a resource stub from asset-management master data; created offline and invisible to users (status: inactive), configured and switched on in the admin UI.external_referenceis the mapping key (unique per provider, 409 on duplicate);resource_type_idis required. AndPOST /v1/resources/{id}/transitions{ "to": "archived" }— ends bookability and hides the resource on disposal; 409 while future bookings exist; repeatable. New scoperesources:write. Resources gainexternal_reference,archived_atandfilter[resource_type_id]. Built from member feedback (forum, Aug 2026). - Note resource
statusis derived:archivedwhen archived through the API,inactivewhen the resource is offline or unconfigured,activeotherwise. OpenIRIS itself never reads the stored status column, so the API reports the flags that actually govern bookability. - Added
GET /v1/bookingsandGET /v1/bookings/{id}— bookings on your providers' resources. Filter onresource_id,provider_id,user_id,group_id,project_id,request_id,status,kind,external_reference,start,end,created_at,updated_at; sort byid,start,end,created_at. Scopebookings:read. - Note booking
statusnow has five values:confirmed,pending_approval,rejected,cancelled,completed. A rejected booking is neither confirmed nor cancelled and was missing from the earlier derivation. - Added
GET /v1/resources/{id}/current-booking?user_id=…&at=…— the door-access answer: does the user hold a valid booking on the resource at that instant (default now), personally or through a group they are an active member of? Always 200 for a visible resource withaccess,via(user|group) and the booking in the body. Scopebookings:read. - Added
POST /v1/bookingswith"kind": "usage"— record a completed measurement as a usage entry: a booking entirely in the past, no prior reservation, the same row an admin creates by hand. 409 on overlap with an existing booking (never a delete); the user must exist and, withgroup_id, be an active member. New scopebookings:write. Reservations in advance ("kind": "booking") return 422 in this version. - Note usage entries are created without charges for now: the pricing engine lives on the internal side of the API and has not yet been shared with the public host. An admin editing the entry in OpenIRIS triggers the usual recalculation.
- Added
PATCH /v1/bookings/{id}forexternal_referenceandcomments— the ELN round-trip.If-Matchrequired; an emptyexternal_referenceclears it. Bookings gainkind,provider_id,parent_booking_id,is_cancelled,cancelled_at. - Added
GET /v1/projects,…/{id},…/{id}/membersandPOST /v1/projects— create a project from an external proposal form with members given by email. Emails that match no visible user come back inunmatched_emails; accounts are never created.organization_idmay be omitted whengroup_idis given.external_referenceis unique within the organization. PlusPOST …/{id}/membersandDELETE …/{id}/members/{user_id}, idempotent. New scopeprojects:write. Built from member feedback (forum, Aug 2026). - Added
charge.cost_center— the cost-center assignment a charge bills to, resolved from its booking or request:provider_code(the SAP WBS / ERP posting code),provider_name,provider_cost_center_id, and anygroup_code,organization_code,user_code. Null when nothing is assigned. Plusfilter[cost_center.provider_code](eq, in). This is the field a per-cost-center split or a journal posting was missing. Built from member feedback (forum, Aug–Sep 2026). - Changed (preview spec) charge batches removed — superseded by charge
confirmation on 2026-09-14.
/v1/chargesgainsfilter[updated_at]in the preview and the ERP guidance now points atfilter[confirmed]=true, notstatus=invoiced./v1/invoicesis parked: confirmation plus export acknowledgements cover the workflow that asked for it. - Decided SCIM does not terminate at OpenIRIS in v1. Identity provisioning belongs at Auth0 (inbound SCIM on enterprise connections); OpenIRIS provides the email lookup and the membership writes.
2026-09-14 — v1 development: requests and the people on them
- Added
GET /v1/requestsandGET /v1/requests/{id}— service requests (what most facilities call projects) belonging to your key's providers. Cursor-paginated; filter onstatus,provider_id,service_id,user_id,group_id,project_id,alt_idandcreated_at; sort byid,nameorcreated_at. Scoperequests:read. Read-only for now — create, transition and the notes/milestones/products sub-collections follow. Built from member feedback (forum, Sep 2026). - Added
GET /v1/requests/{id}/participants— everyone on a request: the owner (role: owner, always first) and the people on its Participants tab, each withemail, name andorganization_idso a directory or IAM sync can map rows to accounts without a second lookup. Replaces scraping the Participants tab. - Note the owner is returned whether or not a participant row also exists for them. Only about 30% of requests that have participants carry one for their own owner, so this collection — not a raw membership list — is the complete answer to "who can reach this project?".
- Note request access follows the participant link existing,
not its
status. Take the whole collection rather than filtering tostatus: approved; rejecting a participant deletes the row outright.statusisnullfor an owner with no participant row and for a small number of rows that predate the field. - Changed (preview spec)
request.statusnow lists the seven states OpenIRIS actually stores —pending,active,rejected,closed,inactive,reviewed,discontinued. The earlier preview guessed atdraft|active|completed|rejected; no implementation ever served those values.request.provider_idadded. - Note training requests are stored separately and are not part
of
/v1/requests, so there is nofilter[type]yet.
2026-09-14 — v1 development: charge confirmation
- Added
charge.confirmed_at— when a billing admin signed the charge off as checked and ready to bill, ornull. Set it withPUT /v1/charges/{id}/confirmation, clear it withDELETEon the same path, and set it on up to 500 charges at once withPOST /v1/charges/confirmations. New scopebilling:write. Built from member feedback (forum, Aug–Sep 2026). - Added
filter[confirmed]=true|falseandfilter[confirmed_at][gte|gt|lt|lte]. Your ready-to-bill queue isfilter[status]=unbilled&filter[confirmed]=true; pollfilter[confirmed_at][gte]for what has been signed off since your last pull. - Note confirmation is not a
statusvalue.statusholds one value at a time, so aconfirmedmember would disappear the moment the charge was invoiced.confirmed_atis its own field and survives invoicing and export — it stays the audit answer to "was this signed off, and when?". - Fixed
filter[updated_at]on/v1/chargesreturned 500 for every operator. It now works and excludes charges whoseupdated_atis null.
2026-09-01 — v1 development: exports, durable idempotency, per-key limits
- Added
POST/GET /v1/charges/{id}/exports— ERP export acknowledgements (the dedup fence). Chargestatusgainsexported, includingfilter[status]=exported. - Added
GET /v1/openapi.json— the generated specification, publicly served in every environment. - Idempotency-Key replay is now durable across service restarts.
- Per-key rate-limit raises are now possible (see the handbook).
- Preview spec v9: live surfaces are now marked IMPLEMENTED;
corrected
resource.classto the real domain values (scheduled | application | service | scheduled_addon | event).
2026-09-01 — v1 development: write surfaces
- Added cost-center writes:
POST /v1/cost-centers,PATCH /v1/cost-centers/{id}(inactivation;If-Matchrequired) andfilter[code]. New scopecost-centers:write. Built from member feedback (forum, Aug 2026). - Added group-member administration:
POST /v1/groups/{id}/members,DELETE /v1/groups/{id}/members/{user_id}. New scopegroups:write. Users are never auto-created. Built from member feedback (forum, Jul 2026). - Added
Idempotency-Keyrequirement on all POST/PATCH requests, with byte-identical replay.
2026-09-01 — v1 development: read surfaces
- Added
GET /v1/resourcesandGET /v1/resources/{id}— provider-scoped resource directory. - Added
GET /v1/charges,…/{id},…/{id}/line-items— the primary ERP surface over booking and request charges. (Product-order charges follow in a later increment.) - Added collection conventions everywhere: envelope, cursor
pagination (forward-only in v1),
filter[field][op]with per-field safelists, multi-key sort, RFC 9457 errors withcode+trace_id, ETag/If-None-Match on single reads.
2026-08 — preview v8: first feedback-driven revision
- All five member suggestions on the feedback forum addressed: cost-center writes and group-member writes committed to v1; project creation and resource provisioning proposed for v1.1; charge batches (period-close vetting) opened as a design proposal.
- Invoice model corrected: an invoice may span many cost centers.
- Four provisioning scopes added, kept separate from end-user scopes.
2026-04 — preview v7: contract proposal published
- Full proposed surface (98 paths) published for member review at
api-preview.openiris.iowith the feedback forum attached.