ReferenceReference by module

Resources API

Every Resources action (7) and data model (3): endpoints, scopes, input, preconditions, events and examples.

Rooms, pitches, cars, chairs and equipment people book — by the hour or by the day.

Module code resources · 7 actions · 3 data models · 7 events. A key or token never does more here than the person behind it can; row-level security applies exactly as in the app. Scopes: resources (everything), resources:read (read only) or resources:<capability>.

Resources

ResourceTableList and readPOSTPATCHDELETE
resource_bookingsresource_booking/api/v1/resource_bookingsresources.book
resource_servicesresource_service/api/v1/resource_services
resourcesresource/api/v1/resourcesresources.createresources.updateresources.archive

Lists take limit (up to 200), cursor, order (e.g. -created_at), fields and q; every other query parameter is a column filter: ?status=paid, ?total[gte]=100, ?id[in]=a,b, ?x=null.

Actions

ActionNeedsWhat it does
resources.archiveresources:manageArchive
resources.bookresources:writeBook a resource
resources.book_weeklyresources:writeHold every week
resources.cancel_bookingresources:writeCancel booking
resources.createresources:manageAdd a resource
resources.set_servicesresources:manageSet the services that need it
resources.updateresources:manageEdit a resource

resources.archive

Archive — Stops new bookings. Existing ones stay as they are.

Needs resources:manage · reaches outside (sends, publishes or charges) · asks a person to confirm when Era runs it

POSThttps://app.getera.io/api/v1/resources/{id}/actions/archive
API key or OAuth token · resources:manage
  • REST alias: DELETE /api/v1/resources/{id}
  • Canonical address: POST /api/v1/actions/resources.archive

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Resource · id of resource

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
resource_not_foundThe resource must exist.
resource_archivedIt must not be archived already.

Events it publishes: resources.archived

What it writes: resource (update) — Stamps archived_at

curl -X POST https://app.getera.io/api/v1/resources/RESOURCE_ID/actions/archive \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "resources.archived"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.resources.archive("RESOURCE_ID")
era resources archive RESOURCE_ID
tools/call
{
  "name": "era__resources__archive",
  "arguments": {
    "id": "RESOURCE_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold resources:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 resource_not_found, resource_archived · 429 slow down

resources.book

Book a resource — An hour on a pitch or nine nights in a room — refused when it is already full then.

Needs resources:write · changes data

POSThttps://app.getera.io/api/v1/resource_bookings/actions/book
API key or OAuth token · resources:write
  • REST alias: POST /api/v1/resource_bookings
  • Canonical address: POST /api/v1/actions/resources.book

Input

FieldTypeRequiredNotes
resourceIduuidyesResource · id of resource
startsAtstringyesFrom (local, YYYY-MM-DDTHH:mm) · max 16
endsAtstringyesUntil (local, YYYY-MM-DDTHH:mm) · max 16
customerIduuidCustomer · id of customer
appointmentIduuidAppointment (the staff half)
notestringNote · max 2000

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
resource_not_foundThe resource must exist.
resource_archivedAn archived resource takes no bookings.
customer_not_foundThe customer must exist.
appointment_not_foundA linked appointment must exist.
resource_booking_range_invalidA booking ends after it starts.
resource_fullFewer than capacity bookings may overlap it.

Events it publishes: resources.booked

What it writes: resource_booking (insert) — Books it

curl -X POST https://app.getera.io/api/v1/resource_bookings/actions/book \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"resourceId":"RESOURCE_ID","startsAt":"From (local, YYYY-MM-DDTHH:mm)","endsAt":"Until (local, YYYY-MM-DDTHH:mm)"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "resources.booked"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.resourceBookings.create({
  resourceId: "RESOURCE_ID",
  startsAt: "From (local, YYYY-MM-DDTHH:mm)",
  endsAt: "Until (local, YYYY-MM-DDTHH:mm)"
})
era resource_bookings create \
  --resource-id "RESOURCE_ID" \
  --starts-at "From (local, YYYY-MM-DDTHH:mm)" \
  --ends-at "Until (local, YYYY-MM-DDTHH:mm)"
tools/call
{
  "name": "era__resources__book",
  "arguments": {
    "resourceId": "RESOURCE_ID",
    "startsAt": "From (local, YYYY-MM-DDTHH:mm)",
    "endsAt": "Until (local, YYYY-MM-DDTHH:mm)"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold resources:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 resource_not_found, resource_archived, customer_not_found, appointment_not_found, resource_booking_range_invalid, resource_full · 429 slow down

resources.book_weekly

Hold every week — The same weekday and time each week until the subscription’s period ends — all weeks or none.

Needs resources:write · changes data

POSThttps://app.getera.io/api/v1/resource_bookings/actions/book_weekly
API key or OAuth token · resources:write
  • Canonical address: POST /api/v1/actions/resources.book_weekly

Input

FieldTypeRequiredNotes
resourceIduuidyesResource · id of resource
subscriptionIduuidyesSubscription · id of subscription
startsAtstringyesFirst week from (local) · max 16
endsAtstringyesFirst week until (local) · max 16
notestringNote · max 2000

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
resource_not_foundThe resource must exist.
resource_archivedAn archived resource takes no bookings.
subscription_not_liveThe subscription must be running.
resource_booking_range_invalidA booking ends after it starts, inside the period.
resource_fullEvery week must have room.

Events it publishes: resources.series_booked

What it writes: resource_booking (insert) — Books every week of the period

curl -X POST https://app.getera.io/api/v1/resource_bookings/actions/book_weekly \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"resourceId":"RESOURCE_ID","subscriptionId":"SUBSCRIPTION_ID","startsAt":"First week from (local)","endsAt":"First week until (local)"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "resources.series_booked"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.resourceBookings.bookWeekly({
  resourceId: "RESOURCE_ID",
  subscriptionId: "SUBSCRIPTION_ID",
  startsAt: "First week from (local)",
  endsAt: "First week until (local)"
})
era resource_bookings book_weekly \
  --resource-id "RESOURCE_ID" \
  --subscription-id "SUBSCRIPTION_ID" \
  --starts-at "First week from (local)" \
  --ends-at "First week until (local)"
tools/call
{
  "name": "era__resources__book_weekly",
  "arguments": {
    "resourceId": "RESOURCE_ID",
    "subscriptionId": "SUBSCRIPTION_ID",
    "startsAt": "First week from (local)",
    "endsAt": "First week until (local)"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold resources:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 resource_not_found, resource_archived, subscription_not_live, resource_booking_range_invalid, resource_full · 429 slow down

resources.cancel_booking

Cancel booking — Frees the time. For a weekly series, optionally every week still to come.

Needs resources:write · removes or cannot be undone · asks a person to confirm when Era runs it

POSThttps://app.getera.io/api/v1/resource_bookings/{id}/actions/cancel_booking
API key or OAuth token · resources:write
  • Canonical address: POST /api/v1/actions/resources.cancel_booking

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Booking · id of resource_booking
reasonstringReason · max 500
wholeSeriesbooleanEvery week still to come

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
resource_booking_not_foundThe booking must exist.
resource_booking_cancelledIt must not be cancelled already.

Events it publishes: resources.booking_cancelled

What it writes: resource_booking (update) — Marks it cancelled

curl -X POST https://app.getera.io/api/v1/resource_bookings/RESOURCE_BOOKING_ID/actions/cancel_booking \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"reason":"Reason"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "resources.booking_cancelled"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.resourceBookings.cancelBooking("RESOURCE_BOOKING_ID", {
  reason: "Reason"
})
era resource_bookings cancel_booking RESOURCE_BOOKING_ID \
  --reason "Reason"
tools/call
{
  "name": "era__resources__cancel_booking",
  "arguments": {
    "id": "RESOURCE_BOOKING_ID",
    "reason": "Reason"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold resources:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 resource_booking_not_found, resource_booking_cancelled · 429 slow down

resources.create

Add a resource — A room, pitch, car, chair or piece of equipment people book.

Needs resources:manage · changes data

POSThttps://app.getera.io/api/v1/resources/actions/create
API key or OAuth token · resources:manage
  • REST alias: POST /api/v1/resources
  • Canonical address: POST /api/v1/actions/resources.create

Input

FieldTypeRequiredNotes
namestringyesName · max 120
kindstring (enum)Kind · Allowed values: room, pitch, vehicle, chair, equipment, other
capacitynumberBookings at once · min 1 · max 1000
opensAtstringOpens · max 5
closesAtstringCloses · max 5
slotMinutesnumberBooked per (minutes; 1440 = by the day) · min 5 · max 1440
colorstringColour · max 20
descriptionstringDescription · max 2000

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
resource_name_takenTwo resources in use do not share a name.
resource_hours_invalidOpening hours are HH:mm and close after they open.

Events it publishes: resources.created

What it writes: resource (insert) — Adds the resource

curl -X POST https://app.getera.io/api/v1/resources/actions/create \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"name":"Name"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "resources.created"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.resources.create({
  name: "Name"
})
era resources create \
  --name "Name"
tools/call
{
  "name": "era__resources__create",
  "arguments": {
    "name": "Name"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold resources:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 resource_name_taken, resource_hours_invalid · 429 slow down

resources.set_services

Set the services that need it — The services booked with this resource. The booking wizard asks for a free one when such a service is booked.

Needs resources:manage · changes data

POSThttps://app.getera.io/api/v1/resource_services/actions/set_services
API key or OAuth token · resources:manage
  • Canonical address: POST /api/v1/actions/resources.set_services

Input

FieldTypeRequiredNotes
iduuidyesResource · id of resource
itemIdsstringServices · Comma-separated service ids. Empty unties it from every service. · max 4000

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
resource_not_foundThe resource must exist.
resource_archivedAn archived resource is not tied to services.
item_not_foundEvery service must exist.

Events it publishes: resources.services_changed

What it writes: resource_service (upsert) — Replaces the list of services that need it

curl -X POST https://app.getera.io/api/v1/resource_services/actions/set_services \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"id":"RESOURCE_ID"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "resources.services_changed"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.resourceServices.setServices({
  id: "RESOURCE_ID"
})
era resource_services set_services \
  --id "RESOURCE_ID"
tools/call
{
  "name": "era__resources__set_services",
  "arguments": {
    "id": "RESOURCE_ID"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold resources:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 resource_not_found, resource_archived, item_not_found · 429 slow down

resources.update

Edit a resource — Name, kind, capacity, hours and slot length. Existing bookings stand.

Needs resources:manage · changes data

POSThttps://app.getera.io/api/v1/resources/{id}/actions/update
API key or OAuth token · resources:manage
  • REST alias: PATCH /api/v1/resources/{id}
  • Canonical address: POST /api/v1/actions/resources.update

Input

FieldTypeRequiredNotes
iduuidyesFilled from the path {id} · Resource · id of resource
namestringName · max 120
kindstring (enum)Kind · Allowed values: room, pitch, vehicle, chair, equipment, other
capacitynumberBookings at once · min 1 · max 1000
opensAtstringOpens · max 5
closesAtstringCloses · max 5
slotMinutesnumberBooked per (minutes; 1440 = by the day) · min 5 · max 1440
colorstringColour · max 20
descriptionstringDescription · max 2000

Preconditions

The action is refused with 409 and one of these codes:

CodeRefused when
resource_not_foundThe resource must exist.
resource_archivedAn archived resource is not edited.
resource_name_takenTwo resources in use do not share a name.
resource_hours_invalidOpening hours are HH:mm and close after they open.

Events it publishes: resources.updated

What it writes: resource (update) — Updates the resource

curl -X POST https://app.getera.io/api/v1/resources/RESOURCE_ID/actions/update \
  -H "Authorization: Bearer $ERA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"name":"Name"}'
Response
{
  "ok": true,
  "result": "…",
  "events": [
    "resources.updated"
  ]
}
import { createEra } from "@getera/sdk"

const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.resources.update("RESOURCE_ID", {
  name: "Name"
})
era resources update RESOURCE_ID \
  --name "Name"
tools/call
{
  "name": "era__resources__update",
  "arguments": {
    "id": "RESOURCE_ID",
    "name": "Name"
  }
}

Errors: 401 no or expired credential · 403 the credential does not hold resources:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 resource_not_found, resource_archived, resource_name_taken, resource_hours_invalid · 429 slow down

Data models

ResourceBooking

Table resource_booking · Resource resource_bookings

  • GET /api/v1/resource_bookings
  • GET /api/v1/resource_bookings/{id}
  • POST /api/v1/resource_bookings → resources.book
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
resource_idstring (uuid) · uuidresource
customer_idstring (uuid) · uuidyescustomer
appointment_idstring (uuid) · uuidyes
subscription_idstring (uuid) · uuidyessubscription
series_idstring (uuid) · uuidyes
starts_atstring (date-time) · timestamptz
ends_atstring (date-time) · timestamptz
statusstring · textbooked, cancelled
notestring · textyes
cancelled_atstring (date-time) · timestamptzyes
cancel_reasonstring · textyes
created_bystring (uuid) · uuidyesapp_user
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz

Primary key: id

Checks:

  • CHECK ((ends_at > starts_at))

ResourceService

Table resource_service · Resource resource_services

  • GET /api/v1/resource_services
  • GET /api/v1/resource_services/{id}
ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
resource_idstring (uuid) · uuidresource
item_idstring (uuid) · uuiditem
created_atstring (date-time) · timestamptz

Primary key: id

Unique: resource_id, item_id

Resource

Table resource · Resource resources

ColumnTypeNullableAllowed valuesReferences
idstring (uuid) · uuid
organization_idstring (uuid) · uuidorganization
workspace_idstring (uuid) · uuidworkspace
namestring · text
kindstring · textroom, pitch, vehicle, chair, equipment, other
capacityinteger · int4
opens_atstring (time) · time
closes_atstring (time) · time
slot_minutesinteger · int4
colorstring · textyes
descriptionstring · textyes
archived_atstring (date-time) · timestamptzyes
created_bystring (uuid) · uuidyesapp_user
created_atstring (date-time) · timestamptz
updated_atstring (date-time) · timestamptz
is_publicboolean · boolyes

Primary key: id

Checks:

  • CHECK (((capacity >= 1) AND (capacity <= 1000)))
  • CHECK (((slot_minutes = 1440) OR (closes_at > opens_at)))
  • CHECK ((length(TRIM(BOTH FROM name)) > 0))
  • CHECK (((slot_minutes >= 5) AND (slot_minutes <= 1440)))

Events

Workflows and webhooks react to these events.

EventWhat happensPayload
resources.archivedA resource was archived.id
resources.bookedA resource was booked.id, resourceId, customerId, appointmentId, startsAt, endsAt
resources.booking_cancelledA resource booking was cancelled.id, resourceId, count
resources.createdA resource was added.id, name, kind, capacity
resources.series_bookedA resource was held every week for a subscription.id, resourceId, subscriptionId, customerId, weeks, until
resources.services_changedThe services that need a resource changed.id, itemIds
resources.updatedA resource changed.id
Was this page helpful?