Lockii
Lockii
  • Docs
  • Changelog
  • Feature requests
  • Support portal
    • User MCP
    • Login with Lockii
    • Customer MCP
    • Lockii REST API
    • Booking API
Docs / API & MCP

Lockii REST API

Programmatic access to bookings, customers, inventory, and operations via the Lockii REST API.

Base URL

https://dash.lockii.app/api/v1

Authentication

Create an API key in Settings → Integrations → API.

For apps looking to integrate with Lockii you can request a client ID for use in an OAuth based integration

Method

Example

Header

x-api-key: your_api_key

Bearer token

Authorization: Bearer your_api_key

Query string

?api_key=your_api_key


Conventions

IDs

Lockii uses prefixed IDs. Generate new IDs with a UUID v7 suffix:

Resource

Format

Example

Booking

order_<uuid>

order_01923abc-...

Customer

customer_<uuid>

customer_01923abc-...

ect

ect_<uuid>

ect_Xxxxxxx-...

Timestamps & money

  • All date/time fields are Unix milliseconds (UTC) unless noted otherwise.

  • All prices and amounts are in cents (e.g. $50.00 = 5000).

GET request parameters

GET endpoints accept parameters as query strings. Nested objects and arrays can be passed as JSON strings:

GET /booking?status=active&dateRange={"from":1711270800000,"to":1711357200000}

Bookings

Search bookings

GET /booking

Returns a filtered list of bookings with customer, location, company, and order line details.

Query parameters:

Parameter

Type

Default

Description

limit

number

15

Maximum results to return

status

string

all

all, active, upcoming, returned, or cancelled

orderBy

string

number

Sort field: createdAt, number, startHireDate, endHireDate, priceInCents

dateRange

object

—

Hire window overlap filter: { "from": number, "to": number } (Unix ms)

createdAtRange

object

—

Created-at filter: { "from": number, "to": number }

totalRange

object

—

Price filter in whole dollars: { "min": number, "max": number }

productID

string

—

Filter to bookings containing this product

stockID

string

—

Filter to bookings containing this stock row

categoryID

string

—

Filter to bookings with products in this category

locationID

string

—

Filter to bookings at this location

minEndHireDate

number

—

Bookings ending on or after this Unix ms timestamp

paymentStatuses

array

—

["paid"], ["unpaid"], or both

Example:

GET /booking?status=active&limit=10&locationID=location_abc123

Response: Array of booking objects, each including related customer, location, company, and orderLines (with product and stock).

Get booking

GET /booking/:id

Returns the full booking page query — the same data shown in the booking editor.

Path parameter: id — booking/order ID

Response includes: customer, location, stock, company, payments, coupon, services, changeRequests, orderLines (with product, reservation, stock), reservations, messages, hireQuizResponses, activityLogs.

Example:

GET /booking/order_abc123
Create change request

POST /booking/change-request

Create and apply a booking change. Evaluates policy, pricing, and availability. For paid changes, Lockii attempts to charge the customer's saved card first and falls back to emailing a payment link.

Body:

{
  "order_id": "order_abc123",
  "data": {
    "startHireDate": 1711270800000,
    "endHireDate": 1711357200000,
    "locationID": "location_xyz",
    "lineItems": [
      { "productID": "product_abc", "quantity": 2 }
    ],
    "status": "cancelled"
  },
  "approval_mode": "charge_and_apply",
  "cancellation_refund_percent": 100
}

Field

Type

Required

Description

order_id

string

Yes

Internal booking ID

data

object

Yes

Requested changes — only include fields you want to change

data.startHireDate

number

No

New start time (Unix ms)

data.endHireDate

number

No

New end time (Unix ms)

data.locationID

string

No

New pickup/return location

data.lineItems

array

No

Replacement line items: { productID, quantity }

data.status

string

No

Set to "cancelled" to cancel the booking

approval_mode

string

No

send_to_customer, charge_and_apply (default for paid changes), or apply_now (waive payment — use only when customer has agreed)

cancellation_refund_percent

number

No

Refund percentage for cancellations (0–100). Defaults to 100

Manual pickup

POST /booking/:id/manual-pickup

Manually mark a booking as picked up. Records the reason and writes the manual pickup quiz response.

Body:

{
  "id": "order_abc123",
  "reason": "Customer collected item in person"
}

Field

Type

Required

Description

id

string

Yes

Booking ID (must match path :id)

reason

string

Yes

Reason for manual pickup

Response:

{ "success": true, "id": "order_abc123" }
Manual return

POST /booking/:id/manual-return

Manually mark a booking as returned. Updates reservations, logs activity, and sends return webhooks.

Body: Same shape as manual pickup (id, reason).

Response:

{ "success": true, "id": "order_abc123" }

Payments

Refund payment

POST /payment/:id/refund

Refund a paid payment. Stripe-backed payments are refunded in Stripe; manual card payments are adjusted in Lockii.

Body:

{
  "id": "payment_abc123",
  "amount": 5000
}

Field

Type

Required

Description

id

string

Yes

Payment ID

amount

number

Yes

Refund amount in cents (must be positive)

Send payment link

POST /payment-link

Create a Stripe payment link for a booking and store it as a payment record.

Body:

{
  "orderID": "order_abc123",
  "amount": 10000,
  "id": "payment_abc123",
  "companyID": "company_xyz"
}

Field

Type

Required

Description

orderID

string

Yes

Booking to request payment for

amount

number

Yes

Amount to request in cents

id

string

No

Payment ID. Defaults to a generated payment_<uuid>

companyID

string

No

Defaults to authenticated company

Response: Payment row including paymentData.payment_link_url.


Customers

List customers

GET /customer

Query param

Type

Default

Description

status

string

all

all, current (on hire now), recent (booked in last 30 days), new (created in last 30 days), unverified

limit

number

15

Maximum results

Search customers

GET /customer/search?query=john

Query param

Type

Required

Description

query

string

Yes

Search by name, last name, email, or phone

Returns up to 5 matches.

Get customer

GET /customer/:id

Returns a single customer record.

Get customer page

GET /customer/:id/page

Returns customer profile with related non-pending bookings (including location, stock, order lines).

Create customer

POST /customer

Body:

{
  "id": "customer_01923abc-def4-7890-abcd-ef1234567890",
  "name": "Jane",
  "lastName": "Smith",
  "email": "[email protected]",
  "phone": "0412345678",
  "phoneCode": "+61",
  "address": "123 Main St",
  "city": "Sydney",
  "state": "NSW",
  "zip": "2000",
  "country": "AU"
}

Field

Type

Required

Description

id

string

Yes

Customer ID (customer_<uuid>)

name

string

No

First name. Defaults to ""

lastName

string

No

Last name. Defaults to ""

email

string

No

Email address

phone

string

No

Phone number

phoneCode

string

No

Country/area code

address, city, state, zip, country

string

No

Address fields

companyID

string

No

Defaults to authenticated company

stripeCustomerID

string

No

Stripe customer ID if linked

Update customer

POST /customer/:id

Same fields as create — all optional except id. Only include fields you want to change.

Delete customer

DELETE /customer/:id

Body:

{ "id": "customer_abc123" }
Block customer

POST /customer/:id/block

Body:

{
  "id": "customer_abc123",
  "reason": "Repeated no-shows"
}
Unblock customer

POST /customer/:id/unblock

Body:

{ "id": "customer_abc123" }
Manually verify customer

POST /customer/:id/manual-verify

Body:

{
  "id": "customer_abc123",
  "identityLink": "https://...",
  "identityExpiresAt": 1742800800000
}

Field

Type

Required

Description

id

string

Yes

Customer ID

identityLink

string

No

Supporting verification link

identityExpiresAt

number

No

Expiry Unix ms. Defaults to one year from now

Generate verification link

POST /customer/:id/verification-link

Body:

{
  "customer_id": "customer_abc123",
  "send_email": true
}

Field

Type

Required

Description

customer_id

string

Yes

Customer ID

send_email

boolean

No

Email the link to the customer. Defaults to false


Products

Search products

GET /product

Query param

Type

Default

Description

categoryID

string

—

Filter by category

nameSearch

string

—

Filter by product name (partial match)

excludeId

string

—

Exclude a product ID

limit

number

—

Maximum results

withStock

boolean

false

Include non-archived stock rows

Get product

GET /product/:id

Query param

Type

Default

Description

activeOnly

boolean

true

Exclude archived products

Returns product with category, pricingTemplate, and optionally stock.

Create product

POST /product

Body:

{
  "id": "product_01923abc-def4-7890-abcd-ef1234567890",
  "name": "Kayak Single",
  "description": "Single person kayak",
  "imageID": "image_abc123",
  "additionalImageIDs": ["image_def456"],
  "pricePerHourCents": 0,
  "basePriceCents": 5000,
  "pricingTemplateID": "pricing_template_abc",
  "categoryID": "category_xyz",
  "companyID": "company_abc123",
  "updatedAt": 1711270800000,
  "archived": false,
  "sortOrder": 0
}

Field

Type

Required

Description

id

string

Yes

Product ID

name

string

Yes

Product name

description

string

Yes

Product description

imageID

string

Yes

Primary image ID

basePriceCents

number

Yes

Base price in cents

pricePerHourCents

number

Yes

Hourly rate in cents (often 0 when using pricing templates)

pricingTemplateID

string

No

Pricing template ID

categoryID

string

No

Category ID

companyID

string

Yes

Company ID

archived

boolean

Yes

Whether product is archived

updatedAt

number

Yes

Unix ms

sortOrder

number

No

Display sort order

Update product

POST /product/:id

Same fields as create — all optional except id.

Delete product

DELETE /product/:id

Body: { "id": "product_abc123" }


Categories

List categories

GET /category

Query param

Type

Default

Description

withProducts

boolean

false

Include non-archived products in each category

Get category

GET /category/:id

Create category

POST /category

Body:

{
  "id": "category_01923abc-def4-7890-abcd-ef1234567890",
  "name": "Water Sports"
}
Update / delete category

POST /category/:id — partial update
DELETE /category/:id — body: { "id": "category_abc123" }


Stock

List stock

GET /stock

Query param

Type

Default

Description

productID

string

—

Filter by product

locationID

string

—

Filter by location

withTracker

boolean

false

Include GPS tracker data

withLock

boolean

false

Include lock data

withCurrentReservation

boolean

false

Include active reservation

withReservations

boolean

false

Include reservation preview

reservationDateRange

object

—

{ "from": number, "to": number } for reservation overlap

stockIDSearch

string

—

Search by stock identifier

excludeStockID

string/array

—

Exclude stock row(s)

limit

number

—

Maximum results

Search stock

GET /stock/search?query=KAY-01

Search by human-readable stock identifier. Returns up to 5 matches with product, location, tracker, and current reservation.

Get stock

GET /stock/:id

Query param

Type

Default

Description

withCurrentReservationOnly

boolean

false

Only load the active hire reservation

Returns stock with product, location, tracker, lock, and reservation data.

Create stock

POST /stock

Body:

{
  "id": "stock_01923abc-def4-7890-abcd-ef1234567890",
  "productID": "product_abc123",
  "locationID": "location_xyz",
  "stockID": "KAY-01",
  "lockID": "lock_abc",
  "trackerID": "tracker_xyz",
  "archived": false
}

Field

Type

Required

Description

id

string

Yes

Stock row ID

productID

string

Yes

Product this unit belongs to

locationID

string

Yes

Location where stock is held

stockID

string

Yes

Human-readable identifier (shown to operators)

lockID

string

No

Associated lock ID

trackerID

string

No

Associated GPS tracker ID

archived

boolean

No

Defaults to false

Update / delete stock

POST /stock/:id — partial update
DELETE /stock/:id — body: { "id": "stock_abc123" }


Locations

List locations

GET /location

Query param

Type

Description

nameSearch

string

Filter by location name

excludeId

string

Exclude a location

limit

number

Maximum results

ids

array

Filter to specific location IDs

stockProductIDs

array

Only locations with stock for these products

Get location

GET /location/:id

Create location

POST /location

Body:

{
  "id": "location_01923abc-def4-7890-abcd-ef1234567890",
  "name": "Main Depot",
  "address": "456 Industrial Ave",
  "lat": -33.8688,
  "lng": 151.2093,
  "accessDetails": "Gate code instructions",
  "taxRateOverride": null,
  "opens": 28800000,
  "closes": 61200000,
  "archived": false
}

Field

Type

Required

Description

id

string

Yes

Location ID

name

string

Yes

Location name

address

string

No

Street address

lat, lng

number

No

Coordinates

accessDetails

string

No

Customer-facing access instructions

taxRateOverride

number

No

Override company tax rate

opens, closes

number

No

Operating hours as ms from midnight

archived

boolean

No

Defaults to false

Update location

POST /location/:id — partial update


Pricing templates

List / search / get
  • GET /pricing-template — list all templates

  • GET /pricing-template/search?query=Daily — search by name

  • GET /pricing-template/:id — get by ID

Create pricing template

POST /pricing-template

Body:

{
  "id": "pricing_template_01923abc-def4-7890-abcd-ef1234567890",
  "name": "Daily Rate",
  "type": "time",
  "template": {
    "tiers": [
      {
        "name": "1 Day",
        "price_multiplier": 1,
        "duration": 1,
        "duration_unit": "days"
      },
      {
        "name": "3 Days",
        "price_multiplier": 2.5,
        "duration": 3,
        "duration_unit": "days"
      }
    ],
    "day_after": {
      "price_multiplier": 0.8
    }
  }
}

Field

Type

Required

Description

id

string

Yes

Template ID

name

string

Yes

Template name

type

string

No

Defaults to "time"

template.tiers

array

Yes

Pricing tiers with name, price_multiplier, duration, duration_unit (hours or days)

template.day_after

object

Yes

Additional day rate: { "price_multiplier": number }

Update / delete

POST /pricing-template/:id — partial update
DELETE /pricing-template/:id — body: { "id": "pricing_template_abc123" }


Coupons

List coupons

GET /coupon?archived=false

Query param

Type

Default

Description

archived

boolean

false

Include archived coupons when true

Search / get
  • GET /coupon/search?query=SUMMER — search active coupons by name

  • GET /coupon/:id — get by ID

Create coupon

POST /coupon

Body:

{
  "id": "coupon_01923abc-def4-7890-abcd-ef1234567890",
  "name": "SUMMER20",
  "uses": 100,
  "used": 0,
  "staticDiscount": 0,
  "percentageDiscount": 20,
  "archived": false
}

Field

Type

Required

Description

id

string

Yes

Coupon ID

name

string

Yes

Coupon code/name

uses

number

No

Maximum uses. Defaults to 0 (unlimited)

staticDiscount

number

No

Fixed discount in cents

percentageDiscount

number

No

Percentage discount (e.g. 20 = 20%)

archived

boolean

No

Defaults to false

Set either staticDiscount or percentageDiscount, not both.

Update / archive

POST /coupon/:id — partial update
POST /coupon/:id/archive — body: { "id": "coupon_abc123" }


Locks & trackers

List locks

GET /lock

Returns stock locks visible to the user, scoped by location access, with related stock.

Search locks

GET /lock/search?query=IGLOO-01

Search by lock identifier. Returns up to 5 matches.

List trackers

GET /tracker

Query param

Type

Description

limit

number

Maximum results

ids

array

Filter to specific tracker IDs

Search trackers

GET /tracker/search?query=Trailer&limit=5

Query param

Type

Default

Description

query

string

Yes

Search by name, type, or ID

limit

number

5

Maximum results

Get tracker

GET /tracker/:id

Update manual tracker (legacy)

PUT /tracker

Body:

{
  "id": "tracker_001",
  "lat": "-33.8688",
  "lng": "151.2093",
  "battery": 85,
  "speed": "0",
  "name": "Trailer GPS"
}

Inbox & reports

Read inbox

GET /inbox/notifications

Query param

Type

Default

Description

query.limit

number

20

Max notifications (1–100)

query.order_id

string

—

Filter by booking ID. When set, returns read and unread

query.stock_id

string

—

Filter by stock row ID or identifier

query.read_status

string

unread

unread, read, or all. Defaults to all when order_id or stock_id is set

Example:

GET /inbox/notifications?query={"limit":10,"read_status":"unread"}
Query reports

GET /reports/query

Query param

Type

Description

report

string

Required. booking_analytics, performance, customer_analytics, or demand

query.date_from

number

Report window start (Unix ms)

query.date_to

number

Report window end (Unix ms)

query.location_id

string

Location filter

query.product_id

string

Product filter

query.category_id

string

Category filter

query.limit

number

Max rows in ranked sections (1–50, default 10)

Example:

GET /reports/query?report=booking_analytics&query={"date_from":1711270800000,"date_to":1711357200000,"limit":10}

Response:

{
  "report": "booking_analytics",
  "query": { "date_from": 1711270800000, "date_to": 1711357200000, "limit": 10 },
  "generated_at": 1711270800000,
  "result": { }
}

Permissions & scoping

  • All requests are scoped to the company associated with your API key.

  • Location-scoped users only see data for locations they have access to.

  • Write operations require appropriate role permissions (e.g. payment refunds require organization:update).


Related

  • Lockii User MCP — same capabilities as MCP tools for AI clients

  • Customer MCP — limited MCP for customer-facing support tools

  • Browse API — public endpoints for custom booking frontends

  • Connecting Zapier — no-code automations

PrevCustomer MCP
NextBooking API
Was this helpful?