schema { query: Query mutation: Mutation } """ Custom directive for field-level permission checks. Returns null with an error in the errors array if permission is not granted. """ directive @authz( """ The permission slug required to access this field """ permission: String! ) on FIELD_DEFINITION """ Marks a schema element as unstable. No guarantees are made about its behavior: it may have breaking changes, have unexpected behavior, or disappear entirely without warning. """ directive @unstable( """ Optional note explaining what is unstable or what is likely to change. """ reason: String ) on ARGUMENT_DEFINITION | ENUM | ENUM_VALUE | FIELD_DEFINITION | INPUT_FIELD_DEFINITION | INPUT_OBJECT | INTERFACE | OBJECT | SCALAR | UNION input AddCarToMembershipInput { membershipId: ID! nickname: String plate: String! state: String! } """ Input for adding a car to an owner plan """ input AddCarToOwnerPlanInput { """ Optional nickname for this vehicle """ nickname: String """ The ID of the owner plan to add the car to (required) """ ownerPlanId: ID! """ License plate number (required) """ plate: String! """ State/region of registration (required) """ state: String! } """ Why a record was archived. USER means a user explicitly archived it. SYSTEM means it was automatically archived because a newer version replaced it. CASCADE means it was automatically archived alongside a parent record being archived (e.g. a Price cascade-archived when its Product is archived). """ enum ArchivedReason { """ Archived automatically alongside a parent record (e.g. Price cascade-archived with its Product) """ CASCADE """ Archived automatically by the system (e.g. replaced by a newer version) """ SYSTEM """ Archived explicitly by a user """ USER } """ Billing frequency options for subscription prices """ enum BillingFrequency { """ Billed monthly """ MONTHLY """ Billed quarterly (every 3 months) """ QUARTERLY """ Billed yearly """ YEARLY } input CancelCarRemovalInput { carId: ID! membershipId: ID! } type Car { """ The body type of the car """ bodyType: String """ The color of the car """ color: String """ Time when this car was created """ createdAt: DateTime! """ The customer associated with the car """ customer: RollerupCustomer """ The customer ID associated with the car """ customerId: String id: ID! """ Whether the car belongs to a member or not """ isMember: Boolean! """ Timestamp of the vehicle's most recent visit """ lastVisitedAt: DateTime """ Location where the vehicle was last seen """ lastVisitedLocation: Location """ The make of the car """ make: String """ The membership associated with the car """ membership: Membership """ The membership ID associated with the car """ membershipId: String """ The model of the car """ model: String """ The nickname associated with the car """ nickname: String """ The plate number of the car """ plate: String! """ The RFID tag, if there is one, on the car """ rfidTag: String """ The state of the car """ state: String! """ The Stripe customer associated with the car """ stripeCustomer: StripeCustomer @deprecated(reason: "Use RollerupCustomer instead") """ Total number of visits across all locations """ totalVisits: Int! """ Time when this car was last updated """ updatedAt: DateTime! """ The year of the car """ year: String } """ Paginated result for car queries """ type CarPage { """ List of cars in the current page """ nodes: [Car!]! """ Pagination metadata including cursors and page position """ pageInfo: PageInfo! } """ Represents a card used to make a payment. """ type Card { """ The brand of the card """ brand: String! """ The expiration month of the card """ expMonth: Int! """ The expiration year of the card """ expYear: Int! id: ID! """ The last 4 digits of the card. String to match Stripe's format """ last4: String! } """ Pagination input for querying cars. Supports both forward and backward pagination. Use 'first' and 'after' for forward pagination, or 'last' and 'before' for backward pagination. """ input CarsQueryInput { """ A cursor for pagination, returns items after this cursor (forward pagination) """ after: String """ A cursor for pagination, returns items before this cursor (backward pagination) """ before: String """ A customer ID to filter vehicles by """ customerId: String """ The number of items to return from the beginning of the list (forward pagination) """ first: Int """ The number of items to return from the end of the list (backward pagination) """ last: Int """ A search term to filter vehicles by, typically a plate number """ search: String } """ Input for creating a new discount. You must specify either amountOff (fixed amount) or percentOff (percentage), but not both. The duration determines how long the discount applies to subscriptions. """ input CreateDiscountInput { """ Fixed amount to discount in cents (e.g., 500 for $5.00 off). Mutually exclusive with percentOff """ amountOff: Int """ A schedule that describes when this discount is available for redemption (null for always available) """ availabilitySchedule: ScheduleInput """ How long the discount applies to a subscription """ duration: DiscountDuration! """ Number of months the discount is applied (required when duration is REPEATING) """ durationInMonths: Int """ Maximum number of times this discount can be redeemed (null for unlimited) """ maxRedemptions: Int """ Human-readable name for the discount """ name: String! """ Percentage off (e.g., 20 for 20% off). Mutually exclusive with amountOff """ percentOff: Int """ Expiration date for the discount code (null for no expiration) """ redeemBy: DateTime } input CreateNoteInput { """ The ID of the customer """ customerId: ID! """ The note content """ note: String! } """ Input for creating a new owner plan """ input CreateOwnerPlanInput { """ City """ city: String """ Description of the owner plan """ description: String """ Email address for the owner """ email: String """ When this owner plan expires (null for no expiration) """ expiresAt: DateTime """ Name of the owner plan (required) """ name: String! """ Phone number for the owner """ phone: String """ State """ state: String """ Street address line 1 """ street1: String """ Street address line 2 """ street2: String """ The wash package ID that this owner plan provides (required) """ washPackageId: ID! """ ZIP code """ zip: String } """ Input for creating a new user in the system. Note: If username is provided, either password must be set or issueTempPassword must be true. """ input CreateUserInput { """ Email address of the user (must be valid email format) """ email: EmailAddress """ Optional external system identifier for the user """ externalId: String """ List of group IDs the user should belong to """ groupIds: [String!]! """ Full name of the user """ name: String! """ Phone number of the user (must be valid phone format - example: +12345678901) """ phone: PhoneNumber """ Unique username for authentication. If provided, a temporary password will be returned in the response """ username: String } """ Input for creating a new wash package """ input CreateWashPackageInput { """ An optional detailed description of the package """ description: String """ An optional reference ID to link this Rollerup package to a system external to Rollerup """ externalId: String """ A friendly name for the package """ name: String! } """ Input for searching Rollerup customers with multiple optional filter criteria. Supports cursor-based pagination. Multiple filters are combined using AND logic. """ input CustomersInput { """ A cursor for pagination, returns items after this cursor (forward pagination) """ after: String """ A cursor for pagination, returns items before this cursor (backward pagination) """ before: String """ Filter by customer email address (case-insensitive partial match) """ email: String """ The number of items to return from the beginning of the list (forward pagination) """ first: Int """ Filter by active member status. A customer is an active member if they have at least one car assigned to a membership (i.e. a membership_car exists). This is independent of subscription billing status. """ isActiveMember: Boolean """ The number of items to return from the end of the list (backward pagination) """ last: Int """ Filter by last four digits of payment method (card) """ lastFour: String """ Filter by customer name (case-insensitive partial match) """ name: String """ Filter by phone number (E.164 exact match if valid, otherwise partial match) """ phone: String """ Filter by vehicle license plate (case-insensitive, normalized) """ plate: String } """ Paginated result for Rollerup customer search queries """ type CustomersPage { """ List of customers matching the search criteria """ nodes: [RollerupCustomer!]! """ Pagination metadata including cursors and page position """ pageInfo: PageInfo! } scalar DateTime """ Represents a discount that can be applied to subscriptions or purchases. Discounts can be either a fixed amount off or a percentage off the total. """ type Discount { """ Fixed amount to discount in cents (e.g., 500 for $5.00 off) """ amountOff: Int """ A schedule that describes when this discount is available for redemption (null for always available) """ availabilitySchedule: Schedule """ Timestamp when the discount was created """ createdAt: DateTime! """ How long the discount applies to a subscription """ duration: DiscountDuration! """ Number of months the discount is applied (only used when duration is REPEATING) """ durationInMonths: Int """ Unique identifier for the discount """ id: ID! """ Maximum number of times this discount can be redeemed (null for unlimited) """ maxRedemptions: Int """ Human-readable name for the discount """ name: String! """ Percentage off (e.g., 20 for 20% off) """ percentOff: Int """ Expiration date for the discount code (null for no expiration) """ redeemBy: DateTime """ Timestamp when the discount was last updated """ updatedAt: DateTime! } """ Duration types for how long a discount applies to a subscription """ enum DiscountDuration { """ Apply discount to all payments indefinitely """ FOREVER """ Apply discount only to the first payment """ ONCE """ Apply discount for a specific number of months (requires durationInMonths) """ REPEATING } """ Paginated result for discounts """ type DiscountPage { """ List of discounts in the current page """ nodes: [Discount!]! """ Pagination metadata including cursors and page position """ pageInfo: PageInfo! } """ Input for querying discounts with optional filter criteria. Supports both forward and backward cursor-based pagination. Use 'first' and 'after' for forward pagination, or 'last' and 'before' for backward pagination. """ input DiscountQueryInput { """ Filter by active status (true for discounts that haven't expired and haven't reached max redemptions) """ active: Boolean """ A cursor for pagination, returns items after this cursor (forward pagination) """ after: String """ A cursor for pagination, returns items before this cursor (backward pagination) """ before: String """ Filter for discounts that expire on or before this date """ expiresEnd: DateTime """ Filter for discounts that expire on or after this date """ expiresStart: DateTime """ The number of items to return from the beginning of the list (forward pagination) """ first: Int """ The number of items to return from the end of the list (backward pagination) """ last: Int """ Filter by discount name (case-insensitive partial match) """ name: String } scalar EmailAddress """ Represents an employee. This is backed by the same data as the User model, but with less fields and without the same permission restrictions. """ type Employee { """ The car assigned to the employee """ car: Car """ Timestamp when the employee was created """ createdAt: DateTime! """ An id from an system external to Rollerup for reference purposes """ externalId: String """ Unique identifier for the employee """ id: ID! """ Whether or not the employee is still active in Rollerup """ isActive: Boolean! """ Name of the employee """ name: String """ Timestamp when the employee was last updated """ updatedAt: DateTime! } """ Input for querying employees. Supports both forward and backward pagination. Use 'first' and 'after' for forward pagination, or 'last' and 'before' for backward pagination. """ input EmployeesInput { """ A cursor for pagination, returns items after this cursor (forward pagination) """ after: String """ A cursor for pagination, returns items before this cursor (backward pagination) """ before: String """ The number of items to return from the beginning of the list (forward pagination) """ first: Int """ The number of items to return from the end of the list (backward pagination) """ last: Int } """ Paginated result for employee queries """ type EmployeesPage { """ List of employees in the current page """ nodes: [Employee!]! """ Pagination metadata including cursors and page position """ pageInfo: PageInfo! } """ Represents a user group for organizing users and managing permissions """ type Group { """ Optional description explaining the purpose of the group """ description: String """ Unique identifier for the group """ id: ID! isAdmin: Boolean! """ Display name of the group """ name: String! permissions: [String!]! @authz(permission: "users:manage") """ URL-friendly identifier for the group """ slug: String! } """ Pagination input for querying owner plans. Supports both forward and backward pagination. Use 'first' and 'after' for forward pagination, or 'last' and 'before' for backward pagination. """ input ListOwnerPlansInput { """ A cursor for pagination, returns items after this cursor (forward pagination) """ after: String """ A cursor for pagination, returns items before this cursor (backward pagination) """ before: String """ The number of items to return from the beginning of the list (forward pagination) """ first: Int """ The number of items to return from the end of the list (backward pagination) """ last: Int } """ Pagination input for querying owner visits. Supports both forward and backward pagination. Use 'first' and 'after' for forward pagination, or 'last' and 'before' for backward pagination. """ input ListOwnerVisitsInput { """ A cursor for pagination, returns items after this cursor (forward pagination) """ after: String """ A cursor for pagination, returns items before this cursor (backward pagination) """ before: String """ if provided filter visits to just those for this particular car """ carId: ID """ The number of items to return from the beginning of the list (forward pagination) """ first: Int """ The number of items to return from the end of the list (backward pagination) """ last: Int ownerPlanId: ID! } scalar LocalDate """ Represents a location in the system """ type Location { """ Whether cash payments are enabled for this location """ cashEnabled: Boolean! """ City """ city: String """ The company this location belongs to """ companyId: ID! """ Timestamp when the location was created """ createdAt: DateTime! """ External system identifier for the location """ externalId: String """ Unique identifier for the location """ id: ID! """ Whether this is a virtual location """ isVirtual: Boolean! """ Display name of the location """ name: String! """ Short display name of the location """ shortName: String """ State or province """ state: USStateCode """ Street address """ street: String """ The Stripe account ID used by this location """ stripeAccountId: String! """ Stripe terminal location ID """ stripeTerminalLocationId: String """ Whether tax calculation is enabled for this location """ taxEnabled: Boolean! """ Location timezone """ timezone: String! """ Timestamp when the location was last updated """ updatedAt: DateTime! """ ZIP or postal code """ zip: USPostalCode } """ Paginated result for location queries """ type LocationPage { """ List of locations in the current page """ nodes: [Location!]! """ Pagination metadata including cursors and page position """ pageInfo: PageInfo! } """ Pagination input for querying locations. Supports both forward and backward pagination. Use 'first' and 'after' for forward pagination, or 'last' and 'before' for backward pagination. """ input LocationQueryInput { """ A cursor for pagination, returns items after this cursor (forward pagination) """ after: String """ A cursor for pagination, returns items before this cursor (backward pagination) """ before: String """ The number of items to return from the beginning of the list (forward pagination) """ first: Int """ The number of items to return from the end of the list (backward pagination) """ last: Int } type Membership { """ Whether this membership is active """ active: Boolean! """ Maximum number of cars allowed on this membership """ carLimit: Int! """ Timestamp when the membership was created """ createdAt: DateTime! """ Membership ID """ id: String! """ Whether this membership uses fleet-style billing / management """ isFleet: Boolean! """ All cars linked to this membership, including those scheduled for removal """ membershipCars: [MembershipCar!]! """ Price """ price: Price! """ Price ID """ priceId: String! } """ A car linked to a subscription membership, including scheduled end-of-period removal. """ type MembershipCar { """ The vehicle """ car: Car! """ When this link was created """ createdAt: DateTime! id: ID! """ Optional nickname for this vehicle on the membership """ nickname: String """ When the car is scheduled to be removed (null if not scheduled) """ removingAt: DateTime } """ The kind of change being previewed against a membership's linked cars. """ enum MembershipCarChangeIntent { """ Adding a new car to the membership """ add """ Cancelling a previously-scheduled removal """ cancel_removal """ Scheduling an existing car for removal at end of period """ remove } """ Preview of a membership car change. Reflects the upcoming invoice for the proposed change without mutating any state. """ type MembershipCarChangePreview { """ Whether this change is an upgrade (more cars / charge now) or downgrade """ changeType: SubscriptionChangeType! """ Amount that would be invoiced immediately, in the smallest currency unit """ immediateTotal: Int! """ Line items for the immediate (proration) preview invoice """ lineItems: [MembershipCarChangePreviewLineItem!]! """ Number of vehicles on the membership after the change is applied """ newVehicleQuantity: Int! """ When the next recurring invoice would be billed """ nextBillingDate: DateTime """ Total of the next recurring invoice after the change """ nextInvoiceTotal: Int! } """ A line item from the upcoming invoice preview. """ type MembershipCarChangePreviewLineItem { """ Amount in the smallest currency unit """ amount: Int! """ Invoice line description (may be null) """ description: String """ Whether this line is a proration adjustment """ proration: Boolean! """ Quantity for this line, when applicable """ quantity: Int } """ Input for merging one Rollerup customer into another. The source customer is hard-deleted after dependent records are re-pointed to the target. """ input MergeCustomersInput { """ Customer that will be absorbed and hard-deleted """ sourceId: ID! """ Customer that will survive and receive the merged data """ targetId: ID! } type MutateUserResponse { """ A temporary password for the user if username was set """ tempPassword: String """ The newly created user """ user: User! } type Mutation { addCarToMembership(input: AddCarToMembershipInput!): MembershipCar! @authz(permission: "subscriptions:manage") """ Add a car to an owner plan """ addCarToOwnerPlan(input: AddCarToOwnerPlanInput!): OwnerCar! @authz(permission: "owner-plans:manage") archiveNote(id: ID!): Note! cancelCarRemoval(input: CancelCarRemovalInput!): MembershipCar! @authz(permission: "subscriptions:manage") """ Create a new discount. Either amountOff or percentOff must be specified, but not both """ createDiscount(input: CreateDiscountInput!): Discount! @authz(permission: "discounts:manage") createNote(input: CreateNoteInput!): Note! """ Create a new owner plan """ createOwnerPlan(input: CreateOwnerPlanInput!): OwnerPlan! @authz(permission: "owner-plans:manage") """ Create a new user. Requires 'users:manage' permission """ createUser( """ User creation parameters """ input: CreateUserInput! ): MutateUserResponse! @authz(permission: "users:manage") """ Create a new Wash package. Requires the 'wash-packages:manage' permission """ createWashPackage(input: CreateWashPackageInput!): WashPackage! @authz(permission: "wash-packages:manage") """ Deactivate a user account, preventing them from logging in. Requires 'users:manage' permission """ deactivateUser( """ The id of the user to deactivate """ id: ID! ): User! @authz(permission: "users:manage") """ Delete an owner plan (soft delete) """ deleteOwnerPlan(id: ID!): ID! @authz(permission: "owner-plans:manage") """ Merge one Rollerup customer into another. The source customer's subscriptions, paid invoices, and stripe customers are re-pointed to the target; any null fields on the target are backfilled from the source; the source row is then hard-deleted. A snapshot of the source row is preserved in the customer_merges audit table. Requires the 'customers:manage' permission. """ mergeCustomers(input: MergeCustomersInput!): RollerupCustomer! @authz(permission: "customers:manage") """ Reactivate a previously deactivated user account, restoring their ability to log in. Requires 'users:manage' permission """ reactivateUser( """ The id of the user to reactivate """ id: ID! ): User! @authz(permission: "users:manage") removeCarFromMembership(input: RemoveCarFromMembershipInput!): MembershipCar! @authz(permission: "subscriptions:manage") """ Remove a car from an owner plan """ removeCarFromOwnerPlan(id: ID!): ID! @authz(permission: "owner-plans:manage") """ Update a Rollerup customer's name, email, or phone. Only fields provided in the input are updated. If the new email matches another customer in the same company, the mutation fails with a CUSTOMER_EMAIL_CONFLICT error whose extensions include the conflicting customer id so the client can offer a merge. """ updateCustomer(input: UpdateCustomerInput!): RollerupCustomer! @authz(permission: "customers:manage") """ Update an existing owner plan """ updateOwnerPlan(input: UpdateOwnerPlanInput!): OwnerPlan! @authz(permission: "owner-plans:manage") """ Update a car on an owner plan (e.g., change nickname) """ updateOwnerPlanCar(input: UpdateOwnerPlanCarInput!): OwnerCar! @authz(permission: "owner-plans:manage") """ Update an existing user. Requires 'users:manage' permission """ updateUser( """ User update parameters """ input: UpdateUserInput! ): MutateUserResponse! @authz(permission: "users:manage") """ Update an existing Wash package. Requires the 'wash-packages:manage' permission """ updateWashPackage(input: UpdateWashPackageInput!): WashPackage! @authz(permission: "wash-packages:manage") } type Note { """ The timestamp when the note was archived """ archivedAt: DateTime """ The user who archived the note """ archivedBy: Employee """ The timestamp when the note was created """ createdAt: DateTime! """ The user who created the note """ createdBy: Employee! """ The ID of the customer """ customerId: ID! """ Unique identifier for the note """ id: ID! """ The note content """ note: String! """ The timestamp when the note was last updated """ updatedAt: DateTime! } """ A vehicle registered to an owner plan """ type OwnerCar { """ Timestamp when this car was registered to the owner plan """ createdAt: DateTime! """ Unique identifier for this owner car registration """ id: ID! """ Optional nickname for this vehicle """ nickname: String """ the license plate of this vehicle """ plate: String """ the state of this vehicle """ state: String """ Timestamp when this record was last updated """ updatedAt: DateTime! } """ Full representation of an owner plan with nested relations. Use ownerPlan(id) query to fetch this for detail views. """ type OwnerPlan { """ Vehicles registered to this owner plan """ cars: [OwnerCar!]! """ City """ city: String """ Timestamp when the owner plan was created """ createdAt: DateTime! """ Description of the owner plan """ description: String """ Email address for the owner """ email: String """ When this owner plan expires (null if no expiration) """ expiresAt: DateTime """ Unique identifier for the owner plan """ id: ID! """ Name of the owner plan """ name: String! """ Phone number for the owner """ phone: String """ State """ state: String """ Street address line 1 """ street1: String """ Street address line 2 """ street2: String """ Timestamp when the owner plan was last updated """ updatedAt: DateTime! """ The wash package that this owner plan provides """ washPackage: WashPackage! """ The wash package ID that this owner plan provides """ washPackageId: ID! """ ZIP code """ zip: String } """ A wash record for an owner plan """ type OwnerVisit { """ The car """ car: OwnerCar """ Timestamp when the wash occurred """ createdAt: DateTime! """ Unique identifier for this wash record """ id: ID! """ The visit details """ visit: Visit! } type OwnerVisitsPage { """ List of owner visits in the current page """ nodes: [OwnerVisit!]! """ Pagination metadata including cursors and page position """ pageInfo: PageInfo! } type PageInfo { endCursor: String hasNextPage: Boolean! hasPreviousPage: Boolean! startCursor: String } type PaidInvoice { """ The amount available to refund in cents (total minus already-refunded credit notes) """ amountAvailableToRefund: Int! """ The billing reason for the paid invoice """ billingReason: String """ The card used to make the payment, if any """ card: Card """ The date and time the paid invoice was created """ createdAt: DateTime! """ The customer who was sold to """ customer: SimpleRollerupCustomer """ The employee who made the sale """ employee: Employee id: ID! """ The url for the invoice """ invoiceUrl: String """ Whether this invoice is a recharge (subscription_cycle billing reason) """ isRecharge: Boolean! """ Whether this invoice is an update (subscription_update billing reason) """ isUpdate: Boolean! """ The line items that were sold in the paid invoice """ lineItems: [SimplePaidInvoiceLineItem!] """ The location that the paid invoice occurred in """ location: SimpleLocation """ The charge ID associated with the paid invoice """ stripeChargeId: String """ The Stripe invoice ID associated with the paid invoice """ stripeInvoiceId: String """ The rollerup subscription ID associated with this paid invoice """ subscriptionId: String """ The total amount of the paid invoice in cents """ total: Int! """ The visit that the paid invoice occurred in """ visit: Visit } type PaidInvoicePage { nodes: [PaidInvoice!]! pageInfo: PageInfo! } input PaidInvoicesQueryInput { """ A cursor for pagination, returns items after this cursor (forward pagination) """ after: String """ A cursor for pagination, returns items before this cursor (backward pagination) """ before: String """ If provided, filter by the brand of the card """ cardBrand: String """ If provided, filter by the last 4 digits of the card """ cardLast4: String """ If provided, filter to just this customer """ customerId: String """ If provided, filter by the ID of the employee """ employeeId: ID """ If provided, filter by the end date of the paid invoices """ endDate: LocalDate """ If provided, filter by the end time of the paid invoices """ endTime: DateTime """ The number of items to return from the beginning of the list (forward pagination) """ first: Int """ Include recharges (subscription_cycle billing reason) """ includeRecharges: Boolean """ Include sales (manual and subscription_create billing reasons) """ includeSales: Boolean! = true """ Include updates (subscription_update billing reason) """ includeUpdates: Boolean """ The number of items to return from the end of the list (backward pagination) """ last: Int """ If provided, filter by the ID of the location """ locationId: ID """ If provided, filter to paid invoices at any of these locations. Combined with locationId when both are set. """ locationIds: [ID!] """ If provided, filter by the plate number of the visit """ plate: String """ If provided, filter by the start date of the paid invoices """ startDate: LocalDate """ If provided, filter by the start time of the paid invoices """ startTime: DateTime """ If provided, filter by this total amount in cents """ total: Int } """ Represents a payment method (source-agnostic) """ type PaymentMethod { """ Card brand (Visa, Mastercard, etc) if applicable """ cardBrand: String """ Last 4 digits of card if applicable """ cardLast4: String """ Timestamp when the payment method was created """ createdAt: DateTime! """ Unique identifier """ id: ID! """ Source of the payment method (stripe, internal, etc) """ source: PaymentMethodSource! """ Type of payment method (card, cash, other) """ type: String! } """ Source of the payment method (stripe, internal, etc) """ enum PaymentMethodSource { INTERNAL STRIPE } """ Phone number scalar that enforces E.164 format (e.g., +1234567890) """ scalar PhoneNumber """ A record of a plate change (car linked or unlinked from a membership) """ type PlateChange { """ Whether the car was linked or unlinked """ action: String! """ The car that was linked or unlinked """ car: Car! """ The user who made the change """ changedBy: User """ Timestamp when the change occurred """ createdAt: DateTime! """ Whether this change was exempt from plate change limits """ exempt: Boolean! """ Unique identifier """ id: ID! """ The original car that was replaced (for swaps) """ originalCar: Car } """ Input for querying plate change history """ input PlateChangeHistoryInput { """ Subscription ID to get plate change history for """ subscriptionId: String! } """ Represents a prepaid that can be redeemed for wash packages """ type Prepaid { """ Number of codes per prepaid book (null if not set) """ codesPerBook: Int """ The company this prepaid belongs to """ companyId: ID! """ Timestamp when the prepaid was created """ createdAt: DateTime! """ The employee who created this prepaid """ createdBy: Employee """ The employee who created this prepaid """ createdById: ID """ Description of what this prepaid provides """ description: String! """ Number of codes that can be included in an export (unactivated and not yet exported) """ exportableCodeCount: Int! """ List of exports for this prepaid """ exports: [SimplePrepaidExport!]! """ Unique identifier for the prepaid """ id: ID! """ Whether this prepaid was imported from Sitewatch """ importedFromSitewatch: Boolean! """ Maximum number of times this prepaid can be redeemed per prepaid code """ maxRedemptionsPerPrepaid: Int """ Human-readable name for the prepaid """ name: String! """ Timestamp when the prepaid was last updated """ updatedAt: DateTime! """ The wash package that this prepaid provides """ washPackage: WashPackage! """ The wash package that this prepaid provides """ washPackageId: ID! } """ Represents a prepaid book that contains prepaid codes """ type PrepaidBook { """ When this book was activated (null if not yet activated) """ activatedAt: DateTime """ Timestamp when the prepaid book was created """ createdAt: DateTime! """ Unique identifier for the prepaid book """ id: ID! """ The prepaid this book belongs to """ prepaid: Prepaid! """ List of prepaid codes in this book """ prepaidCodes: [PrepaidCode!]! """ The prepaid this book belongs to """ prepaidId: ID! """ Timestamp when the prepaid book was last updated """ updatedAt: DateTime! } """ Paginated result for prepaid books """ type PrepaidBookPage { """ List of prepaid books in the current page """ nodes: [PrepaidBook!]! """ Pagination metadata including cursors and page position """ pageInfo: PageInfo! } """ Pagination input for querying prepaid books. Supports both forward and backward pagination. Use 'first' and 'after' for forward pagination, or 'last' and 'before' for backward pagination. """ input PrepaidBookQueryInput { """ A cursor for pagination, returns items after this cursor (forward pagination) """ after: String """ A cursor for pagination, returns items before this cursor (backward pagination) """ before: String """ Filter by prepaid code string (returns books that contain a matching code) """ code: String """ The number of items to return from the beginning of the list (forward pagination) """ first: Int """ The number of items to return from the end of the list (backward pagination) """ last: Int """ Filter by prepaid ID """ prepaidId: ID } """ Represents a prepaid code that can be redeemed for a prepaid """ type PrepaidCode { """ When this code was activated (null if not yet activated) """ activatedAt: DateTime """ The code string that is typically scanned but can also be manually entered """ code: String! """ The company this prepaid code belongs to """ companyId: ID! """ Timestamp when the prepaid code was created """ createdAt: DateTime! """ DRB book number """ drbBook: Int """ DRB series identifier """ drbSeries: String """ DRB ticket number """ drbTicket: Int """ Unique identifier for the prepaid code """ id: ID! """ Maximum number of times this code can be redeemed """ maxRedemptions: Int """ The prepaid this code applies to """ prepaid: Prepaid! """ The prepaid book ID this code belongs to (null if not part of a book) """ prepaidBookId: ID """ The export this code was included in (null if never exported) """ prepaidExport: SimplePrepaidExport """ The prepaid this code applies to """ prepaidId: ID! """ List of redemptions for this prepaid code (limited by maxRedemptionsPerPrepaid) """ redemptions: [PrepaidCodeRedemption!]! """ Total count of redemptions for this prepaid code """ redemptionsCount: Int! """ Timestamp when the prepaid code was last updated """ updatedAt: DateTime! } """ Paginated result for prepaid codes """ type PrepaidCodePage { """ List of prepaid codes in the current page """ nodes: [PrepaidCode!]! """ Pagination metadata including cursors and page position """ pageInfo: PageInfo! } """ Pagination input for querying prepaid codes. Supports both forward and backward pagination. Use 'first' and 'after' for forward pagination, or 'last' and 'before' for backward pagination. """ input PrepaidCodeQueryInput { """ A cursor for pagination, returns items after this cursor (forward pagination) """ after: String """ A cursor for pagination, returns items before this cursor (backward pagination) """ before: String """ Filter by prepaid code string """ code: String """ The number of items to return from the beginning of the list (forward pagination) """ first: Int """ The number of items to return from the end of the list (backward pagination) """ last: Int """ Filter by prepaid book ID """ prepaidBookId: ID """ Filter by prepaid ID """ prepaidId: ID } """ Represents a redemption of a prepaid code """ type PrepaidCodeRedemption { """ Timestamp when the redemption was created """ createdAt: DateTime! """ Unique identifier for the redemption """ id: ID! """ The location where this code was redeemed """ location: Location! """ The location where this code was redeemed """ locationId: ID! """ The prepaid code that was redeemed """ prepaidCode: PrepaidCode! """ The prepaid code that was redeemed """ prepaidCodeId: ID! """ When this code was redeemed """ redeemedAt: DateTime! """ The employee who redeemed this code (null if redeemed without an employee) """ redeemedBy: Employee """ The employee who redeemed this code (null if redeemed without an employee) """ redeemedById: ID """ Timestamp when the redemption was last updated """ updatedAt: DateTime! """ The visit ID associated with this redemption (null if not associated with a visit) """ visitId: ID } """ Paginated result for prepaid code redemptions """ type PrepaidCodeRedemptionPage { """ List of redemptions in the current page """ nodes: [PrepaidCodeRedemption!]! """ Pagination metadata including cursors and page position """ pageInfo: PageInfo! } """ Pagination input for querying prepaid code redemptions. Supports both forward and backward pagination. Use 'first' and 'after' for forward pagination, or 'last' and 'before' for backward pagination. """ input PrepaidCodeRedemptionQueryInput { """ A cursor for pagination, returns items after this cursor (forward pagination) """ after: String """ A cursor for pagination, returns items before this cursor (backward pagination) """ before: String """ Filter by prepaid code string """ code: String """ The number of items to return from the beginning of the list (forward pagination) """ first: Int """ The number of items to return from the end of the list (backward pagination) """ last: Int """ Filter by prepaid ID """ prepaidId: ID } """ Paginated result for prepaids """ type PrepaidPage { """ List of prepaids in the current page """ nodes: [Prepaid!]! """ Pagination metadata including cursors and page position """ pageInfo: PageInfo! } """ Pagination input for querying prepaids. Supports both forward and backward pagination. Use 'first' and 'after' for forward pagination, or 'last' and 'before' for backward pagination. """ input PrepaidQueryInput { """ A cursor for pagination, returns items after this cursor (forward pagination) """ after: String """ A cursor for pagination, returns items before this cursor (backward pagination) """ before: String """ Filter by prepaid code string """ code: String """ The number of items to return from the beginning of the list (forward pagination) """ first: Int """ The number of items to return from the end of the list (backward pagination) """ last: Int } input PreviewMembershipCarChangeInput { """ Required when intent is `remove` or `cancel_removal`. Must be one of the membership's currently linked cars. """ carId: ID """ The kind of change to preview """ intent: MembershipCarChangeIntent! """ Membership being changed """ membershipId: ID! } """ Represents a price for a wash package with billing details """ type Price { """ Price amount in cents (e.g., 1999 = $19.99) """ amount: Int! """ Why this price was archived: USER (manually by a user), SYSTEM (automatically during archive-and-replace), or null if not archived """ archivedReason: ArchivedReason """ A schedule that describes when this price is available for purchase (null for always available) """ availabilitySchedule: Schedule """ Whether this price is currently available for selection in the POS """ availableInPos: Boolean! """ Whether this price is currently available for selection in unattended purchase flow """ availableInUnattended: Boolean! """ Whether this price is currently available for selection online """ availableOnline: Boolean! """ Billing frequency for subscription prices (null for one-time prices) """ billingFrequency: BillingFrequency """ When this price was created """ createdAt: DateTime! """ Currency code (e.g., 'USD', 'EUR') """ currency: String! """ An (optional) promotional discount that will be applied to this price at sign-up """ discount: Discount """ Operator-editable customer-facing name. When null, the UI falls back to `product.name` at render time. """ displayName: String """ Unique identifier for the price """ id: ID! """ Admin-only annotation. When set, shown as the primary label in admin tables with the resolved display name as the secondary label. """ internalName: String """ Whether this price is archived and no longer active """ isArchived: Boolean! """ Whether this is a default price for the product (automatically assigned to new locations) """ isDefault: Boolean! """ Display name for this price """ name: String! """ The pricing profile this price applies to """ pricingProfile: PricingProfile @deprecated(reason: "Use pricingProfiles instead") """ The pricing profiles this price applies to """ pricingProfiles: [PricingProfile!]! """ The product this price belongs to (null for v1 pricing-profile prices). Lightweight projection — full `Product` is available via a separate `product(id:)` query. """ product: SimpleProduct """ Sort order for displaying the price in the POS """ sortOrder: Int! """ Pricing tiers for graduated pricing (empty for flat-rate prices) """ tiers: [PriceTier!]! """ Duration of the free trial period (used with trialUnits) """ trialDuration: Int """ Units for the trial duration (DAYS, WEEKS, or MONTHS) """ trialUnits: TrialUnits """ When this price was last updated """ updatedAt: DateTime! """ The wash package this price applies to (null for v2 product-catalog prices) """ washPackage: WashPackage } """ A pricing tier for graduated pricing. Each tier defines a unit price that applies starting at a given quantity. """ type PriceTier { """ The quantity at which this tier begins """ fromQuantity: Int! """ Unique identifier for the tier """ id: ID! """ Price per unit in cents for this tier """ unitAmount: Int! } """ Represents a Pricing profile in the system """ type PricingProfile { """ Timestamp when the pricing profile was created """ createdAt: DateTime! """ Pricing profile description """ description: String """ Unique Pricing profile identifier """ id: ID! """ Locations associated with the pricing profile """ locations: [Location!]! """ Pricing profile name """ name: String! """ Prices associated with the pricing profile """ prices: [Price!]! """ Timestamp when the pricing profile was last updated """ updatedAt: DateTime! } """ Product type discriminator. """ enum ProductType { GIFT_CARD PREPAID_WASH_BOOK RETAIL_WASH SUBSCRIPTION } type Query { car(id: ID!): Car cars(input: CarsQueryInput): CarPage! """ Get a single Rollerup customer by ID """ customer( """ Customer ID """ id: ID! ): RollerupCustomer @authz(permission: "customers:view") """ Search for Rollerup customers using flexible filters. Supports searching by name, email, phone, license plate, and last four digits of payment method. Results are paginated using cursor-based pagination. """ customers( """ Search parameters and pagination options """ input: CustomersInput! ): CustomersPage! @authz(permission: "customers:view") """ Retrieve a single discount by its unique ID """ discount(id: ID!): Discount! @authz(permission: "discounts:view") """ Query discounts with pagination support. Returns a paginated list of discounts. Supports optional filtering by name, active status, and expiration date range. """ discounts(input: DiscountQueryInput): DiscountPage! @authz(permission: "discounts:view") """ Get an employee by their unique identifier """ employee(id: ID!): Employee! """ Get a list of employees """ employees(input: EmployeesInput): EmployeesPage! group(id: ID!): Group groups: [Group!]! isCarActive(plate: String!, state: String!): Boolean! """ Query owner plans with pagination support. Returns a paginated list of simple owner plans without nested relations to avoid N+1 queries. """ listOwnerPlans(input: ListOwnerPlansInput): SimpleOwnerPlansPage! @authz(permission: "owner-plans:view") listOwnerVisits(input: ListOwnerVisitsInput!): OwnerVisitsPage! @authz(permission: "owner-plans:view") """ Get a location by ID. Requires 'locations:view' permission """ location(id: ID!): Location @authz(permission: "locations:view") """ Query locations with pagination. Requires the 'locations:view' permission """ locations( """ Pagination parameters for the location query """ input: LocationQueryInput ): LocationPage! @authz(permission: "locations:view") membershipCars(membershipId: ID!): [MembershipCar!]! @authz(permission: "subscriptions:manage") """ Retrieve a single owner plan by its unique ID. Returns full details including nested relations (wash package, cars, wash history). """ ownerPlan(id: ID!): OwnerPlan! @authz(permission: "owner-plans:view") """ Get a single paid invoice by its ID """ paidInvoice(id: ID!): PaidInvoice! @authz(permission: "sales:view") """ Get a paginated list of paid invoices, sorted in reverse chronological order """ paidInvoices(input: PaidInvoicesQueryInput): PaidInvoicePage! @authz(permission: "sales:view") """ Get plate change history for a subscription """ plateChangeHistory(input: PlateChangeHistoryInput!): [PlateChange!]! @authz(permission: "customers:view") """ Retrieve a single prepaid by its unique ID """ prepaid(id: ID!): Prepaid! @authz(permission: "prepaids:view") """ Query prepaid books with pagination support. Returns a paginated list of prepaid books """ prepaidBooks(input: PrepaidBookQueryInput): PrepaidBookPage! @authz(permission: "prepaids:view") """ Query prepaid code redemptions with pagination support. Returns a paginated list of redemptions """ prepaidCodeRedemptions(input: PrepaidCodeRedemptionQueryInput): PrepaidCodeRedemptionPage! @authz(permission: "prepaids:view") """ Query prepaid codes with pagination support. Returns a paginated list of prepaid codes """ prepaidCodes(input: PrepaidCodeQueryInput): PrepaidCodePage! @authz(permission: "prepaids:view") """ Returns a signed URL to download a prepaid export file. """ prepaidExportDownloadUrl(prepaidExportId: ID!): String! @authz(permission: "prepaids:view") """ Query prepaids with pagination support. Returns a paginated list of prepaids """ prepaids(input: PrepaidQueryInput): PrepaidPage! @authz(permission: "prepaids:view") """ Preview the invoice impact of adding, removing, or cancelling the removal of a car on a membership. Does not mutate any state. """ previewMembershipCarChange(input: PreviewMembershipCarChangeInput!): MembershipCarChangePreview! @authz(permission: "subscriptions:manage") """ Get a Stripe account by ID. Requires the 'stripe-accounts:view' permission """ stripeAccount(id: String!): StripeAccount @authz(permission: "stripe-accounts:view") """ Query Stripe accounts with pagination. Requires the 'stripe-accounts:view' permission """ stripeAccounts( """ Pagination parameters for the Stripe accounts query """ input: StripeAccountQueryInput ): StripeAccountPage! @authz(permission: "stripe-accounts:view") """ Get a user by ID """ user(id: ID!): User @authz(permission: "users:view") """ Query users with pagination. Requires 'users:view' permission """ users( """ Pagination parameters for the user query """ input: UserQueryInput ): UserPage! @authz(permission: "users:view") """ Get the currently authenticated user """ viewer: User """ Get a single visit by ID """ visit(id: ID!): Visit! """ List all visits in reverse chronological order """ visits(input: VisitsInput): VisitsPage! """ Get a Wash package by ID. Requires the 'wash-packages:view' permission """ washPackage(id: ID!): WashPackage! @authz(permission: "wash-packages:view") """ Query Wash packages with pagination. Requires the 'wash-packages:view' permission """ washPackages: [WashPackage!]! @authz(permission: "wash-packages:view") } """ RFC-5545 compliant recurrence rule scalar """ scalar RRule input RemoveCarFromMembershipInput { carId: ID! membershipId: ID! } """ Represents a Rollerup customer with their subscriptions """ type RollerupCustomer { """ City """ city: String """ Country """ country: String """ Timestamp when the customer was created """ createdAt: DateTime! """ Customer's email address """ email: EmailAddress """ Unique identifier """ id: ID! """ Whether the customer is an active member. True if the customer has at least one car assigned to a membership (i.e. a membership_car exists). This is independent of subscription billing status. """ isActiveMember: Boolean! """ Customer's full name """ name: String """ List of active (non-archived) notes for this customer """ notes: [Note!]! @authz(permission: "customers:view") """ Customer's phone number in E.164 format """ phone: PhoneNumber """ State """ state: String """ Street address line 1 """ street1: String """ Street address line 2 """ street2: String """ List of subscriptions for this customer """ subscriptions: [RollerupSubscription!]! """ Timestamp when the customer was last updated """ updatedAt: DateTime! """ ZIP/postal code """ zip: String } type RollerupSubscription { """ Latest billing provider customer ID (e.g., Stripe 'cus_...') associated with this subscription """ billingCustomerId: String """ Billing frequency """ billingFrequency: String! """ Latest billing provider subscription ID (e.g., Stripe 'sub_...') associated with this subscription """ billingSubscriptionId: String """ Timestamp when the subscription is scheduled to be cancelled """ cancelAt: DateTime """ Timestamp when the subscription was cancelled """ cancelledAt: DateTime """ Timestamp when the subscription was created """ createdAt: DateTime! """ Current period end """ currentPeriodEnd: DateTime! """ Current period start """ currentPeriodStart: DateTime! """ Customer for this subscription """ customer: RollerupCustomer """ Customer ID """ customerId: String """ Default payment method for this subscription """ defaultPaymentMethod: PaymentMethod """ Subscription ID """ id: String! """ Current location for this subscription """ location: Location """ Current location ID associated with this subscription """ locationId: String """ Memberships belonging to this subscription """ memberships: [Membership!]! """ Location where this subscription was sold """ soldAtLocation: SimpleLocation """ Location ID where this subscription was sold """ soldAtLocationId: String """ Employee who sold this subscription """ soldBy: User """ Employee ID who sold this subscription """ soldById: String """ Status of this subscription """ status: String! } """ A schedule defining availability of a resource (e.g. a price or discount). All date/time values in a Schedule follow a floating-time convention: they are serialized as UTC but should be interpreted as local times relative to the context in which the schedule is evaluated (typically the location's time zone). For example, a startDate of 2026-02-17T00:00:00Z means "midnight local time on Feb 17", not "midnight UTC". """ type Schedule { """ Duration of each recurring event in minutes (required if rrule is present). For example, a recurring event from 8am-9am local time can be represented by: { "rrule": "RRULE:FREQ=DAILY;BYHOUR=8;BYMINUTE=0;BYSECOND=0", "durationMinutes": 60 } """ durationMinutes: Int """ When the schedule expires (null means no expiration). Stored as UTC but interpreted as a floating local time — see the Schedule type description. """ endDate: DateTime """ Recurrence pattern (null means no recurrence). This follows the RRULE property format from iCalendar (RFC-5545). Note that there are redundant degrees of freedom between the rrule's UNTIL and COUNT rules and the endDate property on the Schedule type. In practice, the value resulting in the soonest expiration will take effect. """ rrule: RRule """ When the resource becomes active (null means active from when the schedule is created). Stored as UTC but interpreted as a floating local time — see the Schedule type description. """ startDate: DateTime } """ Input for creating a new Schedule. All DateTime values follow the same floating-time convention described on the Schedule type. For fixed schedules: one or both of startDate and endDate must be set. For recurring schedules: rrule and durationMinutes must be set. """ input ScheduleInput { """ Duration of each recurring event in minutes (required if rrule is present). For example, a recurring event from 8am-9am local time can be represented by: { "rrule": "RRULE:FREQ=DAILY;BYHOUR=8;BYMINUTE=0;BYSECOND=0", "durationMinutes": 60 } """ durationMinutes: Int """ When the schedule expires (null means no expiration). Stored as UTC but interpreted as a floating local time. """ endDate: DateTime """ Recurrence pattern (null means no recurrence). This follows the RRULE property format from iCalendar (RFC-5545). Note that there are redundant degrees of freedom between the rrule's UNTIL and COUNT rules and the endDate property on the Schedule type. In practice, the value resulting in the soonest expiration will take effect. Additional iCalendar properties (such as DTSTART) are not supported; to restrict the start date of a recurring event, use the startDate property. """ rrule: RRule """ When the resource becomes active (null means active from when the schedule is created). Stored as UTC but interpreted as a floating local time. """ startDate: DateTime } """ Simplified company type with minimal fields """ type SimpleCompany { """ Client-visible feature flags enabled for this company """ features: [String!]! """ Unique identifier for the company """ id: ID! """ Maximum number of cars per family membership """ maxCarsPerFamilyMembership: Int """ Company name """ name: String! """ Company Slug """ slug: String! """ Company Timezone """ timezone: String! } """ Represents a location in the system with only primitives and no sensitive settings """ type SimpleLocation { city: String createdAt: DateTime! externalId: String id: ID! isVirtual: Boolean! name: String! shortName: String state: USStateCode street: String timezone: String! updatedAt: DateTime! zip: USPostalCode } """ Simple flat representation of an owner plan without nested relations. """ type SimpleOwnerPlan { """ City """ city: String """ Timestamp when the owner plan was created """ createdAt: DateTime! """ Description of the owner plan """ description: String """ Email address for the owner """ email: String """ When this owner plan expires (null if no expiration) """ expiresAt: DateTime """ Unique identifier for the owner plan """ id: ID! """ Name of the owner plan """ name: String! """ Phone number for the owner """ phone: String """ State """ state: String """ Street address line 1 """ street1: String """ Street address line 2 """ street2: String """ Timestamp when the owner plan was last updated """ updatedAt: DateTime! """ The wash package ID that this owner plan provides """ washPackageId: ID! """ ZIP code """ zip: String } """ Paginated result for simple owner plan queries """ type SimpleOwnerPlansPage { """ List of owner plans in the current page """ nodes: [SimpleOwnerPlan!]! """ Pagination metadata including cursors and page position """ pageInfo: PageInfo! } type SimplePaidInvoiceLineItem { id: ID! """ The price of the product that was sold """ price: Int """ The name of the product that was sold (from Stripe at sync time) """ productName: String """ The quantity of the product that was sold """ quantity: Int } """ Minimal prepaid export fields for list display (e.g. on Prepaid.exports). """ type SimplePrepaidExport { """ When this export was created """ exportedAt: DateTime! """ The employee who created this export """ exportedBy: Employee """ Number of codes included in this export """ exportedCodeCount: Int! """ Unique identifier for the export """ id: ID! } """ Lightweight projection of Product — scalar fields only, no relational joins or computed aggregates. Used by list payloads like `Price.product` so paginated responses don't fan out into per-row `activeLocationCount` and `productPrices` resolutions. """ type SimpleProduct { """ Unique identifier for the product """ id: ID! """ Whether this product is archived. Mirrors `Product.isArchived` — lets list payloads render an 'on archived product' indicator without a second per-row query. """ isArchived: Boolean! """ Human-readable name for the product """ name: String! """ The kind of product """ productType: ProductType! } type SimpleRollerupCustomer { city: String country: String createdAt: DateTime! email: EmailAddress id: ID! name: String phone: PhoneNumber state: String street1: String street2: String updatedAt: DateTime! zip: String } """ Represents a Stripe account in the system """ type StripeAccount { """ City """ city: String """ The company this Stripe account belongs to """ companyId: ID """ Timestamp when the account was created """ createdAt: DateTime! """ Unique Stripe account identifier """ id: String! """ Account name """ name: String """ Stripe account requirements for onboarding """ requirements: StripeAccountRequirements """ State """ state: USStateCode """ Street address """ street: String """ Timestamp when the account was last updated """ updatedAt: DateTime! """ ZIP or postal code """ zip: USPostalCode } """ Paginated result for Stripe account queries """ type StripeAccountPage { """ List of Stripe accounts in the current page """ nodes: [StripeAccount!]! """ Pagination metadata including cursors and page position """ pageInfo: PageInfo! } """ Pagination input for querying Stripe accounts. Supports both forward and backward pagination. Use 'first' and 'after' for forward pagination, or 'last' and 'before' for backward pagination. """ input StripeAccountQueryInput { """ A cursor for pagination, returns items after this cursor (forward pagination) """ after: String """ A cursor for pagination, returns items before this cursor (backward pagination) """ before: String """ The number of items to return from the beginning of the list (forward pagination) """ first: Int """ The number of items to return from the end of the list (backward pagination) """ last: Int } """ Stripe account requirements for onboarding and compliance """ type StripeAccountRequirements { """ Currently due requirements """ currentlyDue: [String!] """ Disabled reason """ disabledReason: String """ Eventually due requirements """ eventuallyDue: [String!] """ Past due requirements """ pastDue: [String!] """ Pending verification requirements """ pendingVerification: [String!] } """ Represents a Stripe customer in the system """ type StripeCustomer { """ The company this Stripe customer belongs to """ companyId: ID! """ Timestamp when the customer was created """ createdAt: DateTime! """ Default payment method ID """ defaultPaymentMethodId: String """ Customer description """ description: String """ Customer email address """ email: String """ Unique Stripe customer identifier """ id: String! """ Whether the customer is deleted """ isDeleted: Boolean! """ Whether the phone number is valid """ isPhoneValid: Boolean! """ Customer memberships with detailed information """ memberships: [StripeCustomerMembership!]! """ Customer name """ name: String """ Customer phone number """ phone: String """ Customer phone number in E.164 format """ phoneE164: String """ Customer referral code """ referralCode: String! """ Timestamp when the customer was last updated """ updatedAt: DateTime! } """ Represents a customer membership with subscription details """ type StripeCustomerMembership { """ Ban ID if plate is banned """ banId: String """ Cancel at period end """ cancelAtPeriodEnd: Boolean! """ Canceled at timestamp """ canceledAt: DateTime """ Company ID """ companyId: String! """ Created timestamp """ createdAt: DateTime! """ Current period end """ currentPeriodEnd: DateTime """ Current period start """ currentPeriodStart: DateTime """ Product description """ description: String """ Whether the plate is banned """ hasBan: Boolean! """ Subscription ID """ id: String! """ Product name """ name: String """ Recurring interval """ recurringInterval: String """ Recurring interval count """ recurringIntervalCount: Int """ Sold by employee badge """ soldByBadge: String """ Sold by employee name """ soldByName: String """ Subscription status """ status: String! """ Stripe account ID """ stripeAccountId: String! """ Customer ID """ stripeCustomerId: String! """ Updated timestamp """ updatedAt: DateTime! } enum SubscriptionChangeType { downgrade upgrade } """ Trial period units for free trial durations """ enum TrialUnits { """ Duration specified in days """ DAYS """ Duration specified in months """ MONTHS """ Duration specified in weeks """ WEEKS } """ Postal code scalar that enforces valid US postal code format """ scalar USPostalCode """ State code scalar that enforces valid 2-character USPS state code format """ scalar USStateCode """ Input for updating a Rollerup customer. Only fields provided are updated. """ input UpdateCustomerInput { """ Customer email """ email: EmailAddress """ Customer ID """ id: ID! """ Customer name """ name: String """ Customer phone """ phone: PhoneNumber } """ Input for updating a car on an owner plan """ input UpdateOwnerPlanCarInput { """ The ID of the owner plan car to update (required) """ id: ID! """ Nickname for this vehicle """ nickname: String """ License plate number """ plate: String """ State/region of registration """ state: String } """ Input for updating an existing owner plan. All fields except 'id' are optional. """ input UpdateOwnerPlanInput { """ City """ city: String """ Description of the owner plan """ description: String """ Email address for the owner """ email: String """ When this owner plan expires (null for no expiration) """ expiresAt: DateTime """ The ID of the owner plan to update (required) """ id: ID! """ Name of the owner plan """ name: String """ Phone number for the owner """ phone: String """ State """ state: String """ Street address line 1 """ street1: String """ Street address line 2 """ street2: String """ The wash package ID that this owner plan provides """ washPackageId: ID """ ZIP code """ zip: String } """ Input for updating an existing user. All fields except 'id' are optional """ input UpdateUserInput { """ Update the user's email address (must be valid email format) """ email: EmailAddress """ Update the external system identifier """ externalId: String """ Update the list of group IDs the user belongs to """ groupIds: [String!] """ The unique identifier of the user to update """ id: ID! """ Update the user's full name """ name: String """ Update the user's phone number (must be valid phone format) """ phone: PhoneNumber """ If true, generates a new temporary password that must be changed on next login """ resetPassword: Boolean """ Update the username for authentication. If username was not set before, a temporary password will be returned in the response """ username: String } """ Input for updating an existing wash package. All fields except 'id' are optional. """ input UpdateWashPackageInput { """ An optional detailed description of the package """ description: String """ An optional reference ID to link this Rollerup package to a system external to Rollerup """ externalId: String """ The ID of the Wash package to update """ id: ID! """ A friendly name for the package """ name: String } """ Represents a user in the system """ type User { """ The company this user belongs to """ company: SimpleCompany! """ Timestamp when the user was created """ createdAt: DateTime! """ Email address of the user """ email: EmailAddress """ External system identifier for the user """ externalId: String """ Groups this user belongs to """ groups: [Group!]! """ Unique identifier for the user """ id: ID! """ Indicates if the user is active and able to authenticate. If not can be reactivated with 'reactivateUser' mutation """ isActive: Boolean! """ Full name of the user """ name: String """ List of permissions granted to this user (derived from groups and direct assignments) """ permissions: [String!]! """ Phone number of the user """ phone: PhoneNumber """ Timestamp when the user was last updated """ updatedAt: DateTime! """ Username used for authentication """ username: String } """ Paginated result for user queries """ type UserPage { """ List of users in the current page """ nodes: [User!]! """ Pagination metadata including cursors and page position """ pageInfo: PageInfo! } """ Pagination input for querying users. Supports both forward and backward pagination. Use 'first' and 'after' for forward pagination, or 'last' and 'before' for backward pagination. """ input UserQueryInput { """ A cursor for pagination, returns items after this cursor (forward pagination) """ after: String """ A cursor for pagination, returns items before this cursor (backward pagination) """ before: String """ if provided, filter users by email """ email: String """ The number of items to return from the beginning of the list (forward pagination) """ first: Int """ When true, include inactive users in results. Defaults to false (only active users returned). """ includeInactive: Boolean = false """ The number of items to return from the end of the list (backward pagination) """ last: Int """ if provided, filter users by name """ name: String """ if provided, filter users by phone """ phone: String """ if provided, filter users by username """ username: String } """ Represents a visit to a location """ type Visit { """ The timestamp when the visit was created """ createdAt: DateTime! """ The employee who processed the visit """ employee: Employee """ The unique identifier for the visit """ id: ID! """ The URL of the image of the car. This is a signed URL for our object storage that will expire. """ imageUrl: String """ Whether or not this is a member in an external system. Primarily useful during onboarding. Will always be false if visit type is not 'member'. """ isExternalMember: Boolean! """ Whether or not this visit included a membership signup or wash purchase. """ isSale: Boolean! """ The lane ID where the visit occurred """ laneId: String """ Whether the LPR data has been overridden """ lprOverridden: Boolean """ The plate as seen by LPR """ lprPlate: String """ The state as seen by LPR """ lprState: String """ The plate number of the vehicle """ plate: String """ The URL of the plate image. This is a signed URL for our object storage that will expire. """ plateImageUrl: String """ The RFID tag of the vehicle """ rfidTag: String """ The state of the vehicle """ state: String """ The status of the visit """ status: String! """ The Stripe subscription ID for the visit """ stripeSubscriptionId: String @deprecated(reason: "Will be replaced with Membership IDs") """ The total time the visit took in seconds. """ timeTotal: Float """ The time the visit spent waiting for the attendant in seconds. """ timeWaitingForAttendant: Float """ The time the visit spent waiting for the gate to open in seconds. """ timeWaitingForGate: Float """ The time the visit spent with the attendant in seconds. """ timeWithAttendant: Float """ The timestamp when the visit was last updated """ updatedAt: DateTime! """ The type of visit """ visitType: String """ The wash package for the visit """ washPackage: WashPackage } """ Options for setting pagination and filtering for the visits query """ input VisitsInput { """ A cursor for pagination, returns items after this cursor (forward pagination) """ after: String """ A cursor for pagination, returns items before this cursor (backward pagination) """ before: String """ If set will only return visits matching this car ID """ carId: String """ The number of items to return from the beginning of the list (forward pagination) """ first: Int """ If set will only return visits that are sales """ isSale: Boolean """ The number of items to return from the end of the list (backward pagination) """ last: Int locationId: String """ If set will only return visits matching this plate number (case insensitive) """ plate: String """ If set will only return visits matching this state (case insensitive) """ state: String """ If set will only return visits matching this status (case insensitive) """ status: String """ If set will only return visits matching this visit type (case insensitive) """ visitType: String } """ Paginated result for visit queries """ type VisitsPage { """ List of visits in the current page """ nodes: [Visit!]! """ Pagination metadata including cursors and page position """ pageInfo: PageInfo! } """ Represents a Wash package in Rollerup """ type WashPackage { """ Timestamp when the package was created """ createdAt: DateTime! """ An optional detailed description of the package """ description: String """ An optional reference ID to link this Rollerup package to a system external to Rollerup """ externalId: String """ Unique Wash package identifier """ id: ID! """ A friendly name for the package """ name: String! """ Timestamp when the package was last updated """ updatedAt: DateTime! }