The base URL to send all API requests ishttps://api.loby.io. HTTPS is required for all API requests.
The Loby API follows RESTful conventions when possible, with most operations performed via GET, POST, PATCH, and DELETE requests. Request and response bodies are encoded as JSON and therefore requests need to include the headercontent-type: application/json
when appropriate.
Use Loby API to retrieve, create or modify data stored in your Loby account programmatically and to create custom integrations.
There is currently one version, which is reachable via:https://api.loby.io/v1
Loby API uses API access tokens to authenticate requests. You can view and manage your API keys in Loby.
Your API keys carry many privileges, so be sure to keep them secure! Do not share your secret API key in publicly accessible areas such as GitHub, client-side code, and so forth.
All API requests must be made over HTTPS. Calls made over plain HTTP will fail. API requests without authentication will also fail.
The API key should be passed as a Bearer authorization header, e.g.:
Authorization: Bearer {{accessToken}}
Replace{{accessToken}}
with your key from Loby.
Property | Type | Default | Description | Example |
---|---|---|---|---|
id * | string (UUIDv4) | Unique identifier | "bd4a0997-39db-41d9-883a-cdfa83e2101f" | |
encryptedId | string | Encrypted identifier. Used to create direct checkout links. It has been encrypted with a key for the organization. | "Wn6VsJflvjBO3YyC0lgXdBt9QKcLVZQ2qkEcvJGqa+Txg+mHI/TWbEuUpS45VZgg" | |
firstName | string | null | First name of customer | "Johanna" |
lastName | string | null | Last name of customer | "Ha" |
email | string | null | Email of customer. Email is unique and trying to create a new customer with an email that already exists will fail | "hello@hello.com" |
phone | string | null | Phone number of customer | "12345678" |
phoneCountryCode | string | null | Country code of phone number | "dk" |
memberNumber | number | null | Member number of customer. This will only be issued if the customer at some point has had a membership | 12345678 |
address | string | null | Address of customer | "Hovedgaden 1" |
address2 | string | null | Address 2 of customer | "1. sal" |
postalCode | string | null | Postal code of customer | "1234" |
city | string | null | City of customer | "København" |
country | string | null | Country of customer | "dk" |
birthdate | string | null | Birth date for the customer formattedYYYY-MM-DD | "2024-01-04" |
birthyear | number | null | Birth year for the customer if you only have this information | 2000 |
avatar | string (UUIDv4) | null | Id of the image used for the avatar | "bd4a0997-39db-41d9-883a-cdfa83e2101f" |
note | string | null | Optional internal note | "This customer is awesome" |
qrCode | string | null | QR code of the customer | "https://www.acme-museum.com/?qr=KLkjndfjf..." |
GET /customers
You can use this endpoint to retrieve a list of customers. You can use thefilter
parameter to filter the list of customers.
Use thePagination
andQuerying
sections to learn more about how to complete this request.
List of available fields to query:
Field Name | Type |
---|---|
NAME | string |
FIRST_NAME | string |
LAST_NAME | string |
EMAIL | string |
MEMBER_NUMBER | number |
INITIALS | string |
ADDRESS | string |
POSTAL_CODE | string |
CITY | string |
COUNTRY | string |
PHONE | string |
ENABLE_MEMBERSHIP_EXPIRATION_FLOW | boolean |
SUBSCRIBED_TO_NEWSLETTER | boolean |
MEMBERSHIP | Membership |
CHECKIN | Checkin |
TRANSACTION | Transaction |
GET /customers/:id
If you have an id for a customer, you can use this endpoint to retrieve the customer.
Example response
{
"id": "bd4a0997-39db-41d9-883a-cdfa83e2101f",
"firstName": "Henny",
...
}
POST /customers
You can create a new customer by providing any of the following fields:
Property | Type | Description |
---|---|---|
firstName | string | First name of customer |
lastName | string | Last name of customer |
email | string | Email of customer |
phone | number | Phone number of customer |
phoneCountryCode | string | ISO Country code of phone number |
address | string | Address of customer |
address2 | string | Address 2 of customer |
postalCode | string | Postal code of customer |
city | string | City of customer |
country | string | ISO Country code of customer |
birthdate | string | Birth date for the customer |
avatar | string (UUIDv4) | Id of the image used for the avatar |
note | string | Note for the customer |
PATCH /customers/:id
You can update a customer by providing any of the following fields:
Property | Type | Description |
---|---|---|
firstName | string | First name of customer |
lastName | string | Last name of customer |
memberNumber | number | Member number of the customer |
email | string | Email of customer |
phone | number | Phone number of customer |
phoneCountryCode | string | ISO Country code of phone number |
address | string | Address of customer |
address2 | string | Address 2 of customer |
postalCode | string | Postal code of customer |
city | string | City of customer |
country | string | ISO Country code of customer |
birthdate | string | Birth date for the customer |
avatar | string (UUIDv4) | Id of the image used for the avatar |
note | string | Note for the customer |
Set to null to remove the field.
DELETE /customers/:customerId
A membership type is a type specification, that is referred to when issuing new memberships.
Property | Type | Default | Description | Example |
---|---|---|---|---|
id * | string (UUIDv4) | Unique identifier | "bd4a0997-39db-41d9-883a-cdfa83e2101f" | |
title * | string | Title of membership type | "All access pass" or"Season Pass" or"Yearly Membership" | |
price | number | null | Price of ticket in lowest unit. Cents forEUR ,USD etc. 0 = FREE | 54000 |
cycle | string | YEARLY | For how long the membership will be active until it needs to be renewed. Can be eitherYEARLY orMONTHLY orINFINITE . | "MONTHLY" |
translations | array | [] | A list of translation objectsMembershipTypeTranslation for the object | [{ language: "da", title: "Et adgang til alt..." }] |
renewalPrice | number | null | A potential renewal price | 49000 |
enableRenewalPrice | boolean | false | Whether the renewal price should be enabled | true |
enableRenewalPriceEligibility | boolean | false | If this is set to true, you are only allowed to renew if the conditions inrenewalPriceEligibilityPeriodType ,renewalPriceEligibilityPeriods andrenewalPriceEligibilityBeforeExpiration are met. | true |
renewalPriceEligibilityPeriodType | string | null | Can beDAY ,MONTH orYEAR . Determines how many of the chosen types have to be passed before you are uneligible for renewal price | "MONTH" |
renewalPriceEligibilityPeriods | number | null | IfrenewalPriceEligibilityPeriodType is set toMONTH andrenewalPriceEligibilityPeriods is set to 2 andrenewalPriceEligibilityBeforeExpiration is set totrue , then the member needs to renew its membership 2 months before expiration to be eligible for the renewal price. | 2 |
enableRenewalPrice | boolean | false | Whether the renewal price should be enabled | true |
renewalPriceEligibilityBeforeExpiration | boolean | false | As default it will append the period before the expiration. Otherwise it will be after. | true |
GET /membership-types
You can use this endpoint to retrieve a list of membership types.
Use thePagination
andQuerying
sections to learn more about how to complete this request.
AMembershipTypeTranslation
contains translated fields for the object.
Property | Type | Default | Description | Example |
---|---|---|---|---|
language * | string (ISO 639-1) | Language code for the translation | "da" | |
title | string | null | See description of field inMembershipType |
AMembership
represents an entered membership, that has a MembershipType. A Membership can e.g. be used to get benefits or to get access to the museum.
Property | Type | Default | Description | Example |
---|---|---|---|---|
id * | string (UUIDv4) | Unique identifier | "bd4a0997-39db-41d9-883a-cdfa83e2101f" | |
validFrom | string (YYYY-MM-DD) | null | Date for when the membership starts | 2024-04-05 |
validTo | string (YYYY-MM-DD) | null | Date for when the membership will expire. Including the date | 2025-04-05 |
active | boolean | Whether the membership is valid or not. This is a convenience property that is calculated from validFrom and validTo | true | |
autoRenew | boolean | false | Shows whether the membership will be auto renewed | true |
preferredRenewalMembershipTypeId | string (UUIDv4) | null | This field can be used to determine which membership type should be used for the renewal | "bd4a0997-39db-41d9-883a-cdfa83e2101f" |
membershipType | MembershipType | A reference to aMembershipType | { id: "... } | |
payerId | string (UUIDv4) | null | A reference to aCustomer that is the payer of the membership | "bd4a0997-39db-41d9-883a-cdfa83e2101f" |
List of available fields to query:
Field Name | Type |
---|---|
ID | uuid |
ACTIVE | boolean |
AUTO_RENEW | boolean |
DATE | date |
VALID_FROM | date |
VALID_TO | date |
POST /customers/:customerId/memberships
You can post a new membership by providing the following fields:
Property | Type | Description | |
---|---|---|---|
membershipTypeId * | string (UUIDv4) | ID of membership type | |
validFrom | string (YYYY-MM-DD) | Date for when the membership should be valid from. If not provided, it will be set to the current date. | |
validTo | string (YYYY-MM-DD) | Date for when the membership should be valid to. If not provided, it will be set to the current date + the cycle of the membership type. | |
previousMembershipId | string (UUIDv4) | If the membership is a renewal, then this field should be set to the id of the previous membership. | \ |
payerId | string (UUIDv4) | If the membership is paid by another customer, then this field should be set to the id of the payer. |
PATCH /memberships/:membershipId
You can update the following fields:validFrom
,validTo
,autoRenew
,preferredRenewalMembershipTypeId
,payerId
DELETE /memberships/:membershipId
POST /memberships/:membershipId/send-email
This will automatically send a membership email to the customer.
GET /verify-membership-qr-code/:qrData
The variableqrData
is the entire data for the qr code e.g.https://test...?qr=test
. It needs to be url encoded. So in that means something like this:https%3A%2F%2Ftest...%2F%3Fqr%3DHX9Smn5X%252
It will always return a response with the booleanvalid
.
{
"valid": true
}
A ticket type is a type specification, that is referred to when issuing new tickets.
Property | Type | Default | Description | Example |
---|---|---|---|---|
id * | string (UUIDv4) | Unique identifier | "bd4a0997-39db-41d9-883a-cdfa83e2101f" | |
locationId | string (UUIDv4) | Reference to a location. If that ticket type belongs to a specific location | "bd4a0997-39db-41d9-883a-cdfa83e2101f" | |
name * | string | Name of ticket type | "Adult Ticket Web" | |
description | string | Description of the ticket | "This ticket..." | |
onlineName * | string | Online Name of ticket type | "Adult Ticket" | |
onlineDescription | string | Online Description of the ticket | "This ticket..." | |
translations | array | [] | A list of translation objectsTicketTypeTranslation for the object | [{ language: "da", name: "Voksen Bill..." }] |
price | number | null | Price of ticket in lowest unit. Cents forEUR ,USD etc. 0 = FREE | 54000 |
GET /ticket-types
You can use this endpoint to retrieve a list of ticket types.
ATicketTypeTranslation
contains translated fields for the object.
Property | Type | Default | Description | Example |
---|---|---|---|---|
language * | string (ISO 639-1) | Language code for the translation | "da" | |
name | string | null | See description of field inTicketType | |
description | string | null | See description of field inTicketType | |
onlineName | string | null | See description of field inTicketType | |
onlineDescription | string | null | See description of field inTicketType |
ATicket
represents an issued ticket, that has a TicketType. A Ticket can e.g. be used to get access to the museum.
Property | Type | Default | Description | Example |
---|---|---|---|---|
id * | string (UUIDv4) | Unique identifier | "bd4a0997-39db-41d9-883a-cdfa83e2101f" | |
createdAt | string | Date for when the ticket was created | "2021-03-01T12:00:00.000Z" | |
number | number | Number of the ticket | 166 | |
ticketType | TicketType | TheTicketType object for the ticket | { id: "... } | |
qrCode | string | QR code of the ticket | "https://www.acme-museum.com/tickets?qr=KLkjndfjf..." |
GET /tickets/:id
If you have an id for a ticket, you can use this endpoint to retrieve the ticket.
Example response
{
"id": "bd4a0997-39db-41d9-883a-cdfa83e2101f",
"number": 3455,
...
}
POST /tickets
You can post a new ticket by providing the following fields:
Property | Type | Description |
---|---|---|
ticketTypeId * | string (UUIDv4) | ID of ticket type |
customerId | string (UUIDv4) | ID of customer |
timeSlotId | string (UUIDv4) | A valid time slot reference for the ticket. Ticket Type and Time Slot should either not have location id or the same. Time Slot should have sufficient capacity. |
DELETE /tickets/:ticketId
A location can be used for various things. Eg. Assigning timeslots and ticket types to it
Property | Type | Default | Description | Example |
---|---|---|---|---|
id * | string (UUIDv4) | Unique identifier | "bd4a0997-39db-41d9-883a-cdfa83e2101f" | |
name * | string | Name of location | "Train" |
GET /locations
You can use this endpoint to retrieve a list of locations.
A time slot holds information regarding a specific time slot for tickets.
Property | Type | Default | Description | Example |
---|---|---|---|---|
id * | string (UUIDv4) | Unique identifier | "bd4a0997-39db-41d9-883a-cdfa83e2101f" | |
maxCapacity | number | The max capacity for the slot | 120 | |
start | date | Start time stamp for the time slot | "2024-01-11T10:00:00.000Z" | |
end | date | Start time stamp for the time slot | "2024-01-11T10:29:59.999Z" | |
numberOfIssuedTickets | number | How many tickets have been issued for this time slot | 99 | |
numberOfReservedTickets | number | How many tickets have been reserved for this time slot | 2 | |
availableTickets | number | How many tickets are available in total | 19 |
GET /locations/:locationId/time-slots/:dateQuery
You can use this endpoint to retrieve a list of time slots. You can query the date with the following formats:YYYY
,YYYY-MM
,YYYY-MM-DD
When querying for a list of objects, you will receive a format like this:
{
"total": 15646,
"list": [
{
"id": "bd4a0997-39db-41d9-883a-cdfa83e2101f",
...
},
...
]
}
Wheretotal
is the total number of objects that are available andlist
is the list of objects that are returned. The limit is 1000 objects per request. So in the above response there are 15646 objects available, but only 1000 are returned. If you want the next 1000 objects, you can use theoffset
parameter.
To query a list of objects, you can use thefilter
parameter. Thefilter
parameter is a uri encoded JSON object, where you can specify the fields you want to query.
The base filter is an object like this:
{
"operator": "CONTAINS",
"fieldName": "NAME",
"value": "John"
}
So if you want to run this filter on aCustomer
, then you need to stringify the object and uri encode it. The result will be:
%7B%22operator%22%3A%22CONTAINS%22%2C%22fieldName%22%3A%22NAME%22%2C%22value%22%3A%22John%22%7D
And this needs to be appended to the request, which will look like this:
GET
https://api.loby.io/v1/customers?filter=%7B%22operator%22%3A%22CONTAINS%22%2C%22fieldName%22%3A%22NAME%22%2C%22value%22%3A%22John%22%7D
Below are the types foroperator
: | Operator | Description | | - | - | |CONTAINS
| The field contains the value | |NOT_CONTAINS
| The field does not contain the value | |EQUAL
| The field is equal to the value | |NOT_EQUAL
| The field is not equal to the value | |STARTS_WITH
| The field starts with the value | |ENDS_WITH
| The field ends with the value | |INCLUDES
| The field includes the value | |NOT_INCLUDES
| The field does not include the value | |LESSER
| The field is lesser than the value | |LESSER_OR_EQUAL
| The field is lesser than or equal to the value | |GREATER
| The field is greater than the value | |GREATER_OR_EQUAL
| The field is greater than or equal to the value | |AND
| Use this operator if you want to nest conditions and check that all sub conditions are true | |OR
| Use this operator if you want to nest conditions and check that at least one is true |
ThefieldName
is the field you want to query. The available fields are listed in the resource documentation for each resource.
Some fields refer to other resources. E.g.MEMBERSHIP
onCustomer
refers to aMembership
. In this case you can query the nested fields by using the.
notation. E.g. if you want to query theVALID_TO
field on theMembership
from the customer you can do it like this:
{
"operator": "GREATER",
"fieldName": "MEMBERSHIP.VALID_TO",
"value": 1646071663704
}
If you want to query multiple conditions, you can use theAND
orOR
operator. E.g. if you want to query all customers that have a membership that is valid for more than 1 month, you can do it like this:
{
"operator": "AND",
"conditions": [
{
"operator": "GREATER",
"fieldName": "MEMBERSHIP.VALID_TO",
"value": 1646071663704
},
...
]
}
You can also nest each condition infinitely and also combineAND
andOR
operators.
Loby provides a fully functional image generator, that dynamically generates images for requested sizes. The images are quickly generated and cached for fast reuse.
Use the following url for generating images:
https://img.loby.io/{{imageId}}_{{sizingType}}{{size}}.{{format}}
component | Description | Example |
---|---|---|
imageId | The id of the image | 6ef7d631-b898-40a4-ba27-b8c772f6db03 |
sizingType | There are 3 options:w ,h ands . By choosingw , image is sized according to width.h according to height ands will square crop the image and size according to both sides | w |
size | The size according to the sizing type | 1280 |
format | You can choose betweenjpg andpng | jpg |
https://img.loby.io/6ef7d631-b898-40a4-ba27-b8c772f6db03_w1280.jpg