# RentalTide Documentation — Full Content > Auto-generated single-file mirror of every page on docs.rentaltide.com. > Intended for LLM ingestion. For a structured site index see /llms.txt. > Generated: 2026-05-18T20:18:22.833Z --- # RentalTide Documentation Source: https://docs.rentaltide.com/ > Everything you need to manage your watercraft rental and marina business # RentalTide Documentation Welcome to the RentalTide documentation. Here you will find everything you need to set up, run, and grow your watercraft rental or marina business. Whether you are configuring your first location or integrating with the API, these guides walk you through every feature step by step. {% callout type="tip" title="New to RentalTide?" %} Start with the [quick start guide](/getting-started/) to get your first location accepting bookings in under 15 minutes. {% /callout %} --- ## Explore the platform {% cardGroup cols=3 %} {% card title="Core" href="/core/" /%} {% card title="Operations" href="/operations/" /%} {% card title="Point of Sale" href="/pos/" /%} {% card title="Fleet & Business" href="/fleet/" /%} {% card title="Staffing" href="/staffing/" /%} {% card title="Marina" href="/marina/" /%} {% card title="Marketing" href="/marketing/" /%} {% card title="Reporting" href="/reporting/" /%} {% card title="Admin" href="/admin/" /%} {% card title="Customer-Facing" href="/public/" /%} {% card title="API Reference" href="/api-reference/" /%} {% /cardGroup %} --- ## Platform highlights **All-in-one operations.** Manage bookings, walk-ups, manifests, and real-time asset tracking from a single dashboard. **Built-in point of sale.** Ring up retail, snack bar, and rental transactions with integrated Stripe terminals. **Marina management.** Assign slips, track contracts, handle haul services, and bill for meter readings. **Embeddable booking widget.** Drop a booking experience directly onto your website with one script tag. **Reporting and ledger.** Every dollar flows through a double-entry general ledger with real-time financial reports. **API-first.** Everything the dashboard can do is available through the REST API for custom integrations. --- # Admin Source: https://docs.rentaltide.com/admin/ > Staff management, integrations, subscription, storage, data import, and partner access Account-level settings and tools for managing your team, integrations, billing, and data. {% cardGroup cols=2 %} {% card title="Staff management" href="/admin/staff/" /%} {% card title="App store" href="/admin/app-store/" /%} {% card title="Subscription" href="/admin/subscription/" /%} {% card title="Storage" href="/admin/storage/" /%} {% card title="Import" href="/admin/import/" /%} {% card title="Partner access" href="/admin/partner-access/" /%} {% /cardGroup %} --- # App store Source: https://docs.rentaltide.com/admin/app-store/ > Browse, install, and manage integrations across analytics, accounting, marketing, security, and developer tools The app store is your central hub for connecting RentalTide to third-party services and enabling add-on products. Browse available integrations, install them in a few clicks, and manage everything from one place. Navigate to **Admin > App Store** in the sidebar. ## Page layout The app store has two main views: - **My Apps** -- shows all currently installed integrations with their connection status, setup date, and quick-access configuration buttons. - **Discover** -- browse all available integrations organized by category, with search and filtering. ## Add-on products RentalTide offers modular product add-ons that unlock entire feature sets when enabled: | Product | Features unlocked | | ---------------- | ----------------------------------------------------------------------------------------------------------- | | Staffing | Staff scheduling, timesheets, clock in/out, shift swaps, time-off management, GPS tracking, staff portal | | Point of Sale | Product catalog, transaction processing, till closing, invoicing, inventory audit, stock transfers | | Slips and Marina | Slip inventory, reservations, waitlist, guest access, haul services, contracts, meter readings, marina maps | Each product controls which sidebar items are visible. Disabling a product hides the corresponding navigation items for all users. ## Integration categories | Category | Examples | | ------------------------- | ------------------------------------------------------------------- | | Website | Hosted Website builder, WordPress Plugin | | Analytics | Google Tags (GTM/GA4), AI Business Audit | | Accounting | Xero, QuickBooks, Wave Accounting | | Marketing | Meta Conversion API, TikTok Ads Pixel, Mailchimp | | Reviews and Reputation | Google Reviews, TripAdvisor Reviews | | Communication | WhatsApp Business | | Calendar | Google Calendar | | Security and Verification | Stripe Identity, Solink video surveillance | | Inspection and AI | AI Receipt Validation | | Automation | Webhooks, Zapier | | Developer Tools | API Key, Custom Code Block | | OTAs and Marketplaces | Viator, Google Things to Do, LetsBatch, WetRentals | | Navigation and Safety | Nautras navigation | | Insurance | Buoy Insurance | | E-commerce | Gift Cards, Memberships, Loyalty, Referral Program | | Operations | Self-Service Check-In, VQuip fleet inspection, HighKey social media | | CRM | SignlOS customer engagement | ## Installing an integration 1. Navigate to the **Discover** tab or use the search bar to find an integration. 2. Click the app card to view its details, features, pricing, and required permissions. 3. Click **Install** or **Connect**. 4. Complete the authorization flow -- this varies by integration: - **OAuth integrations** (Google Calendar, Xero, QuickBooks, Wave) redirect you to the provider to authorize access. - **API key integrations** (Meta Conversion API, TikTok Pixel, WhatsApp) require you to enter credentials from the provider's dashboard. - **One-click integrations** (Google Tags, Webhooks, Custom Code) are configured directly in RentalTide. 5. The app appears in **My Apps** once connected. ## Pricing Integrations have different pricing models: | Pricing type | Examples | | ------------ | ------------------------------------------------------------------------------------ | | Free | Google Calendar, Google Tags, WordPress, Webhooks, Meta Conversion API, TikTok Pixel | | Per-use | AI Receipt Validation ($0.10/receipt), Stripe Identity ($2/verification) | | One-time | AI Business Audit ($4.99) | | Monthly | Solink (from $150/month) | | Per-booking | Buoy Insurance (from $2.99/booking) | ## API keys The API Key integration lets you access RentalTide data programmatically. Generate keys from the API Key app card. Keys are scoped to your account and rate-limited. Full API documentation is available at `https://public.api.rentaltide.com/`. ## Custom code The Custom Code Block integration lets you inject custom HTML, CSS, and JavaScript into your booking pages: - **Header code** -- injected into the page `` (useful for analytics scripts, chat widgets) - **Footer code** -- injected before the closing `` tag - **Custom CSS** -- additional stylesheets applied to your booking pages ## Webhooks Configure HTTP webhook endpoints to receive real-time notifications for events including: - Booking created, updated, or cancelled - Calendar sync updates Webhooks send POST requests with JSON payloads to your specified URL. ## Accounting integrations Xero, QuickBooks, and Wave integrations support: - Automatic transaction sync and daily sales invoice creation - GL code mapping between RentalTide ledger codes and your chart of accounts - Bank account integration - OAuth token management (tokens refresh automatically; Xero tokens expire after 60 days of inactivity) {% callout type="tip" %} All OAuth integrations use secure authorization -- RentalTide never stores your third-party passwords. Review the permissions each app requests before installing. Uninstall apps you no longer use to keep your account clean. Some integrations (like Google Calendar) are per-operator, meaning each staff member can connect their own calendar. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **App not connecting** -- Try uninstalling and reinstalling the integration. Make sure you complete the full authorization flow in the popup window. **OAuth token expired** -- For Xero and QuickBooks, reconnect from the My Apps view. Tokens expire if not refreshed within the provider's window (60 days for Xero). **App installed but not working** -- Some integrations require additional configuration after installation (API keys, webhook URLs, GL code mapping). Check the app's settings panel in My Apps. **Webhook not firing** -- Verify the endpoint URL is correct and publicly accessible. Check that the events you want are enabled in the webhook configuration. {% /callout %} --- # Import Source: https://docs.rentaltide.com/admin/import/ > Import data from FareHarbor, Rezdy, or CSV files using a guided six-step wizard The import tool walks you through migrating data from another platform into RentalTide with a six-step wizard. Navigate to **Admin > Import** in the sidebar. ## Supported sources | Source | Connection method | Data types | | ------------------ | ------------------ | ------------------------------------------ | | FareHarbor | CSV file upload | Bookings, customers, gift cards, inventory | | Rezdy | API key connection | Bookings, customers, products, vouchers | | PeekPro | Coming soon | -- | | Checkfront | Coming soon | -- | | Generic CSV | CSV file upload | Customers, bookings | | Historical Renters | CSV file upload | Customer records (simplified flow) | ## Import steps ### Step 1: Select Source Choose the platform or file type you are importing from. Click a source card to select it. If you select **Historical Renters**, the wizard switches to a simplified upload flow that bypasses the standard six-step process. ### Step 2: Connect or Upload The connection method depends on your selected source: - **FareHarbor** -- Upload one or more CSV files exported from FareHarbor. Files are auto-detected as bookings, contacts, items, or gift cards based on their column headers. - **Rezdy** -- Enter your Rezdy API key and click **Connect**. The system fetches your products, booking count, customer count, and voucher count directly from the Rezdy API. - **Generic CSV** -- Upload CSV files and tag each as bookings or contacts. ### Step 3: Configure 1. **Select the target location** -- choose which RentalTide location the imported data should be associated with. 2. **Choose data types** to import: - Renters (customer records) - Inventory - Pricing - Bookings - Gift cards 3. **Map inventory items** -- for FareHarbor and Rezdy imports, each unique product/item name from the source must be mapped to an existing RentalTide inventory item. The wizard lists all unique items detected and provides a dropdown to select the corresponding RentalTide asset. All items must be mapped before you can proceed (when booking import is selected). ### Step 4: Preview Click **Generate Preview** to analyze the uploaded data without importing it. The preview shows: - Total counts of renters, inventory items, bookings, and gift cards that will be imported - Sample records from each category so you can verify the data looks correct For Rezdy, the preview is generated from the connected API rather than uploaded files. ### Step 5: Import Click **Start Import** to begin the import process. The import runs in the background and shows real-time progress: - Current phase (e.g., importing renters, importing bookings) - Progress bar with completed/total counts and percentage - Any errors encountered during import You can navigate away from the page -- the import continues in the background and you can check back later. ### Step 6: Complete The completion step shows the final results: - Number of renters, inventory items, bookings, and gift cards imported - Number of renters matched to existing records (de-duplicated by email) - Any errors that occurred, with details and timestamps ## Import options | Option | Default | Description | | ----------------- | ------- | ------------------------------------- | | Import Renters | On | Import customer records | | Import Inventory | On | Import fleet/product items | | Import Pricing | On | Import pricing data | | Import Bookings | On | Import booking/reservation records | | Import Gift Cards | On | Import gift card balances and codes | | Skip Duplicates | On | De-duplicate renters by email address | ## Inventory mapping During FareHarbor and Rezdy imports, you must map each source product name to an existing RentalTide inventory item. The mapper shows: - All unique product/item names detected in the source data - A dropdown for each item to select the corresponding RentalTide inventory asset The import will not proceed until all items are mapped when booking import is enabled. {% callout type="tip" %} Always review the preview step before starting the import. Large imports run in the background -- you can navigate away and check back later. Keep a backup of your original CSV files. The import handles duplicate detection by email address. Create your inventory items in RentalTide before starting the import so they are available in the mapping step. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Import failed** -- Check the error details in the completion step. Common causes are incorrect file format, missing required columns, or network issues during API-based imports. **Duplicate records** -- The importer de-duplicates by email address. If you see duplicates after import, use the merge tool in the Customers page to combine them. **FareHarbor CSV format issues** -- FareHarbor CSVs sometimes have a title row before the header row. The importer automatically detects and skips this row. Ensure the "Item" column is present in booking CSVs. **Rezdy connection failed** -- Verify your API key is correct and has not expired. Check that your Rezdy account has API access enabled. **Items not mapping** -- Make sure you have created the corresponding inventory items in RentalTide before starting the import. The mapper only shows existing RentalTide assets. {% /callout %} --- # Partner access Source: https://docs.rentaltide.com/admin/partner-access/ > Manage third-party partner access requests, approve or deny impersonation, and audit session history The partner access page lets you control when third-party partners (such as support agents, consultants, or resellers) can access your account. Review requests, grant time-limited access, and audit everything they do. Navigate to **Admin > Partner Access** in the sidebar. ## Customer ID Your Customer ID is displayed at the top of the page. Share this ID with partners who need to request access to your account. Partners use this ID to initiate an access request through the RentalTide partner portal. ## Tabs | Tab | Description | | --------------------- | ---------------------------------------------------------------------------------------------------------- | | Pending Requests | Partner access requests awaiting your approval. Shows the count of pending requests in the tab label. | | Active Access | Partners currently authorized to access your account. Shows the count of active partners in the tab label. | | Impersonation History | Audit log of all past and current partner sessions. | ## Access levels | Level | Badge | Description | | -------- | --------------- | ------------------------------------------------- | | Partner | Primary badge | Full partner access with configurable permissions | | Referral | Secondary badge | Referral-level access with limited scope | Each access request also specifies whether impersonation is allowed. Impersonation lets the partner act as your account for support and troubleshooting purposes. ## Approving a request 1. Navigate to the **Pending Requests** tab. 2. Review the partner's name, email, company, access level, and whether impersonation is requested. 3. Click **Approve** to grant access. 4. Confirm the approval in the dialog that describes the scope of access being granted. Approved partners receive time-limited, scoped access to the areas you authorized. ## Denying a request 1. Click **Deny** on the pending request. 2. Optionally enter a reason for the denial in the text field. 3. Click **Deny** to reject the request. The partner is notified of the denial. The denial reason is recorded for your reference. ## Revoking active access From the **Active Access** tab, click **Revoke** on any partner. Confirm the revocation in the dialog. Access is terminated immediately. ## Impersonation history The **Impersonation History** tab shows every partner session with the following details: | Column | Description | | --------- | ------------------------------------------------------------------------------------------------- | | Partner | Name and email of the person who accessed your account | | Started | Date and time the session began | | Duration | Length of the session in minutes (capped at the maximum allowed duration) | | API Calls | Number of API calls made during the session | | Status | Active (session in progress), Expired (exceeded max duration), or Ended (session formally closed) | Sessions have a maximum duration (default: 60 minutes). If a session is not formally ended, it is marked as expired once the maximum duration has elapsed. ## Required permission The partner access page requires the `partner_access` permission. Typically only Admin-role users have this permission. {% callout type="tip" %} Only approve access for partners you trust. Revoke access as soon as the partner's work is complete. Review the impersonation history periodically to ensure no unexpected activity. Partner access is always scoped -- partners can only see and do what you authorized. Share your Customer ID only with trusted partners. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **No pending requests showing** -- Partners must initiate the access request from their side using your Customer ID. Confirm they have the correct ID. **Partner cannot access after approval** -- Access may have expired. Check the Active Access tab to verify the partner's session is still active. **Suspicious activity in audit log** -- If you see unexpected API calls or page visits, revoke the partner's access immediately and contact RentalTide support. **Cannot approve or deny requests** -- Ensure your user has the `partner_access` permission and Admin role. {% /callout %} --- # Staff management Source: https://docs.rentaltide.com/admin/staff/ > Add staff members, assign roles and permissions, manage certifications, track skills, and audit activity The staff management page lets you invite team members, assign roles with granular permissions, manage certifications, and define skills -- all from a single view. Navigate to **Admin > Staff** in the sidebar. ## Page tabs | Tab | Purpose | | ------------------- | --------------------------------------------------------- | | Staff | View, add, edit, and delete staff accounts | | Certifications | Assign and track certifications with expiration dates | | Certification Types | Define the types of certifications your organization uses | | Skills | Manage the global skill tag library assigned to staff | ## Adding staff 1. Click **+ Add Staff** in the top-right corner. 2. Enter the staff member's full name and email address. 3. Select a role -- **Admin** or **Standard**. 4. Assign one or more locations using the location dropdown. Each selected location appears as a chip. 5. Select applicable skills from the skill chip list. 6. Configure permissions by toggling individual permission chips (Standard role only -- Admin automatically receives all permissions). 7. Optionally configure hidden sidebar items to limit the navigation a staff member sees. 8. Click **Add User**. An invitation email is sent automatically. The staff member must complete the invitation to activate their account. ### Copy settings from another user When adding a new staff member, you can copy the role, permissions, locations, skills, and view settings from an existing user. Select a user from the **Copy settings from user** dropdown at the top of the Add Staff dialog. ### CSV import Click **Import CSV** to bulk-create staff accounts from a CSV file. The importer recognizes the following column headers: | Column | Required | Notes | | ---------------- | -------- | ------------------------------------------------------------------------- | | Email | Yes | Must be a valid email address | | First Name | No | Combined with Last Name for the display name | | Last Name | No | Combined with First Name | | Permission Level | No | "manager" or "admin" maps to Admin role; everything else maps to Standard | | Location | No | Matched against your location names (falls back to first location) | | Role Name | No | Passed as a skill tag | Duplicate emails are automatically skipped. The system reports how many were created, skipped, or failed. ## Roles | Role | Access level | | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Admin | Full access to all features, settings, and data across all assigned locations. All permissions are automatically granted and cannot be individually toggled. | | Standard | Limited access based on individually assigned permissions. Each permission can be enabled or disabled independently. | ## Permissions Permissions are organized into groups. You can toggle an entire group at once using the **Select All / Deselect All** button next to each group header. The groups are: | Group | Permissions | | --------------- | ----------------------------------------------------------------------------------------------------------- | | Inventory | Access, add, delete, edit pricing | | Point of Sale | Add/delete/edit inventory, add transactions, access POS | | POS Accounts | View summary, add/edit/delete transactions, manage debt, manage terminals, access cashout, access reporting | | Text Templates | Access, add, edit, delete | | Email Templates | Access, add, edit, delete | | Bookings | Access, manual payment, edit, delete, force, check in/out, download, deposit, revoke, collect extra | | Calendar | Access, edit | | Customers | Access, add, edit, delete | | Reports | Access, export | | Marketing | Access promotions, gift cards, bundles | | Staff | Access, add, edit, delete | | Settings | Access location and account settings | ### Hidden sidebar items You can hide specific sidebar navigation items for a staff member. This is separate from permissions -- it controls what the user sees in the navigation, not what they can access via direct URL. Items are grouped by product area and toggled individually or in bulk. ## Editing staff Click the edit icon on any staff row to open the Update Staff dialog. You can change the name, email, role, locations, skills, permissions, and view settings. Click **Save** to apply changes. ## Activity audit Click the history icon on any staff row to open the **Activity Log** modal. The audit log shows: - **Total requests** -- lifetime count of API calls made by the user - **First activity** and **Last activity** dates - **Request log** -- each entry shows the HTTP method (color-coded), endpoint path, timestamp, response status code, response time in milliseconds, IP address, and kiosk staff name (if applicable) Pagination controls allow you to browse through large activity logs at 10, 25, 50, or 100 entries per page. ## Certifications The **Certifications** tab displays all certifications assigned to staff members. You can filter by staff member, certification type, and status (active, expiring soon, expired, revoked). ### Certification statuses | Status | Criteria | | ------------- | ------------------------------------------------ | | Active | No expiry date, or expiry more than 30 days away | | Expiring Soon | Expiry date within 30 days | | Expired | Expiry date has passed | | Revoked | Manually revoked by an administrator | The staff table shows certification counts inline -- an active count and a warning count for expiring or expired certifications. Clicking the certification count navigates to the Certifications tab filtered to that staff member. ### Adding a certification 1. Click **+ Add Certification**. 2. Select the staff member and certification type. 3. Enter the issued date and expiry date. 4. Click **Save**. ## Skills The **Skills** tab manages the global list of skill tags available when adding or editing staff. Skills are freeform text labels (stored lowercase). Type a skill name and press Enter or click **Add Skill** to create a new tag. Click the delete icon on any skill chip to remove it from the library. ## Resending invitations If a staff member did not receive or complete their invitation, click the email icon on their row to resend the invitation. ## Deleting staff Click the delete icon on a staff row and confirm the deletion. You cannot delete your own account. ## User limits Your plan has a maximum number of staff accounts (shown as a count next to the staff total, e.g., "5/10"). When you reach the limit, the **+ Add Staff** button is disabled. Upgrade your plan or remove inactive users to make room. {% callout type="tip" %} Follow the principle of least privilege -- give staff members only the permissions they need. Use the copy-from-user feature when onboarding multiple staff with the same role. The activity audit helps you investigate issues and verify that staff are performing the correct actions. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Staff member cannot log in** -- Make sure they completed the invitation process. Try resending the invitation from their row. **Missing features for a staff member** -- Check their permission settings and hidden sidebar items. Standard role users only see features they have been explicitly granted access to. **Reached user limit** -- Your plan has a maximum number of staff accounts. Upgrade your plan or remove inactive users to make room. **Invitation email not received** -- Check the spam folder. Verify the email address is correct in the staff profile. **CSV import skipped users** -- Duplicate emails are silently skipped. Rows without a valid email address are also skipped. {% /callout %} --- # Storage Source: https://docs.rentaltide.com/admin/storage/ > Monitor S3 file storage usage, review breakdowns by category, export reports, and clean up unused files The storage page shows how much file storage your account is using and lets you clean up files you no longer need. Navigate to **Admin > Storage** in the sidebar. ## Storage usage overview The top of the page displays a **Storage Usage Card** showing: - Total storage used (in bytes, KB, MB, or GB) - Storage quota for your plan - Percentage of quota consumed - Visual progress bar indicating usage level If your usage approaches the quota limit, a warning is displayed to help you avoid overage charges. ## Usage breakdown Storage is broken down by category with a progress bar for each: | Category | Description | | ----------------- | ----------------------------------------------------------------- | | Images and Videos | Photos and videos attached to bookings, fleet items, and profiles | | Documents | Signed waivers, receipts, contracts, and uploaded documents | | Other | Miscellaneous files that do not fit the above categories | Each category shows: - Total bytes used - Percentage of total storage - Number of files in the category ## Cleanup The cleanup tool identifies temporary and outdated files that can be safely removed. 1. Click **Clean Storage** in the header. 2. A dialog opens and automatically scans for removable files. The scan identifies: - **Temporary files** -- files created during processing that were never finalized - **Old files** -- files past their retention period 3. Review the estimate showing file counts and estimated space that will be freed. 4. Click **Delete Files Permanently** to execute the cleanup. 5. The storage breakdown refreshes automatically after cleanup completes. The cleanup results report how many files were deleted, broken down by type (temp vs. old), and how much space was freed in GB. {% callout type="warning" %} Deleted files cannot be recovered. Always review the cleanup estimate before proceeding. {% /callout %} ## Export report Click **Export Report** to download a CSV file listing all files in your storage bucket. The CSV includes file names, sizes, categories, and timestamps. Use this for manual review or auditing purposes. The file downloads with a name in the format `storage-report-YYYY-MM-DD.csv`. ## Required permission The storage page requires the `business_access` permission. Only Admin-role users can perform cleanup and export operations. ## Storage management tips - **Optimize images** -- Compress and resize images before uploading to reduce storage usage - **Regular cleanup** -- Run the cleanup tool periodically to remove expired temporary files and free up space - **Plan ahead** -- Monitor your usage trend and upgrade your plan before hitting the quota to avoid overage charges {% callout type="tip" %} Large or high-resolution photos are the most common source of high storage usage. Consider optimizing images before uploading them to fleet inventory or bookings. Run cleanup at the start of each season to clear out old files from the previous year. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Storage breakdown not loading** -- Check your internet connection and refresh the page. The breakdown is fetched from the server and may take a moment for accounts with many files. **Cleanup shows zero files** -- Your account has no temporary or expired files to clean up. All files are currently active. **Export taking too long** -- Large storage buckets may take a few seconds to generate the CSV. The download starts automatically once the file is ready. **Overage charges** -- If you exceed your storage quota, contact support to add capacity or upgrade your plan. {% /callout %} --- # Store settings Source: https://docs.rentaltide.com/admin/store-settings/ > Configure every aspect of your location — business info, taxes, pricing, booking rules, POS, and more Store settings control how each location operates. Navigate to **Settings > Stores** in the sidebar, then click a location to open its settings. Each tab covers a different area of configuration. --- ## Business info Basic information about your location and Stripe payment processing. ### Location details | Setting | Description | | ----------------- | -------------------------------------------------------------------- | | **Location Name** | Display name for this location | | **Address** | Physical address (Mapbox autocomplete) | | **Phone Number** | Contact phone number | | **Website** | Your company website URL | | **Company Email** | Main email contact | | **Company Logo** | Logo for booking widget and receipts (recommended 80x80px) | | **Favicon** | Browser tab icon (16x16 or 32x32px) | | **Splash Image** | Landscape image for multi-location booking page selector (280x158px) | ### Industry type Choose the industry that best matches your business. This affects default settings, terminology, and AI suggestions. Options: General, Watercraft Rental, Winter Spa/Hot Springs, Snow Sports, Fishing Charter, Diving/Snorkeling, General Outdoor Activity, Indoor Attraction. ### Stripe connection | Setting | Description | | -------------------------- | --------------------------------------------------------------------------------------------------- | | **Connect Stripe Express** | Link your Stripe account for payment processing | | **Country** | Country for your Stripe account (set during creation) | | **Test Mode** | Enable test mode for development. Use card `4242 4242 4242 4242` with any future expiry and any CVC | {% callout type="tip" %} You can manage your Stripe account (payouts, bank details, verification) by clicking **Manage Account** after connecting. {% /callout %} --- ## General Timezone, currency, formatting, and business hours. ### Regional settings | Setting | Description | | ----------------- | ------------------------------------------------------------------------------ | | **Timezone** | Location timezone (affects all booking times) | | **Currency** | USD, CAD, AUD, GBP, EUR, CHF, SEK, NOK, DKK, PLN, CZK, HUF, RON, BGN, HRK, ISK | | **Date Format** | dd/mm/yyyy or mm/dd/yyyy | | **Time Format** | 24-hour or 12-hour | | **Start of Week** | Sunday or Monday | | **Units** | Imperial or Metric | ### Business hours | Setting | Description | | -------------------- | ----------------------------------------------------------------------- | | **Core Hours Start** | Opening time for this location | | **Core Hours End** | Closing time for this location | | **Slot Steps** | Time intervals for booking slots (5–60 minutes, in 5-minute increments) | ### Visibility | Setting | Description | | -------------------------- | ---------------------------------------------------------------------------------------------------------------- | | **Hide from Booking Page** | Hides this location from the public booking page selector. Use for internal-only or not-yet-open locations | | **Location Slug** | Human-readable URL for your booking page (e.g., `app.rentaltide.com/booking/your-slug`). Auto-generate available | --- ## Taxes Configure up to 5 tax rates per location. Each tax rate has: | Setting | Description | | --------------------- | ----------------------------------------------- | | **Tax Name** | Display name (e.g., "Sales Tax", "GST") | | **Tax Rate (%)** | Percentage, 0–20% in 0.1% increments | | **GL Code** | Accounting code (maps to GL 3050–3064) | | **Apply to Bookings** | Whether this tax applies to rental bookings | | **Apply to Slips** | Whether this tax applies to marina slip charges | {% callout type="tip" %} Tax appears as a separate line item on customer invoices. Multiple taxes stack (e.g., state + county). {% /callout %} --- ## Pricing & payments Controls how you charge customers, handle fees, and process payments. ### Pricing display | Setting | Description | | ------------------------------ | ---------------------------------------------------- | | **Show Starting From Pricing** | Display "from $X" pricing on the booking widget | | **Show Fee Breakdown** | Show itemized fee breakdown to customers at checkout | | **Show Inclusive Pricing** | Show all-in pricing instead of base + fees | ### Fees & overages | Setting | Description | | -------------------------------------------- | ----------------------------------------------------------------- | | **Charge Application Fee (Platform Fee)** | Pass the 4.9% platform fee to customers as a line item | | **Charge Interchange Fee (Credit Card Fee)** | Pass the 2.7% + $0.30 credit card processing fee to customers | | **Charge Booking Overages** | Bill customers for late returns | | **Reprice Late Returns at Regular Rate** | Use standard hourly rate instead of overage rate for late returns | | **Overage Amount** | Dollar amount charged per overage increment | | **Overage Threshold** | Time increment for overage billing (e.g., every 15 minutes) | {% callout type="warning" title="Australia" %} Credit card surcharging is prohibited in Australia effective October 1, 2026 under RBA regulation. The interchange fee toggle displays a warning for Australian locations. {% /callout %} {% callout type="tip" %} To make customers pay the credit card fee, enable **Charge Interchange Fee**. This adds approximately 2.7% + $0.30 as a separate line item on their checkout total. {% /callout %} ### Payment methods | Setting | Description | | ------------------------------ | --------------------------------------------- | | **Allow Transfer To AR** | Allow marking payments as Accounts Receivable | | **Allow Cheque/Check Payment** | Accept cheque payments | ### Pre-auth hold settings Pre-authorization holds are used for damage deposits. | Setting | Description | | ------------------------- | ------------------------------------------------------------------------------------- | | **Collect Pre-Auth Hold** | When to place the hold: 24h, 12h, 6h, or 3h before rental. Or manual only | | **Release Pre-Auth Hold** | When to release: 3h, 6h, 8h, 12h, 24h, 48h, 96h, or 120h after rental. Or manual only | ### Tipping | Setting | Description | | ----------------------------- | ---------------------------------------------------- | | **Enable Tipping** | Allow customer tipping | | **Section Title** | Title shown on tipping UI (default: "Tip Your Crew") | | **Description** | Optional text below the title | | **Suggested Tip Percentages** | Comma-separated values (e.g., 15,18,20,25) | | **Allow Custom Tip Amount** | Let customers enter a custom amount | | **Minimum Custom Amount** | Floor for custom tips | | **Maximum Custom Amount** | Cap for custom tips | --- ## Booking & checkout Rules for how bookings are created, what customers see at checkout, and payment collection. ### Booking rules | Setting | Description | | ---------------------------------- | ----------------------------------------------------- | | **Enable Booking Groups (Orders)** | Allow multi-item orders | | **Only Allow One Booking** | Restrict customers to 1 active booking at a time | | **Require Booking Approval** | Staff must approve each booking before it's confirmed | | **Require Call To Book** | Disable online booking — customers must call | | **Show Save My Spot** | Enable hold/reservation feature | | **Enable Bundles & Cart** | Allow multi-item carts with bundle discounts | | **Include Waiver On Checkout** | Show waiver during checkout flow | | **Show Address Field on Waivers** | Display address input on waiver form | | **Require Address on Waivers** | Make address mandatory on waivers | ### Cutoffs | Setting | Description | | ------------------------------- | ------------------------------------------------------------------- | | **Online Checkout Last Call** | How far in advance online bookings must be made (0–72 hours slider) | | **Max Simultaneous Departures** | Limit concurrent departures (0–50, 0 = unlimited) | ### Protection plans Toggle each plan on/off and customize the customer-facing description. | Plan | Coverage | | ------------------- | ---------------------- | | **AquaShield** | Damage coverage | | **AquaCover** | Liability coverage | | **BlueBalance** | Carbon offset | | **AquaTow** | Tow coverage | | **Trip Protection** | Cancellation insurance | Additional badges: **Best Selling**, **Best Value**, **X Remaining** — shown on time slots in the booking widget. ### Checkout notes Up to 4 custom fields on the checkout page. | Setting | Description | | --------------- | --------------------------------------------- | | **Type** | Note Field (text input) or Agreement Checkbox | | **Label** | Field label (supports markdown) | | **Placeholder** | Help text or example | | **Required** | Whether the field is mandatory | ### Launch locations Define pickup/departure points with pricing. | Setting | Description | | ------------------- | -------------------------------------------- | | **Location Name** | Name of the launch point | | **Price** | Price for this launch location | | **Layover Minutes** | Required layover time (15-minute increments) | ### Payment links (Quick Book) | Setting | Description | | ------------------------------- | ------------------------------------------------- | | **Auto-cancel Unpaid Bookings** | Automatically cancel if not paid in time | | **Auto-cancel After (Hours)** | Hours before auto-cancel triggers | | **Reminder Schedule** | Comma-separated hours for payment reminder emails | | **Default Send Method** | Email, SMS, or Both | ### Payment options | Setting | Description | | --------------------------- | ------------------------------ | | **Allow Pay Half** | Enable 50/50 payment split | | **Allow Installment Plans** | Enable multi-payment schedules | ### Deposit payment plans | Setting | Description | | -------------------------------- | ------------------------------------------------------- | | **Enable Deposit Payment Plans** | Customers pay deposit now, remainder auto-charged later | | **Failure Action** | Flag for Staff Review or Auto-Cancel Booking | | **Max Retries** | Number of retry attempts for failed auto-charges | | **Reminder Days Before Charge** | Days in advance to send reminder email | #### How fees are collected on deposit-plan bookings When a booking is split across a deposit and a later balance charge, **the platform fee for the full booking is collected upfront on the deposit charge**, not split across both payments. The later balance charge carries only the credit-card processing fee — no additional platform fee. **Why this matters:** without upfront collection, the platform fee on the remaining balance would be lost if the customer later pays the balance in cash at the counter (cash payments don't route through Stripe, so there's no opportunity to withhold a platform fee). Collecting the full-booking platform fee on the card-backed deposit guarantees the fee is captured regardless of how the balance is ultimately paid. **Example:** $400 booking, 50% deposit plan, 4.9% platform fee rate. | Charge | Customer pays | Platform fee withheld | CC fee withheld | Merchant receives | | ------------------ | ------------- | --------------------- | --------------- | ----------------- | | Deposit (upfront) | $200 | $19.60 (4.9% × $400) | $6.10 | $174.30 | | Balance (auto) | $200 | $0 | $6.10 | $193.90 | | **Totals** | $400 | $19.60 | $12.20 | $368.20 | The deposit payout looks smaller than a simple 4.9% of $200 would suggest — that's expected. The upfront deposit carries the full-booking platform fee; the balance charge only carries the CC fee on its own amount. {% callout type="tip" %} If you're reconciling payouts against expected margins, remember that a deposit-plan booking's **deposit** is charged the full platform fee for the entire booking, and the **balance** is charged no platform fee at all. Your total platform-fee cost across both payments still equals `platformRate × bookingTotal`. {% /callout %} --- ## Inventory ### Categories Define custom categories for organizing your fleet (e.g., "Jet Skis", "Pontoons", "Kayaks"). Each category has an auto-generated ID and a display name. ### Booking pipeline Configure the stages bookings flow through (Kanban columns). Each stage has a name, color, icon, and can be enabled/disabled. Drag to reorder. ### Inventory settings | Setting | Description | | ----------------------------------- | ------------------------------------------------------- | | **Show "Require Insurance Upload"** | Display insurance upload requirement on inventory items | | **Show "Require Ownership Upload"** | Display ownership proof requirement on inventory items | --- ## Nav board ### Tags Up to 20 custom tags for the navigation board. Each tag has a name and color (20 preset colors). Use tags to categorize or flag active rentals. ### Pipeline column order Drag-and-drop reorder of pipeline stage columns on the journey board. --- ## Operations (check-in/out) ### Staff assignments Configure how staff are assigned to bookings during checkout. ### Equipment checklist Predefined checklist items for the checkout/check-in process. Toggle each item on or off. ### Zello integration | Setting | Description | | ------------------- | ----------------------------------------------- | | **Network Name** | Your Zello network | | **Username** | Zello account username | | **Password** | Zello account password | | **API Key** | Zello API key | | **Device Mappings** | Map Zello devices to inventory items and assets | ### Waiver template Select which waiver template is active for this location's checkout flow. --- ## Kiosk ### Self-service check-in Toggle each step in the kiosk check-in flow: ID verification, payment collection, damage deposit, waiver signing, safety briefing. ### Safety briefing quiz Create quiz questions customers must answer before their rental. | Setting | Description | | ------------------ | --------------------------------------------------------------- | | **Question** | The question text | | **Type** | Multiple Choice or True/False | | **Options** | Answer choices (2–6 for multiple choice) | | **Correct Answer** | Mark the correct answer | | **AI Generate** | Auto-generate location-specific safety questions (max 10 total) | ### Terminal reader Select and configure the Stripe card reader for this kiosk location. --- ## Customer pages ### Next Steps styling Choose a style template for the post-booking Next Steps page. ### Customer cancellation | Setting | Description | | ----------------------------------- | ---------------------------------------------------------------------------- | | **Allow Self-Service Cancellation** | Let customers cancel from their Next Steps page | | **Cancellation Cutoff (Days)** | Minimum days before rental to allow cancellation | | **Cancellation Fee** | Charge a fee for cancellations | | **Fee Type** | Percentage or Fixed Amount | | **Fee Amount** | The fee value | | **Fee Basis** | Calculate fee on the refund amount or the full booking total | | **Store Credit Option** | Offer store credit as an alternative to cash refund | | **Refund Method** | Customer chooses, Card only, or Store credit only | | **Bonus Markup (%)** | Extra percentage added to store credit (e.g., 10% bonus for choosing credit) | ### Self-service reschedule | Setting | Description | | ---------------------------- | ------------------------------------------------ | | **Allow Reschedule** | Let customers reschedule from Next Steps | | **Reschedule Cutoff (Days)** | Minimum days before rental to allow rescheduling | | **Charge Reschedule Fee** | Apply a fee for rescheduling | | **Fee Type** | Percentage or Fixed Amount | | **Fee Amount** | The fee value | ### Other settings | Setting | Description | | --------------------------------- | --------------------------------------------------- | | **Safety Briefing on Next Steps** | Show safety briefing content on the Next Steps page | | **Hide waiver section** | Remove the waiver section from Next Steps | | **Hide participants section** | Remove the participant manager from Next Steps | | **Terms of Service URL** | Link to your terms of service | | **Cancellation Policy URL** | Link to your cancellation policy | --- ## POS & receipts ### POS settings | Setting | Description | | ---------------------------- | ----------------------------------------- | | **Allow POS Receipt Prompt** | Ask customers if they want a receipt | | **Show SKU on Receipt** | Display product SKU on printed receipts | | **Enable Store Credit** | Enable store credit for customer accounts | | **Default Credit Amount** | Default amount when issuing store credit | ### Cash denominations Configure which bill and coin denominations appear during cash transactions. Each denomination has a value, label, and enabled toggle. Sorted by value. ### Receipt customization | Setting | Description | | ------------------------ | --------------------------------------------- | | **Show Logo on Receipt** | Display your company logo on printed receipts | | **Receipt Header** | Custom header text | | **Receipt Footer** | Custom footer text | --- ## Translations Override default UI text with custom translations per language. | Feature | Description | | ----------------------- | ------------------------------------------------------------ | | **Languages** | English, French, Spanish | | **Custom Translations** | JSON format overrides for any UI string | | **Templates** | Quick-apply: Boat Rentals, Spa Reservations, ATV/UTV Rentals | | **Show Defaults** | Display system default translations alongside custom | {% callout type="tip" %} Use translation templates to quickly adapt the UI terminology for your industry — for example, changing "boat" to "unit" or "reservation" to "appointment". {% /callout %} --- ## Dynamic pricing AI-powered pricing that adjusts rates based on demand signals. ### Enable Master toggle to turn dynamic pricing on or off for this location. ### Strategy | Strategy | Behavior | | -------------------------- | ------------------------------------------ | | **Balanced** (recommended) | Blends urgency and demand signals | | **Urgency Increase** | Prices rise as the booking date approaches | | **Last Minute Deal** | Prices drop for low-occupancy time slots | | **Demand Responsive** | Pure demand-based adjustments | ### Limits | Setting | Description | | ------------------------- | ----------------------------------------------------------- | | **Max Increase (%)** | Maximum percentage prices can rise above base rate (0–100%) | | **High Demand Threshold** | Occupancy percentage that triggers price increases | | **Low Demand Threshold** | Occupancy percentage that triggers price decreases | | **Show Original Price** | Display crossed-out base price next to adjusted price | ### Per-listing overrides Enable or disable dynamic pricing for individual inventory items independent of the global setting. ### Advanced signal weights Fine-tune how different signals influence pricing. Weights auto-normalize to 100%. | Signal | Description | | ------------------- | -------------------------------------- | | **Forecast Demand** | Weight for demand forecast data | | **Occupancy Rate** | Weight for current occupancy | | **Engagement** | Weight for customer engagement metrics | | **Weather** | Weight for weather conditions | --- ## GL codes Map RentalTide's default general ledger codes to your accounting system's chart of accounts. ### Overrides Create mappings from system GL codes to your custom codes. For example, map system code `6520` to your accounting system's rental revenue code. ### System GL code reference | Range | Category | | --------- | ----------------------------------------------------- | | 1020–1140 | Assets (Cash, AR, Revenue Clearing, Deferred Revenue) | | 2100–2150 | Liabilities (Gift Cards, Platform Fees Payable) | | 3015–3115 | Damages, Tips | | 3050–3064 | Tax 1 through Tax 15 | | 4160 | Moorage Seasonal Revenue | | 6509–6551 | Rental Revenue (by type) | | 6560 | Credit Card Surcharge Revenue | | 6561 | Platform Fee Revenue | | 6580–6587 | Protection Plan Revenue | | 6600–6610 | Cancellation Fees, Late Return, Overtime | | 5110–5130 | Cost of Goods Sold | | 8190–8214 | Expenses (Processing, Discounts) | --- ## Slip booking Configure marina slip booking settings. | Setting | Description | | ----------------------- | ---------------------------------------------------- | | **Enable Slip Booking** | Turn on the slips module for this location | | **Deposit Settings** | Configure deposit requirements for slip reservations | | **Rate Configuration** | Set pricing for slip rentals | | **Contract Templates** | Manage lease contract templates | | **Additional Services** | Configure add-on services for slip tenants | {% callout type="note" %} The Slips & Marina module is a paid add-on at $249.99/month for up to 50 units. Additional 50-unit blocks are available for larger marinas. {% /callout %} --- ## Haul services Configure boat haul-out, launch, and maintenance services. ### Service types | Service | Settings | | ------------------- | ------------------------ | | **Haul Out** | Base fee + per-foot rate | | **Put In (Launch)** | Base fee + per-foot rate | | **Pressure Wash** | Base fee + per-foot rate | ### Additional services Up to 15 custom services, each with a name, price, and enabled toggle. ### Scheduling | Setting | Description | | ---------------------- | ----------------------------------------------------------------- | | **Time Slots** | Up to 8 time slots with label, start/end time, and enabled toggle | | **Operating Schedule** | Enable/disable each day of the week with max services per day | ### Equipment & limits | Setting | Description | | ------------------------ | ------------------------------------------------------------ | | **Available Equipment** | Travel Lift, Crane, Hydraulic Trailer, Forklift (checkboxes) | | **Deposit Required** | Toggle + type (percentage or fixed) + amount | | **Rush Surcharge (%)** | Extra charge for rush service | | **Min Boat Length (ft)** | Minimum vessel length (0 = no minimum) | | **Max Boat Length (ft)** | Maximum vessel length (0 = no limit) | | **Max Weight (lbs)** | Maximum vessel weight (0 = no limit) | --- # Stripe account & payments Source: https://docs.rentaltide.com/admin/stripe/ > How RentalTide connects to Stripe, what changed with Stripe Connect Express, and where to access your dashboard RentalTide uses **Stripe Connect** to process payments on your behalf. This page explains how the connection works, what changed when we moved to Stripe Connect **Express**, and where to find the things you used to access in the full Stripe dashboard. --- ## Quick answer: where's my Stripe dashboard? If you used to log into Stripe directly and now your dashboard looks different (or you can only see payouts), this is expected. RentalTide now uses **Stripe Connect Express** instead of Standard accounts, and almost everything you used to do in Stripe is now built directly into RentalTide. **Open Settings → Stripe Dashboard** inside RentalTide to access: - Payments, refunds, and disputes - Payouts and payout schedules - Account balance - Bank account and business details - Onboarding (if not yet complete) You no longer need to leave RentalTide to manage your Stripe account. --- ## Why we changed from Standard to Express In November 2025 RentalTide moved to **Stripe Connect Express with Embedded Components**. The change was deliberate — it gives you a better, more integrated experience without losing any functionality. ### What you gain - **Everything in one place** — payments, payouts, refunds, disputes, and bank details are all inside RentalTide. No more bouncing between two products. - **Faster onboarding** — Express has a streamlined signup flow with fewer fields. New locations get up and running in minutes, not days. - **Branded experience** — your team and customers see RentalTide, not a Stripe-branded screen. - **Built-in role-based access** — RentalTide controls who on your team can issue refunds, manage payouts, or view balances. ### What changed - The connected account no longer has access to the **full Stripe dashboard at `dashboard.stripe.com`**. Instead, you have the **Express Dashboard** (limited — payouts and basic reporting), or the much more capable **embedded dashboard inside RentalTide** (recommended). - Express accounts can't be converted back to Standard. This is a Stripe limitation, not a RentalTide one. {% callout type="note" %} If you have an older **Standard** account from before November 2025, it still works exactly as it did. You can keep using `dashboard.stripe.com` for that account. The change only affects new locations created after the switch. {% /callout %} --- ## Where to find common tasks | What you want to do | Where to do it | | -------------------------------------- | ------------------------------------------------------------- | | Issue a refund | RentalTide → **Stripe Dashboard → Payments**, find the charge | | View payouts and schedule | RentalTide → **Stripe Dashboard → Payouts** | | Trigger an instant payout | RentalTide → **Stripe Dashboard → Payouts → Pay out now** | | Update your bank account | RentalTide → **Stripe Dashboard → Account** | | Update business details (EIN, address) | RentalTide → **Stripe Dashboard → Account** | | View account balance | RentalTide → **Stripe Dashboard → Balances** | | Handle a dispute or chargeback | RentalTide → **Stripe Dashboard → Payments → Disputes** | | Complete onboarding | RentalTide → **Stripe Dashboard → Onboarding** | | Download tax forms (1099-K) | Express Dashboard at `connect.stripe.com/app/express` | | View transactions and exports | RentalTide → **Reporting → Payments** | --- ## Connecting Stripe to a new location When you create a new store in RentalTide: 1. Go to **Settings → Stores → Add store** 2. Fill in the location details (name, address, email, country) 3. Click **Add and Setup** 4. RentalTide creates an Express account behind the scenes and saves the `connectId` to the location 5. Complete onboarding inline by going to **Stripe Dashboard → Onboarding** The whole process happens inside RentalTide — there's no separate Stripe signup. --- ## Test mode Use test mode while you're setting things up or trying new flows: - Toggle **Test Mode** in **Settings → Stores → Business info** - Use card `4242 4242 4242 4242` with any future expiry and any CVC - Test charges show up in the embedded dashboard tagged as test transactions Switch to live mode when you're ready to take real payments. --- ## Frequently asked questions ### Why can't I log into Stripe like I used to? Express connected accounts have a limited Stripe-hosted dashboard at `connect.stripe.com/app/express`. Everything you used to do in the full Stripe dashboard is now built into RentalTide — open **Stripe Dashboard** in the sidebar. ### Can I get my Standard account back? Stripe doesn't allow converting an Express account back to Standard. If you genuinely need full `dashboard.stripe.com` access for something RentalTide doesn't expose, contact us and we'll figure out the right path — but in nearly every case, the embedded dashboard inside RentalTide does the job better. ### What about my old Standard account from before November 2025? It still works. We don't migrate existing Standard accounts. You can keep using `dashboard.stripe.com` for those locations indefinitely. ### Who can access the Stripe Dashboard inside RentalTide? By default, **admins** can access everything. You can restrict refund management, payout management, and account changes to specific roles in **Settings → Staff**. ### Is anything missing from the embedded dashboard? Almost nothing. The embedded dashboard supports payments, refunds, disputes, payouts (instant + scheduled), balances, account management, and onboarding. The only thing currently outside the embedded view is **tax forms (1099-K)** — those still come from `connect.stripe.com/app/express`. --- ## Need help? If you're stuck on a Stripe-related task and can't find what you need, reach out to our support channel (**Settings → Support**) and we'll help you locate it. --- # Subscription Source: https://docs.rentaltide.com/admin/subscription/ > Manage your plan, view pricing, update payment methods, and manage slip add-ons The subscription page shows your current plan details, billing status, and payment methods. Manage everything related to how you pay for RentalTide. Navigate to **Admin > Subscription** in the sidebar. ## Current plan Your subscription page displays the current plan status including: - **Plan name** and tier (Standard or Custom) - **Billing status** (active, past due, cancelled) - **Next billing date** - **Current usage** against plan limits ### Standard plan | Feature | Limit | | --------------- | -------------------- | | Transaction fee | 4.9% | | Interchange fee | 2.7% per transaction | | Locations | Up to 10 | | Fleet items | Up to 100 | | Bookings | Up to 10,000 | | Staff accounts | Up to 100 | | Discount codes | Up to 500 | | API keys | Up to 2 | ### Custom plan Enterprise customers may be on a custom plan with different rates and limits. Custom plans can include: - Reduced transaction and interchange fees - Custom monthly pricing - Higher limits for locations, fleet items, staff, and bookings - Guaranteed revenue thresholds Custom plan details are displayed on the subscription page when applicable. Contact support for custom pricing arrangements. ## Slip add-on The slip add-on enables marina slip management features. It is billed as a separate subscription: | Slip add-on | Rate | | ------------------- | ------------------------------- | | Base | $249.99/month per 50 slip units | | Additional capacity | Added in blocks of 10 slips | ### Managing slips - **Start subscription** -- begins a new slip subscription if you do not have one - **Add slips** -- adds incremental slip capacity (10 units per block) - **Manage billing** -- opens the Stripe billing portal for your slip subscription - **Cancel** -- cancels the slip subscription at the end of the current billing period The subscription page shows your current slip quota, how many slips are in use, and remaining capacity. ## Payment methods View and manage the payment methods on file for your account. You can: - **Add a payment method** -- attach a new card via Stripe's secure setup flow - **View existing cards** -- see the card brand, last four digits, and expiration date - **Set default** -- the default card is charged on each billing cycle ## Actions | Action | Description | | -------------------- | -------------------------------------------------------------------------------------------------- | | View Billing History | Opens your complete billing history in Stripe's customer portal | | Cancel Subscription | Cancels your subscription at the end of the current billing period -- you retain access until then | | Reactivate | If cancelled, reactivate before the period ends to continue uninterrupted | | Add Payment Method | Opens the Stripe setup form to attach a new card | ## Required permission The subscription page requires the `subscription_access` permission. {% callout type="tip" %} Cancellation takes effect at the end of your current billing period -- you do not lose access immediately. Payment method changes take effect on the next billing cycle. Contact support for enterprise pricing or custom arrangements. Slip capacity can be increased at any time without downtime. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Payment failed** -- Update your payment method. Stripe retries the charge automatically on a schedule. **Need more capacity** -- Review your plan limits on the subscription page. Contact support to upgrade or adjust limits. **Slip units exceeded** -- Add another capacity block from the subscription page to increase your slip quota. **Cannot access subscription page** -- Ensure your user has the `subscription_access` permission. Only Admin-role users typically have this permission. **Stripe portal not loading** -- Check for popup blockers in your browser. The Stripe billing portal opens in a new tab. {% /callout %} --- # API Reference Source: https://docs.rentaltide.com/api-reference/ > Integrate with RentalTide using the REST API # API reference The RentalTide API lets you programmatically manage bookings, inventory, customers, transactions, and more. Every action available in the dashboard is available through the API. --- ## Base URL All API requests are made to: ``` https://v3.api.rentaltide.com ``` --- ## Authentication The API supports two authentication methods. ### Bearer token (JWT) Include your JWT in the `Authorization` header. Tokens are issued through Auth0 when a user logs in to the dashboard. ``` Authorization: Bearer eyJhbGciOiJSUzI1NiIs... ``` ### API key For server-to-server integrations, use a static API key. Generate one from **Admin > API Keys** in the dashboard. ``` x-api-key: rtk_live_abc123def456 ``` {% callout type="warning" title="Keep keys secret" %} API keys carry the same permissions as the user who created them. Never expose them in client-side code or public repositories. {% /callout %} --- ## Request format All request bodies must be JSON with the `Content-Type: application/json` header. ```bash curl -X POST https://v3.api.rentaltide.com/bookings \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"inventoryId": "inv_123", "startDate": "2026-06-15T09:00:00Z"}' ``` --- ## Response format Every response returns JSON. Successful responses use this structure: ```json { "success": true, "data": { ... } } ``` Error responses include a message and an error code: ```json { "success": false, "error": "BOOKING_CONFLICT", "message": "The requested time slot is no longer available." } ``` ### HTTP status codes | Code | Meaning | | ----- | ---------------------------------------------------------- | | `200` | Success | | `201` | Created | | `400` | Bad request — check the request body | | `401` | Unauthorized — missing or invalid credentials | | `403` | Forbidden — valid credentials but insufficient permissions | | `404` | Not found | | `409` | Conflict — resource state prevents the action | | `429` | Rate limited — slow down | | `500` | Internal server error | --- ## Rate limits API requests are rate-limited per authentication credential: | Plan | Limit | | ---------- | ----------------------- | | Standard | 100 requests per minute | | Enterprise | 500 requests per minute | When you exceed the limit, the API returns a `429` status with a `Retry-After` header indicating how many seconds to wait. {% callout type="note" %} Webhook deliveries and dashboard usage do not count against your API rate limit. {% /callout %} --- ## Pagination List endpoints return paginated results. Use the `limit` and `offset` query parameters to navigate pages. ``` GET /bookings?limit=25&offset=50 ``` The response includes a `total` count: ```json { "success": true, "data": [ ... ], "total": 142, "limit": 25, "offset": 50 } ``` --- ## API sections {% cardGroup cols=3 %} {% card title="Bookings" href="/api/bookings/" /%} {% card title="Inventory" href="/api/inventory/" /%} {% card title="Customers" href="/api/customers/" /%} {% card title="Point of Sale" href="/api/pos/" /%} {% card title="Availability" href="/api/availability/" /%} {% card title="Payments" href="/api/payments/" /%} {% card title="Locations" href="/api/locations/" /%} {% card title="Staff" href="/api/staff/" /%} {% card title="Waivers" href="/api/waivers/" /%} {% card title="Slips" href="/api/slips/" /%} {% card title="Memberships" href="/api/memberships/" /%} {% card title="Marina" href="/api/marina/" /%} {% card title="Marketing" href="/api/marketing/" /%} {% card title="Public" href="/api/public/" /%} {% card title="Analytics" href="/api/analytics/" /%} {% card title="Integrations" href="/api/integrations/" /%} {% /cardGroup %} --- ## Webhooks RentalTide can send real-time event notifications to your server. Configure webhook endpoints from **Admin > Webhooks** in the dashboard. ### Supported events | Event | Fired when | | --------------------- | -------------------------------- | | `booking.created` | A new booking is placed | | `booking.updated` | A booking is modified | | `booking.cancelled` | A booking is cancelled | | `booking.checked_in` | A customer checks in | | `booking.checked_out` | A rental is returned | | `payment.completed` | A payment is captured | | `payment.refunded` | A refund is issued | | `customer.created` | A new customer record is created | ### Webhook payload ```json { "event": "booking.created", "timestamp": "2026-06-15T14:30:00Z", "data": { "id": "bk_abc123", "inventoryId": "inv_456", "customerId": "cust_789", "startDate": "2026-06-15T09:00:00Z", "endDate": "2026-06-15T11:00:00Z", "status": "confirmed" } } ``` {% callout type="tip" title="Verifying webhooks" %} Each webhook request includes an `X-RentalTide-Signature` header. Verify this HMAC-SHA256 signature against your webhook secret to confirm the request came from RentalTide. {% /callout %} --- # Analytics API Source: https://docs.rentaltide.com/api-reference/analytics/ > Reporting, forecasting, AI insights, and event tracking Endpoints for analytics dashboards, revenue forecasting, AI-powered insights, and event tracking. ## Analytics ### Get analytics metrics for dashboard KPIs `GET /analytics/metrics` Returns aggregated metrics including revenue, tax, tips, discounts, and booking counts with daily breakdown **Parameters** | Name | In | Type | Required | Description | | ------------- | ----- | ------ | -------- | ------------------------------------ | | `locationIds` | query | string | Yes | Comma-separated list of location IDs | | `startDate` | query | string | Yes | Start date (YYYY-MM-DD) | | `endDate` | query | string | Yes | End date (YYYY-MM-DD) | **Responses** | Code | Description | | ----- | --------------------------------------- | | `200` | Analytics metrics returned successfully | | `400` | Missing required parameters | | `500` | Server error | --- ### Get inventory performance metrics `GET /analytics/inventory-performance` Returns top performing inventory items and assets by revenue **Parameters** | Name | In | Type | Required | Description | | ------------- | ----- | ------- | -------- | ------------------------------------ | | `locationIds` | query | string | Yes | Comma-separated list of location IDs | | `startDate` | query | string | Yes | Start date (YYYY-MM-DD) | | `endDate` | query | string | Yes | End date (YYYY-MM-DD) | | `limit` | query | integer | No | Number of items to return | **Responses** | Code | Description | | ----- | ------------------------------------------------ | | `200` | Inventory performance data returned successfully | | `400` | Missing required parameters | | `500` | Server error | --- ### Get year-over-year revenue data `GET /analytics/year-over-year` Returns monthly revenue data for specified locations comparing current and previous year. Uses ledger/journal entries to include all revenue sources (bookings + POS). **Parameters** | Name | In | Type | Required | Description | | ------------- | ----- | ------- | -------- | ------------------------------------------------------ | | `locationIds` | query | string | Yes | Comma-separated list of location IDs | | `currentYear` | query | integer | No | The current year to compare (defaults to current year) | **Responses** | Code | Description | | ----- | ------------------------------------------------- | | `200` | Year-over-year revenue data returned successfully | | `400` | Missing or invalid locationIds parameter | | `500` | Server error | --- ### Update revenue target `PATCH /analytics/revenue-target` Updates the revenue target and/or previous year revenue override for a location **Request body** | Field | Type | Required | Description | | ----------------------------- | ------ | -------- | ----------------------------------------------------------- | | `locationId` | string | Yes | The location ID to update | | `revenueTarget` | number | No | Revenue target amount (must be positive) | | `previousYearRevenueOverride` | number | No | Override value for previous year revenue (must be positive) | **Responses** | Code | Description | | ----- | ------------------------------------- | | `200` | Revenue settings updated successfully | | `400` | Missing locationId or invalid values | | `404` | Location not found | | `500` | Server error | --- ### Realize revenue for all completed bookings `POST /analytics/realize-completed-bookings` Creates journal entries for all completed bookings that haven't had revenue recognized yet. This syncs booking revenue to the ledger. **Request body** | Field | Type | Required | Description | | ------------- | ------- | -------- | ---------------------------------------------------- | | `locationIds` | array | No | Optional - limit to specific location IDs | | `dryRun` | boolean | No | If true, only returns count without creating entries | **Responses** | Code | Description | | ----- | ------------------------------------------ | | `200` | Revenue realization completed successfully | | `500` | Server error | --- ### Get widget/booking page engagement metrics `GET /analytics/widget-metrics` Returns funnel, temporal heatmap, daily engagement, source breakdown, and top products **Parameters** | Name | In | Type | Required | Description | | ------------- | ----- | ------ | -------- | ------------------------------------ | | `locationIds` | query | string | Yes | Comma-separated list of location IDs | | `startDate` | query | string | Yes | | | `endDate` | query | string | Yes | | **Responses** | Code | Description | | ----- | ----------------------------------------------- | | `200` | Widget engagement metrics returned successfully | | `400` | Missing required parameters | | `500` | Server error | --- ## Forecast ### Get demand forecast for a location `GET /forecast` Returns predicted daily renter counts using historical data, weather, and holiday detection **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------- | -------- | ----------------------------------------------------- | | `locationId` | query | string | Yes | Location ID to forecast for | | `days` | query | integer | No | Number of days to forecast (7 or 14) | | `timezone` | query | string | No | Timezone for date calculations (e.g. America/Toronto) | | `units` | query | string | No | Temperature units | **Responses** | Code | Description | | ----- | ----------------------------------- | | `200` | Forecast data returned successfully | | `400` | Missing required parameters | | `500` | Server error | --- ## AI ### Process AI request `POST /ai` Routes AI requests to different services based on the 'what' parameter **Request body** | Field | Type | Required | Description | | ------------------ | ------ | -------- | ------------------------------------------------------ | | `what` | string | Yes | Type of AI request | | `message` | string | No | Message or prompt for the AI | | `prompt` | string | No | Detailed prompt for AI analysis (for emailEnhancement) | | `businessName` | string | No | Business name (for socialMediaPost) | | `businessType` | string | No | Type of business (for socialMediaPost) | | `businessLocation` | string | No | Business location (for socialMediaPost) | | `bookings` | array | No | Booking data (for bookingSidekick) | | `websiteUrl` | string | No | Website URL (for businessAudit) | | `businessData` | object | No | Additional business data (for businessAudit) | **Responses** | Code | Description | | ----- | --------------------------------- | | `200` | AI response returned successfully | | `400` | Invalid or missing parameters | | `401` | Unauthorized | | `500` | Server error | --- ### Perform business audit `POST /ai/business-audit` Performs a comprehensive business audit using AI analysis of website and business data. Charges $4.99 per audit. **Request body** | Field | Type | Required | Description | | -------------- | ------ | -------- | ------------------------------------- | | `websiteUrl` | string | Yes | Website URL to audit | | `businessData` | object | No | Additional business data for analysis | **Responses** | Code | Description | | ----- | -------------------------------------- | | `200` | Business audit completed successfully | | `400` | Invalid or missing websiteUrl | | `401` | Unauthorized | | `403` | Business audit integration not enabled | | `404` | Customer not found | | `500` | Server error | --- ### Get business audit billing history `GET /ai/business-audit/billing` Retrieves business audit billing history and analytics for the authenticated customer **Responses** | Code | Description | | ----- | ------------------------------------- | | `200` | Billing history returned successfully | | `401` | Unauthorized | | `404` | Customer not found | | `500` | Server error | --- ### Validate receipt data `POST /ai/validate-receipt` Validates inputted transaction data against an uploaded receipt image using AI Vision **Request body** | Field | Type | Required | Description | | -------------- | ------ | -------- | --------------------------------- | | `receiptImage` | string | Yes | Base64 encoded image or image URL | | `inputData` | object | No | | **Responses** | Code | Description | | ----- | ---------------------------------------- | | `200` | Validation completed successfully | | `400` | Missing receipt image or validation data | | `500` | Server error | --- ### Extract receipt data `POST /ai/extract-receipt-data` Extracts structured data from a receipt image without validation (useful for auto-filling forms) **Request body** | Field | Type | Required | Description | | -------------- | ------ | -------- | --------------------------------- | | `receiptImage` | string | Yes | Base64 encoded image or image URL | **Responses** | Code | Description | | ----- | --------------------------- | | `200` | Data extracted successfully | | `400` | Missing receipt image | | `500` | Server error | --- ### Proxy external webpage `GET /ai/proxy-page` Proxies an external webpage and injects selection script for click-to-tag inventory import functionality **Parameters** | Name | In | Type | Required | Description | | ----- | ----- | ------ | -------- | ------------------------ | | `url` | query | string | Yes | URL of the page to proxy | **Responses** | Code | Description | | ----- | ----------------------------------------------- | | `200` | Proxied HTML page with injected selection tools | | `400` | Missing or invalid URL | | `500` | Failed to load page | --- ### Scrape inventory from URL `POST /ai/scrape-inventory` Scrapes inventory/rental information from a website URL using Puppeteer screenshots and OpenAI Vision to extract structured data **Request body** | Field | Type | Required | Description | | ----- | ------ | -------- | ----------------------------------- | | `url` | string | Yes | URL of the inventory page to scrape | **Responses** | Code | Description | | ----- | ------------------------------------- | | `200` | Inventory data extracted successfully | | `400` | Missing or invalid URL | | `401` | Customer ID required | | `500` | Server error | --- ### Extract driver's license data `POST /ai/extract-license` Extracts driver's license information from an image using GPT-4 Vision **Request body** | Field | Type | Required | Description | | ------- | ------ | -------- | --------------------------------------------------------- | | `image` | string | Yes | Base64 encoded image or image URL of the driver's license | **Responses** | Code | Description | | ----- | ----------------------------------- | | `200` | License data extracted successfully | | `400` | Missing image or extraction failed | | `500` | Server error | --- ## Events ### Create a new booking event `POST /events` **Request body** | Field | Type | Required | Description | | --------------- | ------ | -------- | ----------- | | `transactionid` | string | No | | | `rentalId` | string | No | | | `event_type` | string | No | | | `eventType` | string | No | | | `event_change` | string | No | | | `eventLabel` | string | No | | | `content` | string | No | | | `details` | object | No | | | `actorName` | string | No | | | `actorId` | string | No | | | `customerId` | string | No | | **Responses** | Code | Description | | ----- | -------------------------- | | `200` | Event created successfully | | `500` | Error creating event | --- ### Get events for booking(s) `GET /events` **Parameters** | Name | In | Type | Required | Description | | --------------- | ----- | ------ | -------- | ------------------------------------------ | | `transactionid` | query | string | No | Single rental ID (backward compat) | | `rentalIds` | query | string | No | Comma-separated rental IDs for batch fetch | **Responses** | Code | Description | | ----- | -------------------------------------- | | `200` | Events retrieved successfully | | `400` | transactionid or rentalIds is required | | `500` | Error retrieving events | --- --- # Availability API Source: https://docs.rentaltide.com/api-reference/availability/ > Check real-time availability, holds, and maintenance blocks Endpoints for checking inventory availability, placing temporary holds on assets, and managing dry dock maintenance periods. ## Availability ### Preload availability data `GET /preload-availability` Preloads booking data for a given inventory and month to enable faster availability checking on the client **Parameters** | Name | In | Type | Required | Description | | ------------- | ----- | ------ | -------- | -------------------------------------------- | | `inventoryId` | query | string | Yes | The inventory ID to preload availability for | | `month` | query | string | Yes | The month to preload in YYYY-MM format | **Responses** | Code | Description | | ----- | ------------------------------------------------- | | `200` | Availability data retrieved successfully | | `400` | Missing or invalid inventoryId or month parameter | | `500` | Internal server error | --- ## Hold Asset ### Create a waitlist entry to hold an asset `POST /holdAsset` Creates a waitlist entry to temporarily hold/reserve an asset for a customer. Entries expire after 2 days (TTL). **Request body** | Field | Type | Required | Description | | ------------- | ------ | -------- | ------------------------------------ | | `customerId` | string | Yes | The customer ID | | `email` | string | Yes | Customer email address | | `inventoryId` | string | Yes | The ID of the inventory item to hold | | `locationId` | string | Yes | The location ID | **Responses** | Code | Description | | ----- | ----------------------------------- | | `201` | Waitlist entry created successfully | | `400` | Missing required fields | | `500` | Could not create waitlist entry | --- ## Dry Dock ### Create a new drydock booking `POST /drydock` Creates a new drydock booking to block a boat from rentals during a specified time period **Request body** | Field | Type | Required | Description | | ----------- | ------ | -------- | ------------------------------------- | | `boatId` | string | Yes | The ID of the boat to block | | `startDate` | string | Yes | Start date of the drydock period | | `endDate` | string | Yes | End date of the drydock period | | `assetIds` | array | No | Optional array of asset IDs to assign | **Responses** | Code | Description | | ----- | ---------------------------------------------- | | `200` | Drydock booking created successfully | | `400` | Missing required fields or invalid date format | | `500` | Server error | --- ### Get drydock bookings `GET /drydock` Retrieves drydock bookings for a given boat and optionally filtered by asset **Parameters** | Name | In | Type | Required | Description | | --------- | ----- | ------ | -------- | ---------------------------------------------- | | `boatId` | query | string | Yes | The ID of the boat to get drydock bookings for | | `assetId` | query | string | No | Optional asset ID to filter by | **Responses** | Code | Description | | ----- | ------------------------ | | `200` | List of drydock bookings | | `400` | Missing boatId parameter | | `500` | Server error | --- ### Update a drydock booking `PATCH /drydock` Updates an existing drydock booking with new dates or asset assignment **Request body** | Field | Type | Required | Description | | ----------- | ------ | -------- | --------------------------------------- | | `rentalId` | string | Yes | The ID of the drydock booking to update | | `startDate` | string | Yes | New start date of the drydock period | | `endDate` | string | Yes | New end date of the drydock period | | `assetId` | string | No | Optional new asset ID to assign | **Responses** | Code | Description | | ----- | ---------------------------------------------- | | `200` | Drydock booking updated successfully | | `400` | Missing required fields or invalid date format | | `500` | Server error | --- ### Delete a drydock booking `DELETE /drydock` Deletes an existing drydock booking **Request body** | Field | Type | Required | Description | | ---------- | ------ | -------- | --------------------------------------- | | `rentalId` | string | Yes | The ID of the drydock booking to delete | **Responses** | Code | Description | | ----- | ------------------------------------ | | `200` | Drydock booking deleted successfully | | `400` | Missing rentalId | | `500` | Server error | --- --- # Bookings API Source: https://docs.rentaltide.com/api-reference/bookings/ > Create, retrieve, update, and cancel rental bookings Endpoints for managing the booking lifecycle -- from creation through checkout and return. ## Core Booking ### Create a new booking `POST /coreBooking/book` Main booking endpoint that handles the complete booking workflow including: - Customer creation/updates - Payment processing (full or installment plans) - Inventory management and asset assignment - Booking record creation - Notifications and accounting entries - Loyalty points awarding **Request body** | Field | Type | Required | Description | | -------------------- | ------ | -------- | ------------------------------------------------------------ | | `rentalDetails` | object | Yes | Core rental information | | `rentalPricing` | object | Yes | Pricing breakdown | | `customerInfo` | object | Yes | Customer details | | `depositInformation` | object | No | Deposit configuration | | `discountDetails` | object | No | Applied discounts | | `paymentMethodId` | string | No | Stripe payment method ID | | `paymentPlan` | object | No | Payment plan type (full or installments) | | `selectedBoatAddons` | array | No | | | `globalAddons` | array | No | | | `extendedData` | object | Yes | Additional booking data including location and customer info | **Responses** | Code | Description | | ----- | ---------------------------------------- | | `201` | Booking created successfully | | `400` | Invalid request data or validation error | | `402` | Payment authorization failed | | `409` | Time slot unavailable or fully booked | | `500` | Internal server error | --- ## Booking Schedule ### Get booking schedule for an inventory `GET /schedule/schedule` Retrieves booking schedule with date range optimization, filtering, sorting, and pagination support **Parameters** | Name | In | Type | Required | Description | | ------------------ | ----- | ------- | -------- | ------------------------------------------ | | `inventory_id` | query | string | Yes | The inventory ID to get schedule for | | `start_date` | query | string | No | Filter bookings from this date | | `end_date` | query | string | No | Filter bookings until this date | | `extend` | query | string | No | Include extended record data | | `dates_only` | query | string | No | Return only date information | | `page` | query | integer | No | Page number for pagination | | `limit` | query | integer | No | Number of items per page | | `include_drydock` | query | string | No | Include drydock bookings | | `use_parallel` | query | string | No | Enable parallel loading | | `use_scan` | query | string | No | Force table scan if GSI issues | | `search_rental_id` | query | string | No | Search for specific rental ID | | `sort_by` | query | string | No | Sort field | | `sort_order` | query | string | No | Sort direction | | `status_filter` | query | string | No | Filter by booking status (comma-separated) | **Responses** | Code | Description | | ----- | --------------------------------------- | | `200` | Successfully retrieved booking schedule | | `400` | Missing required inventory_id parameter | | `500` | Internal server error | --- ### Search bookings `GET /schedule/schedule/search` Quick search endpoint to find specific bookings by rental ID, customer name, or email **Parameters** | Name | In | Type | Required | Description | | --------------- | ----- | ------ | -------- | --------------------------------- | | `inventory_id` | query | string | Yes | The inventory ID to search within | | `rental_id` | query | string | No | Partial rental ID to search for | | `customer_name` | query | string | No | Customer name to search for | | `email` | query | string | No | Customer email to search for | **Responses** | Code | Description | | ----- | --------------------------------------- | | `200` | Search results returned successfully | | `400` | Missing required inventory_id parameter | | `500` | Search failed | --- ### Get inventory items by location `GET /schedule/location` Retrieves inventory items for specified location IDs **Parameters** | Name | In | Type | Required | Description | | -------------- | ----- | ------ | -------- | --------------------------------- | | `location_ids` | query | string | Yes | JSON array string of location IDs | **Responses** | Code | Description | | ----- | ----------------------------------------- | | `200` | Successfully retrieved inventory items | | `400` | Missing or invalid location_ids parameter | | `500` | Internal server error | --- ### Get bookings by customer and status `GET /schedule/by-customer-status` Query bookings by customerId and optionally filter by Status using the customerId-Status-index GSI **Parameters** | Name | In | Type | Required | Description | | ------------- | ----- | ------- | -------- | -------------------------------------------- | | `customer_id` | query | string | No | Customer ID (defaults to authenticated user) | | `status` | query | string | No | Filter by specific booking status | | `start_date` | query | string | No | Filter bookings from this date | | `end_date` | query | string | No | Filter bookings until this date | | `page` | query | integer | No | Page number for pagination | | `limit` | query | integer | No | Number of items per page | | `sort_order` | query | string | No | Sort direction | | `lightweight` | query | string | No | Return minimal data for boards | **Responses** | Code | Description | | ----- | ------------------------------- | | `200` | Successfully retrieved bookings | | `400` | Missing required customer_id | | `500` | Internal server error | --- ### Get bookings by location and status `GET /schedule/by-location-status` Query bookings by locationId and optionally filter by Status using the locationId-Status-index GSI **Parameters** | Name | In | Type | Required | Description | | ------------- | ----- | ------- | -------- | --------------------------------- | | `location_id` | query | string | Yes | Location ID to query | | `status` | query | string | No | Filter by specific booking status | | `start_date` | query | string | No | Filter bookings from this date | | `end_date` | query | string | No | Filter bookings until this date | | `page` | query | integer | No | Page number for pagination | | `limit` | query | integer | No | Number of items per page | | `sort_order` | query | string | No | Sort direction | | `lightweight` | query | string | No | Return minimal data for boards | **Responses** | Code | Description | | ----- | ------------------------------- | | `200` | Successfully retrieved bookings | | `400` | Missing required location_id | | `500` | Internal server error | --- ### Get paginated schedules with cursor-based pagination `GET /schedule/schedules/paginated` Retrieves schedules with smart pagination and advanced filtering support **Parameters** | Name | In | Type | Required | Description | | --------- | ----- | ------- | -------- | ------------------------------------ | | `limit` | query | integer | No | Number of items per page | | `cursor` | query | string | No | Base64 encoded cursor for pagination | | `filters` | query | string | No | JSON encoded filter criteria | **Responses** | Code | Description | | ----- | ------------------------------------------ | | `200` | Successfully retrieved paginated schedules | | `400` | Invalid cursor or filters format | | `401` | Customer ID not found | | `500` | Failed to fetch schedules | --- ### Get total count of schedules `GET /schedule/schedules/count` Returns the total count of schedules for the authenticated customer with optional filtering **Parameters** | Name | In | Type | Required | Description | | --------- | ----- | ------ | -------- | ---------------------------- | | `filters` | query | string | No | JSON encoded filter criteria | **Responses** | Code | Description | | ----- | ---------------------------- | | `200` | Successfully retrieved count | | `400` | Invalid filters format | | `401` | Customer ID not found | | `500` | Failed to count schedules | --- ## Booking Payments ### Authorize a deposit `POST /preAuth/authorize-deposit` Creates a pre-authorization for a security/damage deposit using Stripe or terminal payment **Request body** | Field | Type | Required | Description | | -------------------- | ------ | -------- | --------------------------------------------------- | | `rentalId` | string | Yes | The ID of the rental/booking | | `authorizeAmount` | number | Yes | Amount to authorize in dollars | | `currency` | string | No | Currency code | | `description` | string | No | Description for the payment | | `customer` | string | No | Stripe customer ID | | `paymentMethodType` | string | Yes | Payment method type | | `paymentMethodId` | string | No | Stripe payment method ID (required for stripe type) | | `notes` | string | No | Notes for the deposit | | `readerId` | string | No | Terminal reader ID (for terminal payments) | | `connectedAccountId` | string | No | Stripe connected account ID | | `platformFeePercent` | number | No | Platform fee percentage | | `customerId` | string | No | Customer ID | | `locationId` | string | No | Location ID | **Responses** | Code | Description | | ----- | ----------------------------------------------------- | | `200` | Deposit pre-authorization successful | | `400` | Missing required fields or unsupported payment method | | `500` | Server error | --- ### Finalize a deposit `POST /preAuth/post-deposit` Records the deposit information in the booking record after terminal payment completes **Request body** | Field | Type | Required | Description | | ----------------- | ------ | -------- | ---------------------------- | | `rentalId` | string | Yes | The ID of the rental/booking | | `authorizeAmount` | number | No | Amount that was authorized | | `customerId` | string | No | Customer ID | | `locationId` | string | No | Location ID | | `notes` | string | No | Notes for the deposit | | `intentId` | string | Yes | Stripe PaymentIntent ID | | `connectId` | string | No | Stripe connected account ID | **Responses** | Code | Description | | ----- | ------------------------------------------------- | | `200` | Deposit finalized successfully | | `400` | Missing required fields or payment not successful | | `500` | Server error | --- ### Capture a deposit `POST /preAuth/capture-deposit` Captures a pre-authorized deposit payment for checkout or damage claims **Request body** | Field | Type | Required | Description | | -------------------- | ------ | -------- | ---------------------------------- | | `rentalId` | string | Yes | The ID of the rental/booking | | `paymentIntentId` | string | Yes | Stripe PaymentIntent ID to capture | | `captureAmount` | number | Yes | Amount to capture in dollars | | `connectedAccountId` | string | No | Stripe connected account ID | | `description` | string | No | Description for the capture | | `claimType` | string | No | Type of claim | | `feeInCents` | number | No | Platform fee in cents | | `locationId` | string | No | Location ID | **Responses** | Code | Description | | ----- | ----------------------------------------------------- | | `200` | Deposit captured successfully | | `400` | Missing required fields or payment cannot be captured | | `404` | Payment intent not found | | `500` | Server error | --- ### Release a deposit `POST /preAuth/release-deposit` Releases (cancels) a pre-authorized deposit that won't be charged **Request body** | Field | Type | Required | Description | | -------------------- | ------ | -------- | ---------------------------------- | | `rentalId` | string | Yes | The ID of the rental/booking | | `paymentIntentId` | string | Yes | Stripe PaymentIntent ID to release | | `amount` | number | No | Amount being released | | `customerId` | string | No | Customer ID for notification | | `locationId` | string | No | Location ID for notification | | `connectedAccountId` | string | No | Stripe connected account ID | **Responses** | Code | Description | | ----- | ----------------------------- | | `200` | Deposit released successfully | | `400` | Missing required fields | | `500` | Server error | --- ### Sync missing pre-authorization `POST /preAuth/sync-missing-preauth/{paymentIntentId}` Recovery endpoint to manually sync a missing pre-authorization from Stripe to database **Parameters** | Name | In | Type | Required | Description | | ----------------- | ---- | ------ | -------- | ------------------------------- | | `paymentIntentId` | path | string | Yes | Stripe PaymentIntent ID to sync | **Request body** | Field | Type | Required | Description | | ------------ | ------ | -------- | ------------------------------------- | | `rentalId` | string | No | Override rental ID if not in metadata | | `locationId` | string | No | Location ID for Stripe region | **Responses** | Code | Description | | ----- | ------------------------------------- | | `200` | Pre-authorization synced successfully | | `400` | Missing paymentIntentId or rentalId | | `404` | PaymentIntent not found | | `500` | Server error | --- ### Audit pre-authorizations `GET /preAuth/audit-preauths/{rentalId}` Retrieves all pre-authorizations for a rental from Stripe with status and expiration details **Parameters** | Name | In | Type | Required | Description | | ---------------------- | ----- | ------ | -------- | ---------------------------------------------- | | `rentalId` | path | string | Yes | The rental ID to audit | | `locationId` | query | string | No | Location ID for Stripe region | | `connected_account_id` | query | string | No | Stripe connected account ID for direct charges | **Responses** | Code | Description | | ----- | ----------------------------------- | | `200` | Audit results returned successfully | | `500` | Server error | --- ### Create terminal connection token `POST /preAuth/connection-token` Creates a Stripe Terminal connection token for terminal payments **Request body** | Field | Type | Required | Description | | ------------ | ------ | -------- | ----------------------------- | | `locationId` | string | No | Location ID for Stripe region | **Responses** | Code | Description | | ----- | ------------------------------------- | | `200` | Connection token created successfully | | `500` | Server error | --- --- # Customers API Source: https://docs.rentaltide.com/api-reference/customers/ > Look up and manage customer records and renters Endpoints for managing customer records, renter profiles, and pending renter approvals. ## Customers ### Get customer for authenticated user `GET /customer` Retrieves the customer record associated with the authenticated user **Responses** | Code | Description | | ----- | ------------------------------- | | `200` | Successfully retrieved customer | | `401` | Unauthorized | | `404` | User or customer not found | | `500` | Server error | --- ### Update customer `PATCH /customer` Updates the customer record associated with the authenticated user. Handles subscription changes via Stripe. **Request body** | Field | Type | Required | Description | | -------------- | ------ | -------- | ------------------------------------------- | | `name` | string | No | | | `email` | string | No | | | `permissions` | object | No | | | `integrations` | object | No | Integration settings (merged with existing) | **Responses** | Code | Description | | ----- | ---------------------------------------------- | | `200` | Customer updated successfully | | `400` | No data provided or subscription change failed | | `401` | Unauthorized | | `404` | Customer not found | | `500` | Server error | --- ### Create a new customer `POST /customer` Creates a new customer record and associates it with the authenticated user. Also creates a Stripe customer. **Request body** | Field | Type | Required | Description | | --------------- | ------ | -------- | ----------------------------------------------- | | `name` | string | Yes | | | `email` | string | No | | | `business_name` | string | No | | | `affiliateCode` | string | No | Affiliate/partner code for tracking conversions | | `permissions` | object | No | | **Responses** | Code | Description | | ----- | ----------------------------- | | `201` | Customer created successfully | | `400` | Customer name is required | | `401` | Unauthorized | | `500` | Server error | --- ### Create Stripe customer `POST /customer/create-stripe-customer` Creates a Stripe customer for an existing customer if one does not already exist **Responses** | Code | Description | | ----- | ----------------------------------------- | | `200` | Stripe customer created or already exists | | `401` | Unauthorized | | `404` | Customer not found | | `500` | Server error | --- ### Attach payment method `POST /customer/payment-method` Attaches a payment method to the customer's Stripe account and sets it as default **Request body** | Field | Type | Required | Description | | ----------------- | ------ | -------- | ------------------------ | | `paymentMethodId` | string | Yes | Stripe payment method ID | **Responses** | Code | Description | | ----- | ------------------------------------- | | `200` | Payment method attached successfully | | `400` | Payment method ID is required | | `401` | Unauthorized | | `404` | Customer or Stripe customer not found | | `500` | Server error | --- ### Create Stripe SetupIntent `POST /customer/create-setup-intent` Creates a SetupIntent for setting up a payment method via Stripe Elements **Responses** | Code | Description | | ----- | ------------------------------------- | | `200` | SetupIntent created successfully | | `401` | Unauthorized | | `404` | Customer or Stripe customer not found | | `500` | Server error | --- ### Get saved payment methods `GET /customer/payment-methods` Retrieves all saved payment methods for the customer from Stripe **Responses** | Code | Description | | ----- | -------------------------------------- | | `200` | Successfully retrieved payment methods | | `401` | Unauthorized | | `404` | Customer or Stripe customer not found | | `500` | Server error | --- ### Get subscription details `GET /customer/subscription` Retrieves the customer's current subscription details from Stripe **Responses** | Code | Description | | ----- | ----------------------------------- | | `200` | Successfully retrieved subscription | | `401` | Unauthorized | | `404` | Customer not found | | `500` | Server error | --- ### Cancel subscription `POST /customer/cancel-subscription` Cancels the customer's subscription at the end of the current billing period **Responses** | Code | Description | | ----- | --------------------------------------- | | `200` | Subscription scheduled for cancellation | | `401` | Unauthorized | | `404` | No active subscription found | | `500` | Server error | --- ### Reactivate subscription `POST /customer/reactivate-subscription` Reactivates a subscription that was scheduled for cancellation **Responses** | Code | Description | | ----- | ------------------------------------- | | `200` | Subscription reactivated successfully | | `401` | Unauthorized | | `404` | No active subscription found | | `500` | Server error | --- ## Renters ### Get paginated list of renters `GET /renters` Fetches renters with server-side search, filtering, sorting, and optional accounting enrichment **Parameters** | Name | In | Type | Required | Description | | ------------------- | ----- | ------- | -------- | --------------------------------------------------------------- | | `customerId` | query | string | Yes | The customer ID to filter renters by | | `page` | query | integer | No | Page number for pagination | | `limit` | query | integer | No | Number of renters per page (max 100) | | `includeAccounting` | query | boolean | No | Include accounting data (balance, debits, credits) | | `search` | query | string | No | Search term to filter renters by name, email, phone, or license | | `status` | query | string | No | Filter by renter status | | `sortField` | query | string | No | Field to sort by | | `sortDirection` | query | string | No | Sort direction | **Responses** | Code | Description | | ----- | ------------------------------------- | | `200` | Successfully retrieved renters | | `400` | Missing required customerId parameter | | `401` | Unauthorized access | | `500` | Server error | --- ### Create or update a renter `POST /renters` Creates a new renter or updates an existing one if email and customerId match. Also creates a Stripe customer if needed. **Request body** | Field | Type | Required | Description | | --------------------- | ------ | -------- | ----------- | | `firstName` | string | Yes | | | `lastName` | string | Yes | | | `email` | string | Yes | | | `address` | string | Yes | | | `customerId` | string | Yes | | | `dob` | string | No | | | `waivers_signed_urls` | array | No | | | `id_verifications` | object | No | | | `transactions` | array | No | | | `additional_info` | object | No | | | `stripe_customer_id` | string | No | | **Responses** | Code | Description | | ----- | ------------------------------------ | | `200` | Existing renter updated successfully | | `201` | New renter created successfully | | `400` | Missing required fields | | `500` | Server error | --- ### Export renters data `GET /renters/export` Export renters data as CSV or JSON format with optional filtering **Parameters** | Name | In | Type | Required | Description | | ------------------- | ----- | ------- | -------- | ------------------------------------ | | `customerId` | query | string | Yes | The customer ID to filter renters by | | `format` | query | string | No | Export format | | `includeAccounting` | query | boolean | No | Include accounting data in export | | `search` | query | string | No | Search term to filter renters | | `status` | query | string | No | Filter by renter status | | `sortField` | query | string | No | Field to sort by | | `sortDirection` | query | string | No | Sort direction | **Responses** | Code | Description | | ----- | ---------------------------------- | | `200` | Successfully exported renters data | | `400` | Invalid request parameters | | `401` | Unauthorized access | | `500` | Server error | --- ### Get search suggestions for autocomplete `GET /renters/search-suggestions` Returns suggestions based on renter names, emails, phone numbers, and license numbers **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | ----------------------------------- | | `customerId` | query | string | Yes | The customer ID to search within | | `query` | query | string | Yes | Search query (minimum 2 characters) | **Responses** | Code | Description | | ----- | ------------------------------------- | | `200` | Successfully retrieved suggestions | | `400` | Missing required customerId parameter | | `401` | Unauthorized access | | `500` | Server error | --- ### Get a single renter by ID `GET /renters/{id}` Fetches a single renter with their accounting information **Parameters** | Name | In | Type | Required | Description | | ---- | ---- | ------ | -------- | ------------- | | `id` | path | string | Yes | The renter ID | **Responses** | Code | Description | | ----- | ----------------------------- | | `200` | Successfully retrieved renter | | `400` | Renter ID is required | | `401` | Unauthorized access | | `404` | Renter not found | | `500` | Server error | --- ### Update a renter `PATCH /renters/{id}` Updates renter fields. Can also append notes using add_note flag. **Parameters** | Name | In | Type | Required | Description | | ---- | ---- | ------ | -------- | ------------- | | `id` | path | string | Yes | The renter ID | **Request body** | Field | Type | Required | Description | | ----------------- | ------- | -------- | -------------------------------------------- | | `add_note` | boolean | No | If true, appends the note to the notes array | | `note` | object | No | Note to append (used with add_note) | | `firstName` | string | No | | | `lastName` | string | No | | | `email` | string | No | | | `address` | string | No | | | `status` | string | No | | | `riskScore` | number | No | | | `additional_info` | object | No | | | `transactions` | array | No | Transactions are appended to existing array | **Responses** | Code | Description | | ----- | ------------------------------------------- | | `200` | Renter updated successfully | | `400` | Invalid request or no valid fields provided | | `401` | Unauthorized access | | `404` | Renter not found | | `500` | Server error | --- ### Delete a renter `DELETE /renters/{id}` Deletes a renter from DynamoDB and also deletes the associated Stripe customer **Parameters** | Name | In | Type | Required | Description | | ---- | ---- | ------ | -------- | ------------- | | `id` | path | string | Yes | The renter ID | **Responses** | Code | Description | | ----- | --------------------------- | | `200` | Renter deleted successfully | | `400` | Renter ID is required | | `401` | Unauthorized access | | `404` | Renter not found | | `500` | Server error | --- ### Attach a payment method to a renter `POST /renters/{id}/payment-method` Attaches a payment method to the renter's Stripe customer and sets it as the default **Parameters** | Name | In | Type | Required | Description | | ---- | ---- | ------ | -------- | ------------- | | `id` | path | string | Yes | The renter ID | **Request body** | Field | Type | Required | Description | | ------------------- | ------ | -------- | ------------------------ | | `payment_method_id` | string | Yes | Stripe payment method ID | **Responses** | Code | Description | | ----- | ------------------------------------------ | | `200` | Payment method added successfully | | `400` | Renter ID or payment method ID is required | | `404` | Renter or Stripe customer not found | | `500` | Server error | --- ### Get renters with outstanding balances `GET /owing/renters` Fetches all renters who owe money (balance >= $1) with optional historical date filtering **Parameters** | Name | In | Type | Required | Description | | ---------- | ----- | ------ | -------- | ------------------------------------------------------------- | | `asOfDate` | query | string | No | Calculate balances as of this date (for historical reporting) | **Responses** | Code | Description | | ----- | -------------------------------------------------------- | | `200` | Successfully retrieved renters with outstanding balances | | `500` | Server error | --- ### Get journal entries for a renter `GET /renters/journal-entries/{id}` Fetches all non-deleted journal entries for a specific renter **Parameters** | Name | In | Type | Required | Description | | ---- | ---- | ------ | -------- | ------------- | | `id` | path | string | Yes | The renter ID | **Responses** | Code | Description | | ----- | -------------------------------------- | | `200` | Successfully retrieved journal entries | | `400` | Renter ID is required | | `401` | Unauthorized access | | `404` | Renter not found | | `500` | Server error | --- ### Get renter's saved payment methods `GET /renters/{id}/payment-methods` Retrieves all saved payment methods (cards) for a renter from Stripe **Parameters** | Name | In | Type | Required | Description | | ---- | ---- | ------ | -------- | ----------- | | `id` | path | string | Yes | Renter ID | **Responses** | Code | Description | | ----- | ----------------------------------------- | | `200` | Payment methods retrieved successfully | | `404` | Renter not found or no Stripe customer ID | | `500` | Server error | --- ## Pending Renters ### Create a new waiver number `POST /pending-renters` Creates a new waiver number with a unique PIN for waiver signing **Request body** | Field | Type | Required | Description | | --------------- | ------ | -------- | --------------- | | `customerId` | string | Yes | The customer ID | | `locationId` | string | No | The location ID | | `firstName` | string | No | | | `lastName` | string | No | | | `email` | string | No | | | `phone` | string | No | | | `dob` | string | No | | | `address` | object | No | | | `assignTo` | string | No | | | `assetId` | string | No | | | `transactionId` | string | No | | | `renterId` | string | No | | | `templateId` | string | No | | | `rawData` | object | No | | **Responses** | Code | Description | | ----- | ---------------------------------- | | `201` | Waiver number created successfully | | `400` | Missing required customerId | | `409` | Waiver number already exists | | `500` | Could not create waiver number | --- ### Get waiver numbers `GET /pending-renters` Retrieves waiver numbers by transactionId, customerId, or locationId **Parameters** | Name | In | Type | Required | Description | | --------------- | ----- | ------ | -------- | ---------------------------------------------- | | `transactionId` | query | string | No | Transaction ID to filter by | | `customerId` | query | string | No | Customer ID to filter by | | `locationId` | query | string | No | Location ID to filter by | | `status` | query | string | No | Status to filter by (e.g., PENDING, COMPLETED) | **Responses** | Code | Description | | ----- | ---------------------------------------------------- | | `200` | Waiver numbers retrieved successfully | | `400` | transactionId, customerId, or locationId is required | | `500` | Could not fetch waiver numbers | --- ### Validate a waiver PIN `GET /pending-renters/validate` Validates a PIN and returns waiver details if valid and not expired **Parameters** | Name | In | Type | Required | Description | | ----- | ----- | ------ | -------- | ------------------- | | `pin` | query | string | Yes | The PIN to validate | **Responses** | Code | Description | | ----- | --------------------------------------- | | `200` | PIN validated successfully | | `400` | PIN is required | | `404` | Invalid PIN or waiver already completed | | `410` | Waiver has expired | | `500` | Could not validate PIN | --- ### Update a waiver number `PATCH /pending-renters/{waiverNumber}` Updates waiver details with optimistic locking support **Parameters** | Name | In | Type | Required | Description | | -------------- | ---- | ------ | -------- | --------------------------- | | `waiverNumber` | path | string | Yes | The waiver number to update | **Request body** | Field | Type | Required | Description | | ----------------- | ------ | -------- | ---------------------- | | `firstName` | string | No | | | `lastName` | string | No | | | `email` | string | No | | | `phone` | string | No | | | `dob` | string | No | | | `address` | object | No | | | `assignTo` | string | No | | | `assetId` | string | No | | | `status` | string | No | | | `renterId` | string | No | | | `waiverUrl` | string | No | | | `templateId` | string | No | | | `expectedVersion` | string | No | For optimistic locking | **Responses** | Code | Description | | ----- | ----------------------------------------------------- | | `200` | Waiver updated successfully | | `400` | waiverNumber is required or no valid fields to update | | `404` | Waiver number not found | | `409` | Record has been modified by another user | | `500` | Could not update waiver number | --- ### Delete a waiver number `DELETE /pending-renters/{waiverNumber}` Deletes a waiver number (only if it is in pending status) **Parameters** | Name | In | Type | Required | Description | | -------------- | ---- | ------ | -------- | --------------------------- | | `waiverNumber` | path | string | Yes | The waiver number to delete | **Responses** | Code | Description | | ----- | -------------------------------------- | | `200` | Waiver number deleted successfully | | `400` | waiverNumber is required | | `409` | Can only delete pending waiver numbers | | `500` | Could not delete waiver number | --- ### Complete a waiver `PATCH /pending-renters/{waiverNumber}/complete` Marks a waiver as completed, removes the PIN, and optionally updates the renter record **Parameters** | Name | In | Type | Required | Description | | -------------- | ---- | ------ | -------- | ----------------------------- | | `waiverNumber` | path | string | Yes | The waiver number to complete | **Request body** | Field | Type | Required | Description | | ----------------- | ------ | -------- | ---------------------------------------- | | `renterId` | string | Yes | The renter ID | | `waiverUrl` | string | Yes | URL to the completed waiver | | `signatureId` | string | No | | | `completionData` | object | No | Additional data to store with the waiver | | `expectedVersion` | string | No | For optimistic locking | **Responses** | Code | Description | | ----- | ---------------------------------------------------- | | `200` | Waiver completed successfully | | `400` | waiverNumber, renterId, and waiverUrl are required | | `404` | Waiver number not found | | `409` | Waiver is not in pending status or has been modified | | `500` | Could not complete waiver | --- --- # Integrations API Source: https://docs.rentaltide.com/api-reference/integrations/ > Connect with Google Calendar, Viator, Wave, and more Endpoints for managing third-party integrations including Google Calendar sync, Google Things to Do, Viator, vQuip fleet management, Wave accounting, voice services, and shipment tracking. ## Integrations ### Get GPS alerts for a location `GET /integrations/alerts` Retrieves OneStepGPS alerts from a specific location within a time range **Parameters** | Name | In | Type | Required | Description | | --------- | ----- | ------- | -------- | ----------------------------------------- | | `minutes` | query | integer | No | Number of minutes to look back for alerts | | `limit` | query | integer | No | Maximum number of alerts to return | **Responses** | Code | Description | | ----- | --------------------- | | `200` | List of alerts | | `500` | Internal server error | --- ### Get GPS alerts for a specific device `GET /integrations/device-alerts/{deviceName}` Retrieves OneStepGPS alerts for a specific device within a time range **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------- | -------- | ----------------------------------------- | | `deviceName` | path | string | Yes | The name of the GPS device | | `minutes` | query | integer | No | Number of minutes to look back for alerts | | `limit` | query | integer | No | Maximum number of alerts to return | **Responses** | Code | Description | | ----- | --------------------- | | `200` | List of device alerts | | `500` | Internal server error | --- ### Get alert summary by device `GET /integrations/alert-summary` Retrieves a summary of alert counts grouped by device name for a location **Parameters** | Name | In | Type | Required | Description | | ------- | ----- | ------- | -------- | ---------------------------------------------- | | `hours` | query | integer | No | Number of hours to look back for alert summary | **Responses** | Code | Description | | ----- | ----------------------- | | `200` | Alert summary by device | | `500` | Internal server error | --- ## Google Calendar ### Initiate Google Calendar OAuth flow `GET /integrations/google-calendar/connect` Starts the Google Calendar OAuth2 authorization flow. Returns an authorization URL to redirect the user to. **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | ------------------------------------- | | `userId` | query | string | Yes | The user ID initiating the connection | | `customerId` | query | string | Yes | The customer/business ID | **Responses** | Code | Description | | ----- | --------------------------------------------- | | `200` | Authorization URL generated successfully | | `400` | Missing userId or customerId | | `500` | Failed to initiate Google Calendar connection | --- ### Google Calendar OAuth callback `GET /integrations/google-calendar/callback` Handles the OAuth2 callback from Google, exchanges the code for tokens, and stores the encrypted credentials **Parameters** | Name | In | Type | Required | Description | | ------- | ----- | ------ | -------- | -------------------------------------- | | `code` | query | string | Yes | Authorization code from Google | | `state` | query | string | Yes | State token to validate the request | | `error` | query | string | No | Error code if authorization was denied | **Responses** | Code | Description | | ----- | -------------------------------------------------------- | | `200` | Returns HTML page with postMessage to close popup | | `302` | Redirects to frontend with error if authorization denied | | `400` | Missing code/state or invalid state token | --- ### Disconnect Google Calendar `POST /integrations/google-calendar/disconnect` Revokes Google Calendar access and removes stored credentials for a user **Request body** | Field | Type | Required | Description | | -------- | ------ | -------- | ------------------------- | | `userId` | string | Yes | The user ID to disconnect | **Responses** | Code | Description | | ----- | ----------------------------------------- | | `200` | Google Calendar disconnected successfully | | `400` | Missing userId | | `500` | Failed to disconnect Google Calendar | --- ### Get calendar connection status `GET /integrations/google-calendar/status` Returns the Google Calendar connection status for a user **Parameters** | Name | In | Type | Required | Description | | -------- | ----- | ------ | -------- | -------------------- | | `userId` | query | string | Yes | The user ID to check | **Responses** | Code | Description | | ----- | ---------------------------------------- | | `200` | Connection status retrieved successfully | | `400` | Missing userId | | `500` | Failed to get calendar status | --- ### Get available calendars `GET /integrations/google-calendar/calendars` Returns the list of Google Calendars available to the user **Parameters** | Name | In | Type | Required | Description | | -------- | ----- | ------ | -------- | ----------- | | `userId` | query | string | Yes | The user ID | **Responses** | Code | Description | | ----- | ----------------------------------------------- | | `200` | Calendars retrieved successfully | | `400` | Missing userId or Google Calendar not connected | | `500` | Failed to fetch calendars | --- ### Update selected calendar `POST /integrations/google-calendar/update-calendar` Changes the calendar used for syncing bookings **Request body** | Field | Type | Required | Description | | ------------ | ------ | -------- | ----------------------------- | | `userId` | string | Yes | The user ID | | `calendarId` | string | Yes | The Google Calendar ID to use | **Responses** | Code | Description | | ----- | ---------------------------------------------------------- | | `200` | Calendar updated successfully | | `400` | Missing userId/calendarId or Google Calendar not connected | | `500` | Failed to update calendar | --- ### Trigger manual calendar sync `POST /integrations/google-calendar/sync` Manually triggers a full calendar sync job. Primarily for testing and debugging. **Responses** | Code | Description | | ----- | ---------------------- | | `200` | Sync job started | | `500` | Failed to trigger sync | --- ## Google Things To Do ### Get schema for inventory item `GET /schema/inventory/{inventoryId}` Returns JSON-LD structured data for a single inventory item, formatted for Google Search rich results (Things to Do) **Parameters** | Name | In | Type | Required | Description | | ------------- | ----- | ------ | -------- | ----------------------------- | | `inventoryId` | path | string | Yes | The inventory item ID | | `baseUrl` | query | string | No | Base URL for generating links | **Responses** | Code | Description | | ----- | ------------------------------------- | | `200` | JSON-LD schema for the inventory item | | `403` | Inventory is not publicly visible | | `404` | Inventory or location not found | | `500` | Internal server error | --- ### Get schema for location `GET /schema/location/{locationId}` Returns JSON-LD LocalBusiness schema for a location including all its public inventory items **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | ----------------------------- | | `locationId` | path | string | Yes | The location ID | | `baseUrl` | query | string | No | Base URL for generating links | **Responses** | Code | Description | | ----- | --------------------------------------------- | | `200` | JSON-LD LocalBusiness schema for the location | | `404` | Location not found | | `500` | Internal server error | --- ### Get all schemas for customer `GET /schema/all/{customerId}` Returns an array of JSON-LD schemas for all locations and their public inventory belonging to a customer **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | ----------------------------- | | `customerId` | path | string | Yes | The customer/business ID | | `baseUrl` | query | string | No | Base URL for generating links | **Responses** | Code | Description | | ----- | ------------------------------- | | `200` | Array of JSON-LD schemas | | `404` | No locations found for customer | | `500` | Internal server error | --- ## Viator Integration ### Configure Viator integration `POST /viator/admin/configure` Create or update the Viator marketplace configuration for a customer. Uses JWT auth (admin only). **Request body** | Field | Type | Required | Description | | -------------- | ------- | -------- | ---------------------------------------------------------- | | `customerId` | string | Yes | | | `supplierId` | string | Yes | | | `apiKey` | string | Yes | Inbound API key for Viator to authenticate with RentalTide | | `viatorApiKey` | string | No | Outbound API key for sending notifications to Viator | | `currency` | string | No | | | `isActive` | boolean | No | | **Responses** | Code | Description | | ----- | -------------------------------- | | `200` | Configuration saved successfully | | `400` | Missing required fields | | `500` | Internal server error | --- ### Tour List (V1) `POST /viator/tourlist` Returns the full product catalog for this supplier. Authenticated via Viator API key. **Responses** | Code | Description | | ----- | ---------------------- | | `200` | List of tours/products | | `401` | Unauthorized | --- ### Calendar availability (V2) `POST /viator/v2/availability/calendar` Returns availability and pricing for a date range across products. **Request body** | Field | Type | Required | Description | | ------------------ | ------ | -------- | ----------- | | `productOptionIds` | array | Yes | | | `startDate` | string | Yes | | | `endDate` | string | Yes | | **Responses** | Code | Description | | ----- | -------------------------- | | `200` | Calendar availability data | | `400` | Missing required fields | --- ### Availability check (V2) `POST /viator/v2/availability/check` Real-time capacity check for specific products, dates, and traveler counts. **Request body** | Field | Type | Required | Description | | ---------------- | ------ | -------- | ----------- | | `productOptions` | array | Yes | | | `travelDate` | string | Yes | | **Responses** | Code | Description | | ----- | ------------------------------- | | `200` | Availability status per product | | `400` | Missing required fields | --- ### Reserve inventory (V2) `POST /viator/v2/reserve` Hold inventory for 15+ minutes while Viator processes payment. **Request body** | Field | Type | Required | Description | | ----------------- | ------- | -------- | ----------- | | `productOptionId` | string | Yes | | | `travelDate` | string | Yes | | | `startTime` | string | No | | | `tickets` | array | No | | | `totalTravelers` | integer | No | | **Responses** | Code | Description | | ----- | ---------------------------------------- | | `200` | Reservation created with expiration time | | `400` | Missing required fields | | `404` | Product not found | --- ### Confirm booking (V1) `POST /viator/booking` Confirm a previously reserved booking after Viator has processed payment. **Responses** | Code | Description | | ----- | ----------------------------- | | `200` | Booking confirmed or rejected | --- ### Cancel booking (V1) `POST /viator/booking-cancellation` Cancel a confirmed Viator booking. **Responses** | Code | Description | | ----- | ---------------------------------- | | `200` | Cancellation confirmed or rejected | --- ### Special offers (V2) `POST /viator/v2/product/special-offers` Returns active promotions and special offers. **Responses** | Code | Description | | ----- | ------------------------------------------------ | | `200` | List of special offers (currently returns empty) | --- ### Amend booking (V1) `POST /viator/booking-amendment` Modify an existing booking (date change, traveler details). **Responses** | Code | Description | | ----- | ------------------------------- | | `200` | Amendment confirmed or rejected | --- ### Unified dispatcher (all request types) `POST /viator/api` Single endpoint that accepts all Viator request types via a `requestType` discriminator. Auth is read from `data.ApiKey` in the request body instead of headers. **Request body** | Field | Type | Required | Description | | ------------- | ------ | -------- | ----------- | | `requestType` | string | Yes | | | `data` | object | Yes | | **Responses** | Code | Description | | ----- | ------------------------------------ | | `200` | Response from the dispatched handler | | `400` | Missing or unknown requestType | | `401` | Invalid or missing ApiKey in data | --- ## vQuip ### Check vQuip integration status `GET /vquip/status` Check if the current customer has an active vQuip integration. **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | --------------- | | `customerId` | query | string | Yes | The customer ID | **Responses** | Code | Description | | ----- | ----------------------------------------- | | `200` | Integration status retrieved successfully | | `400` | customerId is required | | `500` | Failed to check vQuip status | --- ### Connect vQuip integration `POST /vquip/connect` Save vQuip credentials, test the connection, and activate the integration. **Request body** | Field | Type | Required | Description | | -------------- | ------ | -------- | ----------- | | `customerId` | string | Yes | | | `clientId` | string | Yes | | | `clientSecret` | string | Yes | | | `tokenUrl` | string | Yes | | **Responses** | Code | Description | | ----- | ----------------------------------------------------- | | `200` | vQuip connected successfully | | `400` | Missing required parameters or connection test failed | | `500` | Failed to connect vQuip | --- ### Disconnect vQuip integration `DELETE /vquip/disconnect` Deactivate the vQuip integration for the customer. **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | --------------- | | `customerId` | query | string | Yes | The customer ID | **Responses** | Code | Description | | ----- | ------------------------------- | | `200` | vQuip disconnected successfully | | `400` | customerId is required | | `500` | Failed to disconnect vQuip | --- ### Get vQuip inventory types `GET /vquip/inventory-types` Fetch all inventory types from the connected vQuip account. **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | --------------- | | `customerId` | query | string | Yes | The customer ID | **Responses** | Code | Description | | ----- | -------------------------------------- | | `200` | Inventory types retrieved successfully | | `400` | vQuip not configured for this customer | | `500` | Failed to get inventory types | --- ### Get vQuip products `GET /vquip/products` Fetch all products from the connected vQuip account. **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | --------------- | | `customerId` | query | string | Yes | The customer ID | **Responses** | Code | Description | | ----- | -------------------------------------- | | `200` | Products retrieved successfully | | `400` | vQuip not configured for this customer | | `500` | Failed to get products | --- ### Get vQuip reservations `GET /vquip/reservations` Fetch reservations from vQuip by external booking ID. **Parameters** | Name | In | Type | Required | Description | | ------------------- | ----- | ------ | -------- | --------------------------------------------- | | `customerId` | query | string | Yes | The customer ID | | `externalBookingId` | query | string | Yes | The RentalTide booking ID to look up in vQuip | **Responses** | Code | Description | | ----- | --------------------------------------------------- | | `200` | Reservations retrieved successfully | | `400` | Missing required parameters or vQuip not configured | | `500` | Failed to get reservations | --- ### Create a vQuip reservation `POST /vquip/reservations` Push a RentalTide booking to vQuip as a new reservation. **Request body** | Field | Type | Required | Description | | ------------------- | ------ | -------- | ----------- | | `customerId` | string | Yes | | | `externalBookingId` | string | Yes | | | `startDate` | string | Yes | | | `endDate` | string | Yes | | | `productId` | string | Yes | | | `customerName` | string | Yes | | | `customerEmail` | string | No | | | `customerPhone` | string | No | | | `totalAmount` | number | No | | | `notes` | string | No | | **Responses** | Code | Description | | ----- | --------------------------------------------------- | | `201` | Reservation created successfully | | `400` | Missing required parameters or vQuip not configured | | `500` | Failed to create reservation | --- ### Update a vQuip reservation `PUT /vquip/reservations/{reservationId}` Update an existing reservation in vQuip. **Parameters** | Name | In | Type | Required | Description | | --------------- | ---- | ------ | -------- | ------------------------ | | `reservationId` | path | string | Yes | The vQuip reservation ID | **Request body** | Field | Type | Required | Description | | --------------- | ------ | -------- | ----------- | | `customerId` | string | Yes | | | `startDate` | string | No | | | `endDate` | string | No | | | `productId` | string | No | | | `customerName` | string | No | | | `customerEmail` | string | No | | | `customerPhone` | string | No | | | `totalAmount` | number | No | | | `notes` | string | No | | | `status` | string | No | | **Responses** | Code | Description | | ----- | -------------------------------------- | | `200` | Reservation updated successfully | | `400` | vQuip not configured for this customer | | `500` | Failed to update reservation | --- ### Cancel a vQuip reservation `PUT /vquip/reservations/{reservationId}/cancel` Cancel an existing reservation in vQuip. **Parameters** | Name | In | Type | Required | Description | | --------------- | ---- | ------ | -------- | ------------------------ | | `reservationId` | path | string | Yes | The vQuip reservation ID | **Request body** | Field | Type | Required | Description | | ------------ | ------ | -------- | ----------- | | `customerId` | string | Yes | | **Responses** | Code | Description | | ----- | -------------------------------------- | | `200` | Reservation cancelled successfully | | `400` | vQuip not configured for this customer | | `500` | Failed to cancel reservation | --- ### Create an external invoice on a vQuip reservation `POST /vquip/reservations/{reservationId}/invoice` Create an external invoice linked to a vQuip reservation. **Parameters** | Name | In | Type | Required | Description | | --------------- | ---- | ------ | -------- | ------------------------ | | `reservationId` | path | string | Yes | The vQuip reservation ID | **Request body** | Field | Type | Required | Description | | ------------- | ------ | -------- | ----------- | | `customerId` | string | Yes | | | `amount` | number | Yes | | | `description` | string | No | | **Responses** | Code | Description | | ----- | --------------------------------------------------- | | `201` | Invoice created successfully | | `400` | Missing required parameters or vQuip not configured | | `500` | Failed to create invoice | --- ### Sync a RentalTide booking to vQuip `POST /vquip/sync-booking` Load a booking and create vQuip reservations for each assigned asset with a product mapping. Creates an invoice on the first reservation if totalPrice > 0. **Request body** | Field | Type | Required | Description | | ------------ | ------ | -------- | ----------- | | `rentalId` | string | Yes | | | `customerId` | string | Yes | | | `locationId` | string | Yes | | **Responses** | Code | Description | | ----- | ------------------------------------------ | | `200` | Sync completed | | `400` | Missing parameters or vQuip not configured | | `500` | Sync failed | --- ## Wave Integration ### Initiate Wave OAuth2 flow `GET /auth/wave/connect` Generates an authorization URL to start the Wave OAuth2 connection process. **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | ---------------------------------- | | `businessId` | query | string | Yes | The business ID to connect Wave to | **Responses** | Code | Description | | ----- | ---------------------------------------- | | `200` | Authorization URL generated successfully | | `400` | Business ID required | | `500` | Failed to initiate Wave connection | --- ### Handle Wave OAuth2 callback `GET /auth/wave/callback` Handles the OAuth2 callback from Wave, exchanges authorization code for tokens. **Parameters** | Name | In | Type | Required | Description | | ------- | ----- | ------ | -------- | ----------- | | `code` | query | string | Yes | | | `state` | query | string | Yes | | **Responses** | Code | Description | | ----- | -------------------------------------------- | | `302` | Redirects to frontend with connection status | --- ### Get Wave integration status `GET /wave/integration-status` **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | ----------- | | `businessId` | query | string | Yes | | **Responses** | Code | Description | | ----- | ----------------------------------------- | | `200` | Integration status retrieved successfully | --- ### Disconnect Wave integration `DELETE /wave/disconnect` Disconnects the Wave integration while preserving GL mappings. **Request body** | Field | Type | Required | Description | | ------------ | ------ | -------- | ----------- | | `businessId` | string | Yes | | **Responses** | Code | Description | | ----- | ------------------------------ | | `200` | Wave disconnected successfully | --- ### Fetch chart of accounts from Wave `GET /wave/chart-of-accounts` **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | ----------- | | `businessId` | query | string | Yes | | **Responses** | Code | Description | | ----- | -------------------------------------- | | `200` | Chart of accounts fetched successfully | --- ### Get Wave businesses for the connected account `GET /wave/businesses` **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | ----------- | | `businessId` | query | string | Yes | | **Responses** | Code | Description | | ----- | ------------------------------- | | `200` | Businesses fetched successfully | --- ### Select which Wave business to use `PUT /wave/select-business` **Request body** | Field | Type | Required | Description | | ------------------ | ------ | -------- | ----------- | | `businessId` | string | Yes | | | `waveBusinessId` | string | Yes | | | `waveBusinessName` | string | Yes | | **Responses** | Code | Description | | ----- | ------------------------------ | | `200` | Business selected successfully | --- ### Set bank account for invoice payments `PUT /wave/bank-account` **Request body** | Field | Type | Required | Description | | --------------- | ------ | -------- | ----------- | | `businessId` | string | Yes | | | `bankAccountId` | string | Yes | | **Responses** | Code | Description | | ----- | --------------------------------- | | `200` | Bank account updated successfully | --- ### Get current GL code mappings `GET /wave/gl-mappings` **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | ----------- | | `businessId` | query | string | Yes | | **Responses** | Code | Description | | ----- | ---------------------------------- | | `200` | GL mappings retrieved successfully | --- ### Update GL code mappings `PUT /wave/gl-mappings` **Request body** | Field | Type | Required | Description | | ------------ | ------ | -------- | ----------- | | `businessId` | string | Yes | | | `glMappings` | object | Yes | | **Responses** | Code | Description | | ----- | -------------------------------- | | `200` | GL mappings updated successfully | --- ## Voice ### Handle incoming phone call `POST /communication/voice/incoming-call` Twilio webhook endpoint that handles incoming phone calls. Looks up the location by Twilio phone number, identifies the caller, and generates IVR menu response. **Responses** | Code | Description | | ----- | ---------------------------- | | `200` | TwiML response with IVR menu | --- ### Handle IVR key press `POST /communication/voice/handle-key` Processes DTMF key presses from the IVR menu and executes the corresponding action (dial, voicemail, say message, etc.). **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | ------------------- | | `locationId` | query | string | Yes | The location ID | | `callSid` | query | string | Yes | The Twilio call SID | **Responses** | Code | Description | | ----- | --------------------------------- | | `200` | TwiML response with action result | --- ### Handle sequential dial progression `POST /communication/voice/sequential-dial-next` Handles the progression of sequential dialing when a number doesn't answer. Moves to the next number in the ring list. **Parameters** | Name | In | Type | Required | Description | | -------------- | ----- | ------- | -------- | ----------------------------------- | | `locationId` | query | string | Yes | The location ID | | `callSid` | query | string | Yes | The Twilio call SID | | `currentIndex` | query | integer | Yes | The current index in the ring list | | `ringList` | query | string | Yes | JSON-encoded array of phone numbers | **Responses** | Code | Description | | ----- | --------------------------------------- | | `200` | TwiML response for next dial or message | --- ### Handle recording webhook from Twilio `POST /communication/voice/recording-webhook` Webhook endpoint that receives call recording notifications from Twilio. Processes and uploads recordings to S3. **Responses** | Code | Description | | ----- | -------------------------------- | | `200` | Recording processed successfully | | `400` | Missing required recording data | | `500` | Error processing recording | --- ### Handle voicemail recording completion `POST /communication/voice/handle-recording` Processes a completed voicemail recording and saves it to the database. **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | --------------- | | `locationId` | query | string | Yes | The location ID | **Responses** | Code | Description | | ----- | ------------------------------------- | | `200` | TwiML response with thank you message | --- ### Get recorded calls with pagination `GET /communication/voice/recordings/{locationId}` Retrieves call recordings for a location with pagination and optional type filtering. **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------- | -------- | --------------------------------- | | `locationId` | path | string | Yes | The location ID | | `page` | query | integer | No | Page number | | `limit` | query | integer | No | Number of items per page (max 50) | | `type` | query | string | No | Filter by recording type | **Responses** | Code | Description | | ----- | --------------------------------- | | `200` | Recordings retrieved successfully | | `500` | Failed to fetch recordings | --- ### Get voicemails for a location `GET /communication/voice/voicemails/{locationId}` Legacy endpoint that retrieves voicemails for a specific location, sorted by timestamp descending. **Parameters** | Name | In | Type | Required | Description | | ------------ | ---- | ------ | -------- | --------------- | | `locationId` | path | string | Yes | The location ID | **Responses** | Code | Description | | ----- | --------------------------------- | | `200` | Voicemails retrieved successfully | | `500` | Failed to fetch voicemails | --- ### Delete a voicemail `DELETE /communication/voice/voicemails/{voicemailId}` Permanently deletes a voicemail recording by its ID. **Parameters** | Name | In | Type | Required | Description | | ------------- | ---- | ------ | -------- | ---------------- | | `voicemailId` | path | string | Yes | The voicemail ID | **Responses** | Code | Description | | ----- | ------------------------------ | | `200` | Voicemail deleted successfully | | `500` | Failed to delete voicemail | --- ### Test OpenAI voice generation `GET /communication/voice/test-openai-voice` Test endpoint to verify OpenAI voice generation is working correctly. **Parameters** | Name | In | Type | Required | Description | | ------- | ----- | ------ | -------- | ----------------------------- | | `text` | query | string | No | The text to convert to speech | | `voice` | query | string | No | The OpenAI voice to use | **Responses** | Code | Description | | ----- | ---------------------------- | | `200` | Voice generated successfully | | `500` | OpenAI voice test failed | --- ### Generate voice preview for IVR configuration `GET /communication/voice/voice-preview/{voice}` Generates a preview of a specific OpenAI voice for IVR configuration purposes. **Parameters** | Name | In | Type | Required | Description | | ------- | ---- | ------ | -------- | ------------------------------------------------------ | | `voice` | path | string | Yes | The OpenAI voice identifier (e.g., alloy, echo, fable) | **Responses** | Code | Description | | ----- | ------------------------------------ | | `200` | Voice preview generated successfully | | `500` | Voice preview generation failed | --- ### Configure location to use OpenAI voice `POST /communication/voice/configure-openai/{locationId}` Updates a location's IVR configuration to use OpenAI voice engine with the specified voice. **Parameters** | Name | In | Type | Required | Description | | ------------ | ---- | ------ | -------- | --------------- | | `locationId` | path | string | Yes | The location ID | **Request body** | Field | Type | Required | Description | | ------- | ------ | -------- | ----------------------- | | `voice` | string | No | The OpenAI voice to use | **Responses** | Code | Description | | ----- | ------------------------------------------------- | | `200` | Location configured for OpenAI voice successfully | | `404` | Location not found | | `500` | Failed to configure OpenAI voice | --- ### Get call logs for a location with pagination `GET /communication/voice/logs/{locationId}` Retrieves call logs for a specific location with pagination support. **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------- | -------- | --------------------------------- | | `locationId` | path | string | Yes | The location ID | | `page` | query | integer | No | Page number | | `limit` | query | integer | No | Number of items per page (max 50) | **Responses** | Code | Description | | ----- | -------------------------------- | | `200` | Call logs retrieved successfully | | `500` | Failed to fetch call logs | --- ### Get all call logs (admin view) `GET /communication/voice/call-logs` Retrieves all call logs across all locations for admin purposes. **Parameters** | Name | In | Type | Required | Description | | ------- | ----- | ------- | -------- | -------------------------------- | | `limit` | query | integer | No | Maximum number of logs to return | **Responses** | Code | Description | | ----- | -------------------------------- | | `200` | Call logs retrieved successfully | | `500` | Failed to fetch call logs | --- ### Handle call status webhook from Twilio `POST /communication/voice/call-status` Webhook endpoint that receives call status updates from Twilio and updates the call log. **Responses** | Code | Description | | ----- | ---------------------------- | | `200` | Call status update processed | | `500` | Error updating call status | --- ### Initiate callback call `POST /communication/voice/initiate-callback` Initiates a callback call where the user is called first, then connected to the destination number. Requires authentication. **Request body** | Field | Type | Required | Description | | ------------------ | ------ | -------- | ----------------------------------------------- | | `userPhone` | string | Yes | The user's phone number to call first | | `destinationPhone` | string | Yes | The destination phone number to connect to | | `locationId` | string | Yes | The location ID for caller ID and authorization | **Responses** | Code | Description | | ----- | -------------------------------------------------------- | | `200` | Callback call initiated successfully | | `400` | Missing required parameters | | `403` | Unauthorized - location doesn't belong to user's account | | `404` | Location not found | | `500` | Failed to initiate callback call | --- ### Handle callback call answer `POST /communication/voice/callback-answer` Twilio webhook called when the user answers the callback call. Dials the destination number. **Parameters** | Name | In | Type | Required | Description | | ------------------ | ----- | ------ | -------- | ------------------------------------------ | | `sessionId` | query | string | Yes | The callback session ID | | `destinationPhone` | query | string | Yes | The destination phone number to connect to | **Responses** | Code | Description | | ----- | ---------------------------------- | | `200` | TwiML response to dial destination | --- ### Handle callback call completion `POST /communication/voice/callback-complete` Twilio webhook called when the callback call is completed. Updates call log with final status. **Parameters** | Name | In | Type | Required | Description | | ----------- | ----- | ------ | -------- | ----------------------- | | `sessionId` | query | string | Yes | The callback session ID | **Responses** | Code | Description | | ----- | -------------------------------------- | | `200` | TwiML response with completion message | --- ### Search for customer by phone number `GET /communication/voice/search-renter/{phoneNumber}` Searches for a customer by phone number within the authenticated user's customer records. Requires authentication. **Parameters** | Name | In | Type | Required | Description | | ------------- | ---- | ------ | -------- | ------------------------------ | | `phoneNumber` | path | string | Yes | The phone number to search for | **Responses** | Code | Description | | ----- | ----------------------------- | | `200` | Search result | | `500` | Failed to search for customer | --- ## Shipments ### Create a new incoming shipment `POST /shipments` Creates a new incoming shipment record to track inventory deliveries. **Request body** | Field | Type | Required | Description | | --------------------- | ------ | -------- | ---------------------------------- | | `locationId` | string | Yes | The location ID for the shipment | | `expectedArrivalDate` | string | Yes | Expected arrival date (ISO string) | | `trackingNumber` | string | No | Shipping tracking number | | `notes` | string | No | Additional notes | | `items` | array | Yes | | | `shippingCost` | number | No | | | `importCost` | number | No | | | `taxes` | number | No | | **Responses** | Code | Description | | ----- | ----------------------------- | | `201` | Shipment created successfully | | `400` | Missing required fields | | `500` | Internal server error | --- ### List all shipments for a location `GET /shipments` Retrieves all shipments for a given location. **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | ------------------------------------ | | `locationId` | query | string | Yes | The location ID to get shipments for | **Responses** | Code | Description | | ----- | -------------------------------- | | `200` | Shipments retrieved successfully | | `400` | Missing locationId parameter | | `500` | Internal server error | --- ### Get a single shipment `GET /shipments/{shipmentId}` Retrieves details for a specific shipment. **Parameters** | Name | In | Type | Required | Description | | ------------ | ---- | ------ | -------- | --------------- | | `shipmentId` | path | string | Yes | The shipment ID | **Responses** | Code | Description | | ----- | ------------------------------- | | `200` | Shipment retrieved successfully | | `400` | Missing shipmentId parameter | | `404` | Shipment not found | | `500` | Internal server error | --- ### Delete a shipment `DELETE /shipments/{shipmentId}` Deletes a shipment if it has not been marked as arrived/received. **Parameters** | Name | In | Type | Required | Description | | ------------ | ---- | ------ | -------- | --------------- | | `shipmentId` | path | string | Yes | The shipment ID | **Responses** | Code | Description | | ----- | ---------------------------------------------------- | | `200` | Shipment deleted successfully | | `400` | Missing shipmentId or cannot delete arrived shipment | | `404` | Shipment not found | | `500` | Internal server error | --- ### Mark shipment as arrived `PUT /shipments/{shipmentId}/arrived` Marks a shipment as arrived and updates inventory quantities accordingly. **Parameters** | Name | In | Type | Required | Description | | ------------ | ---- | ------ | -------- | --------------- | | `shipmentId` | path | string | Yes | The shipment ID | **Responses** | Code | Description | | ----- | ------------------------------------------------ | | `200` | Shipment marked as arrived and inventory updated | | `400` | Missing shipmentId or shipment already arrived | | `404` | Shipment not found | | `500` | Internal server error | --- --- # Inventory API Source: https://docs.rentaltide.com/api-reference/inventory/ > Manage your rental fleet, pricing, and product catalog Endpoints for managing inventory items, pricing rules, and inventory records. ## Inventory ### Upload inventory photo `POST /inventory/photo/{inventory_id}` Uploads and optimizes a photo for an inventory item, storing it in S3 **Parameters** | Name | In | Type | Required | Description | | -------------- | ---- | ------ | -------- | -------------------------------- | | `inventory_id` | path | string | Yes | The inventory ID to add photo to | **Responses** | Code | Description | | ----- | ---------------------------------- | | `200` | Photo uploaded successfully | | `400` | Missing inventory_id or photo file | | `500` | Internal server error | --- ### Upload inventory video `POST /inventory/video/{inventory_id}` Uploads a video for an inventory item, storing it in S3 **Parameters** | Name | In | Type | Required | Description | | -------------- | ---- | ------ | -------- | -------------------------------- | | `inventory_id` | path | string | Yes | The inventory ID to add video to | **Responses** | Code | Description | | ----- | ------------------------------------------------------- | | `200` | Video uploaded successfully | | `400` | Missing inventory_id, video file, or unsupported format | | `500` | Internal server error | --- ### Save asset map configuration `POST /inventory/asset-map/{inventory_id}` Saves asset map pin configuration for an inventory item, optionally uploading a map image **Parameters** | Name | In | Type | Required | Description | | -------------- | ---- | ------ | -------- | ------------------------------------------- | | `inventory_id` | path | string | Yes | The inventory ID to configure asset map for | **Responses** | Code | Description | | ----- | ------------------------------------------ | | `200` | Asset map configuration saved successfully | | `400` | Missing inventory_id or invalid pins data | | `403` | Unauthorized to update this inventory | | `404` | Inventory not found | | `500` | Internal server error | --- ### Create or update inventory settings `POST /inventory/setup` Creates or updates an inventory record with all settings including pricing, capacity, and asset pool configuration **Request body** | Field | Type | Required | Description | | ------ | ------ | -------- | ----------- | | `data` | object | Yes | | **Responses** | Code | Description | | ----- | ----------------------------------------------------- | | `200` | Inventory settings updated successfully | | `400` | Missing required data | | `403` | Unauthorized to update inventory for another customer | | `500` | Internal server error | --- ### Get inventory by customer `GET /inventory/customer` Retrieves all inventory items for a given customer ID **Parameters** | Name | In | Type | Required | Description | | ------------- | ----- | ------ | -------- | ------------------------------------ | | `customer_id` | query | string | Yes | The customer ID to get inventory for | **Responses** | Code | Description | | ----- | -------------------------------------- | | `200` | Inventory items retrieved successfully | | `400` | Missing customer_id query parameter | | `500` | Internal server error | --- ### Delete an inventory item `DELETE /inventory/delete/{inventory_id}` Deletes an inventory item by ID **Parameters** | Name | In | Type | Required | Description | | -------------- | ---- | ------ | -------- | -------------------------- | | `inventory_id` | path | string | Yes | The inventory ID to delete | **Responses** | Code | Description | | ----- | ------------------------------------- | | `200` | Inventory deleted successfully | | `400` | Missing inventory_id param | | `403` | Unauthorized to delete this inventory | | `404` | Inventory not found | | `500` | Internal server error | --- ### Reorder inventory items `POST /inventory/reorder` Updates the display order of inventory items **Request body** | Field | Type | Required | Description | | -------------- | ----- | -------- | ----------- | | `orderedBoats` | array | Yes | | **Responses** | Code | Description | | ----- | --------------------------------------------- | | `200` | Order updated successfully | | `400` | Invalid data - orderedBoats array is required | | `500` | Internal server error | --- ## Inventory Pricing ### Get inventory pricing `GET /inventory-pricing` Retrieves pricing configuration for an inventory item including seasons, hourly rates, and addons **Parameters** | Name | In | Type | Required | Description | | -------------- | ----- | ------ | -------- | -------------------------------------------------------------- | | `inventory_id` | query | string | Yes | The inventory ID to get pricing for (also accepts inventoryId) | **Responses** | Code | Description | | ----- | -------------------------------------------------------- | | `200` | Pricing data retrieved successfully | | `400` | Missing inventory_id query parameter or validation error | | `404` | No pricing found for the inventory | | `500` | Internal server error | --- ### Create or update inventory pricing `POST /inventory-pricing` Creates or updates pricing configuration for an inventory item including seasons, schedule exceptions, and addons **Request body** | Field | Type | Required | Description | | ------ | ------ | -------- | ----------- | | `data` | object | Yes | | **Responses** | Code | Description | | ----- | ----------------------------------------- | | `200` | Inventory pricing updated successfully | | `400` | Missing required data or validation error | | `500` | Internal server error | --- ## Inventory Records ### Get inventory records `GET /boatRecords` Retrieves records for an inventory item, optionally filtered by record type **Parameters** | Name | In | Type | Required | Description | | ------------- | ----- | ------ | -------- | ----------------------------------------------- | | `inventoryId` | query | string | Yes | The inventory ID to get records for | | `RecordType` | query | string | No | Filter by record type (e.g., checkout, checkin) | **Responses** | Code | Description | | ----- | ------------------------------ | | `200` | Records retrieved successfully | | `400` | inventoryId is required | | `500` | Internal server error | --- ### Create an inventory record `POST /boatRecords` Creates a new record for an inventory item. May trigger Ship Shape AI analysis for check-in records with photos. **Request body** | Field | Type | Required | Description | | ------------- | ------ | -------- | ------------------------------------------- | | `inventoryId` | string | Yes | The inventory ID | | `RecordType` | string | Yes | Type of record (checkout, checkin, etc.) | | `Details` | object | Yes | Record details | | `RentalId` | string | No | Associated rental ID | | `AssetId` | string | No | Associated asset ID | | `timestamp` | string | No | Record timestamp (defaults to current time) | **Responses** | Code | Description | | ----- | --------------------------- | | `201` | Record created successfully | | `400` | Missing required fields | | `500` | Internal server error | --- ### Update an inventory record `PATCH /boatRecords` Updates an existing record's Details attribute **Request body** | Field | Type | Required | Description | | ------------- | ------ | -------- | --------------------------------------------- | | `inventoryId` | string | Yes | The inventory ID | | `timestamp` | string | Yes | Record timestamp (used as sort key) | | `Updates` | object | Yes | Fields to update within the Details attribute | **Responses** | Code | Description | | ----- | ------------------------------------------------ | | `200` | Record updated successfully | | `400` | inventoryId, timestamp, and Updates are required | | `500` | Internal server error | --- ### Delete an inventory record `DELETE /boatRecords` Deletes a record by inventoryId and timestamp **Request body** | Field | Type | Required | Description | | ------------- | ------ | -------- | ----------------------------------- | | `inventoryId` | string | Yes | The inventory ID | | `timestamp` | string | Yes | Record timestamp (used as sort key) | **Responses** | Code | Description | | ----- | -------------------------------------- | | `200` | Record deleted successfully | | `400` | inventoryId and timestamp are required | | `500` | Internal server error | --- ### Get paginated rundown records `GET /boatRecords/rundownRecords` Retrieves records for an inventory item with pagination support **Parameters** | Name | In | Type | Required | Description | | ------------- | ----- | ------- | -------- | ------------------------------------------ | | `inventoryId` | query | string | Yes | The inventory ID to get records for | | `limit` | query | integer | No | Number of items to return | | `nextToken` | query | string | No | URL-encoded pagination token for next page | **Responses** | Code | Description | | ----- | --------------------------------------------------- | | `200` | Records retrieved successfully with pagination info | | `400` | inventoryId is required | | `500` | Internal server error | --- --- # Locations API Source: https://docs.rentaltide.com/api-reference/locations/ > Manage business locations and their settings Endpoints for managing business locations, operating hours, and location-specific settings. ## Locations ### Get locations `GET /location` If inventoryId is provided, returns the location for that boat. Otherwise, returns all locations for the authenticated user's customer. **Parameters** | Name | In | Type | Required | Description | | ------------- | ----- | ------ | -------- | -------------------------------------------- | | `inventoryId` | query | string | No | Inventory ID to find the associated location | **Responses** | Code | Description | | ----- | ---------------------------------- | | `200` | Location(s) retrieved successfully | | `401` | Unauthorized | | `404` | User, boat, or location not found | | `500` | Internal server error | --- ### Create a new location `POST /location` Creates a new location and sends a Slack notification. Automatically geocodes the address. **Request body** | Field | Type | Required | Description | | ------------- | ------ | -------- | --------------------------- | | `address` | string | Yes | | | `phoneNumber` | string | Yes | | | `name` | string | Yes | | | `connectId` | string | No | Stripe Connect account ID | | `details` | object | No | Additional location details | **Responses** | Code | Description | | ----- | --------------------------------------- | | `200` | Location created successfully | | `400` | Missing required fields | | `401` | Unauthorized | | `404` | User not found or customer ID not found | | `500` | Internal server error | --- ### Update a location `PATCH /location` Updates an existing location. If address is updated, automatically geocodes for new coordinates. **Request body** | Field | Type | Required | Description | | ------------- | ------ | -------- | ---------------------------- | | `locationId` | string | Yes | ID of the location to update | | `address` | string | No | | | `name` | string | No | | | `phoneNumber` | string | No | | | `details` | object | No | | **Responses** | Code | Description | | ----- | ------------------------------------------------------- | | `200` | Location updated successfully | | `400` | locationId is required or no valid attributes to update | | `500` | Internal server error | --- ### Schedule a location for deletion `DELETE /location` Soft-deletes a location by scheduling it for permanent deletion after 60 days. The location can be restored before the grace period expires. **Request body** | Field | Type | Required | Description | | ------------ | ------ | -------- | ------------------------------------------------- | | `locationId` | string | Yes | ID of the location to delete | | `customerId` | string | No | Customer ID (optional, for notification purposes) | **Responses** | Code | Description | | ----- | ------------------------------- | | `200` | Location scheduled for deletion | | `400` | locationId is required | | `500` | Internal server error | --- ### Update location IVR configuration `PATCH /location/ivr` Updates the IVR (Interactive Voice Response) configuration for a location **Request body** | Field | Type | Required | Description | | ------------ | ------ | -------- | ---------------------------- | | `locationId` | string | Yes | ID of the location to update | | `ivrConfig` | object | Yes | IVR configuration object | **Responses** | Code | Description | | ----- | -------------------------------------- | | `200` | IVR configuration updated successfully | | `400` | locationId and ivrConfig are required | | `500` | Internal server error | --- ### Restore a location scheduled for deletion `PATCH /location/restore` Cancels a pending scheduled deletion, restoring the location to active status. **Request body** | Field | Type | Required | Description | | ------------ | ------ | -------- | ----------------------------- | | `locationId` | string | Yes | ID of the location to restore | **Responses** | Code | Description | | ----- | ---------------------------------------------------------------- | | `200` | Location restored successfully | | `400` | locationId is required or location is not scheduled for deletion | | `404` | Location not found | | `500` | Internal server error | --- --- # Marina API Source: https://docs.rentaltide.com/api-reference/marina/ > Haul services, meter readings, and marina maps Endpoints for managing marina-specific operations including haul-out services, utility meter readings, and interactive marina maps. ## Haul Services ### Get haul services for a location `GET /haul-services` **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | ----------- | | `locationId` | query | string | Yes | | | `status` | query | string | No | | | `startDate` | query | string | No | | | `endDate` | query | string | No | | --- ### Request a new haul service `POST /haul-services` --- ### Get haul service statistics `GET /haul-services/stats` --- ### Get services scheduled for a specific date `GET /haul-services/scheduled/{date}` --- ### Get services for a specific renter `GET /haul-services/renter/{renterId}` --- ### Get services for a specific reservation `GET /haul-services/reservation/{reservationId}` --- ### Get a single haul service by ID `GET /haul-services/{id}` --- ### Update a haul service `PUT /haul-services/{id}` --- ### Delete a haul service (only if not started) `DELETE /haul-services/{id}` --- ### Schedule a haul service with pricing `POST /haul-services/{id}/schedule` --- ### Confirm a scheduled haul service `POST /haul-services/{id}/confirm` --- ### Start a haul service `POST /haul-services/{id}/start` --- ### Complete a haul service `POST /haul-services/{id}/complete` --- ### Cancel a haul service `POST /haul-services/{id}/cancel` --- ### Add photos to a haul service `POST /haul-services/{id}/photos` --- ## Meter Readings ### Get meter readings with filters `GET /meter-readings` --- ### Record a new meter reading `POST /meter-readings` --- ### Get meter reading statistics `GET /meter-readings/stats` --- ### Get unbilled readings for a location `GET /meter-readings/unbilled` --- ### Get latest reading for a unit `GET /meter-readings/unit/{unitId}/latest` --- ### Get reading history for a unit `GET /meter-readings/unit/{unitId}/history` --- ### Get a single meter reading `GET /meter-readings/{id}` --- ### Update a meter reading `PUT /meter-readings/{id}` --- ### Delete a meter reading `DELETE /meter-readings/{id}` --- ### Mark multiple readings as billed `POST /meter-readings/mark-billed` --- ### Add utility charges to a reservation `POST /meter-readings/add-to-reservation` --- ## Marina Maps ### Get all maps for a location `GET /slips/maps/{locationId}` --- ### Create a new marina map `POST /slips/maps` --- ### Update display order for multiple maps `PUT /slips/maps/reorder` --- ### Batch update pin positions `PUT /slips/maps/batch-pins` --- ### Get a single map by ID `GET /slips/maps/{mapId}` --- ### Update a marina map `PUT /slips/maps/{mapId}` --- ### Delete a marina map (unlinks all slips) `DELETE /slips/maps/{mapId}` --- ### Toggle map active status `PATCH /slips/maps/{mapId}/toggle-active` --- ### Get all pins (slips) for a specific map `GET /slips/maps/{mapId}/pins` --- ### Get slips not assigned to any map for a location `GET /slips/maps/{locationId}/unassigned` --- ### Assign or update a slip's map position `PUT /slips/{slipId}/map-pin` --- ### Update only the position of a slip pin `PATCH /slips/{slipId}/map-pin` --- ### Remove a slip from the map `DELETE /slips/{slipId}/map-pin` --- --- # Marketing API Source: https://docs.rentaltide.com/api-reference/marketing/ > Affiliates, cart recovery, and communications Endpoints for managing affiliate programs, cart recovery campaigns, and customer communications. ## Affiliates ### Check affiliate ID availability `GET /affiliate/check-availability` Check if a given affiliate ID is available for use **Parameters** | Name | In | Type | Required | Description | | ------------- | ----- | ------ | -------- | ------------------------- | | `affiliateId` | query | string | Yes | The affiliate ID to check | **Responses** | Code | Description | | ----- | ------------------------------- | | `200` | Availability check result | | `400` | Missing or invalid affiliate ID | | `500` | Server error | --- ### Create an affiliate `POST /affiliate` Create a new affiliate with optional custom affiliate ID **Request body** | Field | Type | Required | Description | | ------------------- | ------ | -------- | ----------- | | `customerId` | string | Yes | | | `name` | string | Yes | | | `email` | string | Yes | | | `percentageEarned` | number | No | | | `customAffiliateId` | string | No | | **Responses** | Code | Description | | ----- | ----------------------------------------------- | | `201` | Affiliate created successfully | | `400` | Missing required fields or invalid affiliate ID | | `409` | Affiliate ID already exists | | `500` | Server error | --- ### Get affiliates for a customer `GET /affiliate` Retrieve all affiliates associated with a customer ID **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | ------------------------------------- | | `customerId` | query | string | Yes | The customer ID to get affiliates for | **Responses** | Code | Description | | ----- | ---------------------------- | | `200` | List of affiliates | | `400` | Missing customerId parameter | | `500` | Server error | --- ### Delete an affiliate `DELETE /affiliate` Delete an affiliate by their affiliate ID **Parameters** | Name | In | Type | Required | Description | | ------------- | ----- | ------ | -------- | -------------------------- | | `affiliateId` | query | string | Yes | The affiliate ID to delete | **Responses** | Code | Description | | ----- | ------------------------------ | | `200` | Affiliate deleted successfully | | `400` | Missing affiliateId parameter | | `404` | Affiliate not found | | `500` | Server error | --- ### Update affiliate data `PATCH /affiliate` Perform various affiliate update operations based on action parameter **Parameters** | Name | In | Type | Required | Description | | -------- | ----- | ------ | -------- | --------------------- | | `action` | query | string | Yes | The action to perform | **Request body** | Field | Type | Required | Description | | ------------------ | ------ | -------- | -------------------------------------- | | `affiliateId` | string | No | | | `paidOut` | number | No | Amount for addPayout action | | `percentageEarned` | number | No | Percentage for editPercentage action | | `totalAmount` | number | No | Total amount for addACommission action | **Responses** | Code | Description | | ----- | ----------------------------------------- | | `200` | Operation completed successfully | | `400` | Missing required fields or invalid action | | `404` | Affiliate not found | | `500` | Server error | --- ### Recalculate affiliate earnings `POST /affiliate/recalculate` Recalculates all affiliate earnings from bookings (excludes cancelled bookings) **Request body** | Field | Type | Required | Description | | ------------- | ------ | -------- | -------------------------------------------------- | | `customerId` | string | Yes | Customer ID to recalculate affiliates for | | `affiliateId` | string | No | Optional - recalculate for specific affiliate only | **Responses** | Code | Description | | ----- | ------------------------------------ | | `200` | Recalculation completed successfully | | `400` | Missing required fields | | `500` | Server error | --- ## Cart Recovery ### Get cart recovery items for a location `GET /cartRecovery/{locationId}` Retrieves all abandoned cart items for the authenticated customer at a specific location **Parameters** | Name | In | Type | Required | Description | | ------------ | ---- | ------ | -------- | --------------------------------------------- | | `locationId` | path | string | Yes | The location ID to filter cart recovery items | **Responses** | Code | Description | | ----- | --------------------------- | | `200` | List of cart recovery items | | `400` | Missing required parameters | | `500` | Internal server error | --- ### Delete a cart recovery item `DELETE /cartRecovery/{id}` Deletes an abandoned cart item. Only the owner of the cart can delete it. **Parameters** | Name | In | Type | Required | Description | | ---- | ---- | ------ | -------- | ------------------------- | | `id` | path | string | Yes | The cart recovery item ID | **Responses** | Code | Description | | ----- | ----------------------------------------- | | `200` | Item deleted successfully | | `400` | Missing required parameters | | `403` | Access denied - not the owner of the cart | | `404` | Item not found | --- ## Communications ### Send a templated communication `POST /communication/send-templated` Sends a templated email or SMS communication to recipients. If rentalId is provided, the recipient is determined from the rental's CustomerInfo. If both rentalId and recipientList are provided, all parties receive the communication. **Request body** | Field | Type | Required | Description | | ---------------- | ------- | -------- | ------------------------------------------------------------------------------------- | | `customerId` | string | Yes | The customer ID | | `locationId` | string | Yes | The location ID | | `templateId` | string | Yes | The template identifier (e.g., booking_confirmation) | | `rentalId` | string | No | The rental ID (optional, but either rentalId or recipientList is required) | | `recipientList` | array | No | List of email recipients (optional, but either rentalId or recipientList is required) | | `forceSendEmail` | boolean | No | Force sending via email | | `forceSendText` | boolean | No | Force sending via SMS | **Responses** | Code | Description | | ----- | ------------------------------------------- | | `200` | Communication sent successfully | | `400` | Missing required fields or validation error | | `500` | Server error | --- ### Send cart recovery email `POST /communication/send-cart-recovery-email` Sends a cart recovery email to a customer with optional custom message and booking information. Generates a short URL for tracking. **Request body** | Field | Type | Required | Description | | --------------- | ------ | -------- | ---------------------------------------------- | | `to` | string | Yes | Recipient email address | | `firstName` | string | No | Customer's first name | | `lastName` | string | No | Customer's last name | | `customMessage` | string | No | Optional custom message content | | `recoveryUrl` | string | Yes | The URL for the customer to recover their cart | | `bookingInfo` | object | No | | **Responses** | Code | Description | | ----- | ----------------------------------------------- | | `200` | Cart recovery email sent successfully | | `400` | Missing required fields or invalid email format | | `500` | Failed to send cart recovery email | --- ### Generate a short code for a URL `POST /communication/generate-short-code` Creates a shortened URL with optional metadata for tracking purposes. Returns the short URL and code with a 30-day expiration. **Request body** | Field | Type | Required | Description | | ------------- | ------ | -------- | -------------------------------------------------- | | `originalUrl` | string | Yes | The original URL to shorten | | `metadata` | object | No | Optional metadata to associate with the short code | **Responses** | Code | Description | | ----- | --------------------------------- | | `200` | Short code generated successfully | | `400` | Missing or invalid URL | | `500` | Failed to generate short code | --- ### Send an SMS message `POST /communication/send-sms` Sends an SMS message with enhanced error handling and international support. Validates phone number format and SMS service availability. **Request body** | Field | Type | Required | Description | | ------------- | ------ | -------- | ------------------------------------- | | `phoneNumber` | string | Yes | The recipient phone number | | `message` | string | Yes | The SMS message content | | `customerId` | string | No | The customer ID for tracking | | `locationId` | string | No | The location ID for tracking | | `country` | string | No | The country code for phone validation | **Responses** | Code | Description | | ----- | ------------------------------------------------- | | `200` | SMS sent successfully | | `400` | Invalid phone number or SMS service not available | | `500` | Failed to send SMS | --- ### Send waiver link via SMS `POST /communication/send-waiver-link` Sends a waiver link to a customer via SMS. Creates a short link for tracking and sends the SMS with a personalized message. **Request body** | Field | Type | Required | Description | | --------------- | ------ | -------- | --------------------------------------------------------------------------- | | `phoneNumber` | string | Yes | The recipient phone number | | `message` | string | No | Optional custom message (default message will be generated if not provided) | | `waiverUrl` | string | Yes | The waiver URL (can be relative or absolute) | | `customerId` | string | No | The customer ID | | `transactionId` | string | No | The transaction ID | | `firstName` | string | No | Customer's first name for personalization | | `lastName` | string | No | Customer's last name | | `locationId` | string | No | The location ID | | `country` | string | No | The country code for phone validation | **Responses** | Code | Description | | ----- | ----------------------------------------------- | | `200` | Waiver link sent successfully | | `400` | Invalid phone number or missing required fields | | `500` | Failed to send waiver link | --- ### Mark cart recovery item as contacted `POST /communication/cartRecovery/{id}/contact` Updates a cart recovery item to mark it as contacted with the current timestamp. **Parameters** | Name | In | Type | Required | Description | | ---- | ---- | ------ | -------- | ------------------------- | | `id` | path | string | Yes | The cart recovery item ID | **Responses** | Code | Description | | ----- | -------------------------------------- | | `200` | Cart recovery item marked as contacted | | `400` | Missing cart recovery ID | | `404` | Cart recovery item not found | | `500` | Failed to mark as contacted | --- ### Get cart recovery items needing contact `GET /communication/cartRecovery/items-needing-contact` Returns active, uncontacted cart recovery items whose ContactOn time has passed. Used by the cart recovery Lambda. **Responses** | Code | Description | | ----- | -------------------------------------------- | | `200` | Items needing contact retrieved successfully | | `500` | Failed to retrieve items | --- ### Get cart recovery items for a location `GET /communication/cartRecovery/{locationId}` Retrieves cart recovery items for a specific location with optional filtering and statistics. **Parameters** | Name | In | Type | Required | Description | | ------------------ | ----- | ------ | -------- | ------------------------------------------------- | | `locationId` | path | string | Yes | The location ID | | `includeContacted` | query | string | No | Whether to include contacted items in the results | **Responses** | Code | Description | | ----- | ------------------------------------------ | | `200` | Cart recovery items retrieved successfully | | `400` | Missing location ID | | `500` | Failed to retrieve cart recovery items | --- ### Delete cart recovery item `DELETE /communication/cartRecovery/{id}` Permanently deletes a cart recovery item by ID. **Parameters** | Name | In | Type | Required | Description | | ---- | ---- | ------ | -------- | ------------------------- | | `id` | path | string | Yes | The cart recovery item ID | **Responses** | Code | Description | | ----- | --------------------------------------- | | `200` | Cart recovery item deleted successfully | | `400` | Missing cart recovery ID | | `404` | Cart recovery item not found | | `500` | Failed to delete cart recovery item | --- ### Validate a phone number `POST /communication/validate-phone` Validates a phone number for SMS capability with enhanced international support. **Request body** | Field | Type | Required | Description | | ------------- | ------ | -------- | ------------------------------- | | `phoneNumber` | string | Yes | The phone number to validate | | `country` | string | No | The country code for validation | **Responses** | Code | Description | | ----- | ------------------------------- | | `200` | Phone validation result | | `400` | Missing phone number | | `500` | Failed to validate phone number | --- ### Process scheduled communications `POST /communication/process-scheduled` Cron job endpoint that processes pending scheduled communications. Should be called every 5 minutes to fetch pending communications, send them, and update their status. **Responses** | Code | Description | | ----- | ------------------------------------------ | | `200` | Scheduled communications processed | | `500` | Failed to process scheduled communications | --- ### Schedule a communication `POST /communication/schedule` Schedules a communication to be sent at a later time based on delay or trigger conditions. **Request body** | Field | Type | Required | Description | | ---------------- | ------- | -------- | --------------------------------------- | | `customerId` | string | Yes | The customer ID | | `locationId` | string | Yes | The location ID | | `templateId` | string | Yes | The template identifier | | `recipientEmail` | string | Yes | The recipient email address | | `rentalId` | string | No | Optional rental ID | | `delayMinutes` | integer | No | Delay in minutes before sending | | `trigger` | string | No | Trigger condition for the communication | | `conditions` | object | No | Additional conditions for sending | **Responses** | Code | Description | | ----- | ------------------------------------ | | `200` | Communication scheduled successfully | | `400` | Missing required fields | | `500` | Failed to schedule communication | --- ### Cancel a scheduled communication `DELETE /communication/schedule/{scheduleId}` Cancels a previously scheduled communication by its schedule ID. **Parameters** | Name | In | Type | Required | Description | | ------------ | ---- | ------ | -------- | ---------------------------------------------- | | `scheduleId` | path | string | Yes | The schedule ID of the communication to cancel | **Responses** | Code | Description | | ----- | ---------------------------------------------- | | `200` | Scheduled communication cancelled successfully | | `400` | Missing schedule ID | | `500` | Failed to cancel scheduled communication | --- ### Get scheduled communications for a rental `GET /communication/schedule/rental/{rentalId}` Retrieves all scheduled communications associated with a specific rental. **Parameters** | Name | In | Type | Required | Description | | ---------- | ---- | ------ | -------- | ------------- | | `rentalId` | path | string | Yes | The rental ID | **Responses** | Code | Description | | ----- | ----------------------------------------------- | | `200` | Scheduled communications retrieved successfully | | `400` | Missing rental ID | | `500` | Failed to retrieve scheduled communications | --- ### Get default email template content `GET /communication/templates/defaults/{templateId}` Retrieves the default content for a specific email template by ID. **Parameters** | Name | In | Type | Required | Description | | ------------ | ---- | ------ | -------- | ----------------------- | | `templateId` | path | string | Yes | The template identifier | **Responses** | Code | Description | | ----- | --------------------------------------- | | `200` | Default template retrieved successfully | | `400` | Missing template ID | | `404` | Default template not found | | `500` | Failed to retrieve default template | --- ### Get all available default templates `GET /communication/templates/defaults` Retrieves a list of all available default email templates with their content. **Responses** | Code | Description | | ----- | ---------------------------------------- | | `200` | Default templates retrieved successfully | | `500` | Failed to retrieve default templates | --- --- # Memberships API Source: https://docs.rentaltide.com/api-reference/memberships/ > Manage membership programs, tiers, billing, and member access Endpoints for managing membership programs including tiers, billing, credits, family plans, organizations, public enrollment, and the member portal. ## Memberships ### Get all memberships `GET /memberships` Retrieves all memberships for a customer with pagination and optional status filtering **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------- | -------- | --------------------------- | | `customerId` | query | string | Yes | The customer ID | | `status` | query | string | No | Filter by membership status | | `tierId` | query | string | No | Filter by tier ID | | `page` | query | integer | No | Page number | | `limit` | query | integer | No | Items per page | **Responses** | Code | Description | | ----- | ---------------------------------- | | `200` | Successfully retrieved memberships | | `400` | customerId is required | | `500` | Server error | --- ### Create a new membership `POST /memberships` Creates a new membership (staff-created). Can optionally create a new renter. **Request body** | Field | Type | Required | Description | | -------------- | ------- | -------- | --------------------------- | | `customerId` | string | Yes | | | `tierId` | string | Yes | | | `memberType` | string | No | | | `memberId` | string | No | | | `renterId` | string | No | Alias for memberId | | `memberEmail` | string | Yes | | | `memberName` | string | No | | | `memberPhone` | string | No | | | `billingCycle` | string | No | | | `staffId` | string | No | | | `notes` | string | No | | | `createRenter` | boolean | No | Create a new renter if true | | `firstName` | string | No | | | `lastName` | string | No | | **Responses** | Code | Description | | ----- | --------------------------------------------------------------- | | `201` | Membership created successfully | | `400` | Missing required fields or member already has active membership | | `404` | Tier not found | | `500` | Server error | --- ### Get a specific membership `GET /memberships/{membershipId}` Retrieves a specific membership with full details including tier and renter info **Parameters** | Name | In | Type | Required | Description | | -------------- | ----- | ------ | -------- | ----------------- | | `membershipId` | path | string | Yes | The membership ID | | `customerId` | query | string | Yes | The customer ID | **Responses** | Code | Description | | ----- | --------------------------------- | | `200` | Successfully retrieved membership | | `400` | customerId is required | | `404` | Membership not found | | `500` | Server error | --- ### Cancel a membership `POST /memberships/{membershipId}/cancel` Cancels a membership. Can cancel immediately or at period end. **Parameters** | Name | In | Type | Required | Description | | -------------- | ---- | ------ | -------- | ----------------- | | `membershipId` | path | string | Yes | The membership ID | **Request body** | Field | Type | Required | Description | | ------------------- | ------- | -------- | -------------------------------------------------------------- | | `customerId` | string | Yes | | | `cancelImmediately` | boolean | No | If true, cancels immediately. Otherwise cancels at period end. | **Responses** | Code | Description | | ----- | ------------------------------------------------- | | `200` | Membership canceled or scheduled for cancellation | | `400` | customerId is required | | `404` | Membership not found | | `500` | Server error | --- ### Reactivate a canceled membership `POST /memberships/{membershipId}/reactivate` Reactivates a membership that was canceled **Parameters** | Name | In | Type | Required | Description | | -------------- | ---- | ------ | -------- | ----------------- | | `membershipId` | path | string | Yes | The membership ID | **Request body** | Field | Type | Required | Description | | ------------ | ------ | -------- | ----------- | | `customerId` | string | Yes | | **Responses** | Code | Description | | ----- | ---------------------- | | `200` | Membership reactivated | | `400` | customerId is required | | `500` | Server error | --- ### Pause a membership `POST /memberships/{membershipId}/pause` Pauses a membership. Staff can use force=true to bypass tier policy restrictions. **Parameters** | Name | In | Type | Required | Description | | -------------- | ---- | ------ | -------- | ----------------- | | `membershipId` | path | string | Yes | The membership ID | **Request body** | Field | Type | Required | Description | | ------------ | ------- | -------- | ------------------------------------- | | `customerId` | string | Yes | | | `resumeAt` | string | No | Optional date to auto-resume | | `force` | boolean | No | Bypass tier pause policy restrictions | **Responses** | Code | Description | | ----- | ----------------------------------------------------------------- | | `200` | Membership paused | | `400` | customerId is required or pause not enabled or max pauses reached | | `404` | Membership not found | | `500` | Server error | --- ### Resume a paused membership `POST /memberships/{membershipId}/resume` Resumes a membership that was paused **Parameters** | Name | In | Type | Required | Description | | -------------- | ---- | ------ | -------- | ----------------- | | `membershipId` | path | string | Yes | The membership ID | **Request body** | Field | Type | Required | Description | | ------------ | ------ | -------- | ----------- | | `customerId` | string | Yes | | **Responses** | Code | Description | | ----- | -------------------------------------------------- | | `200` | Membership resumed | | `400` | customerId is required or membership is not paused | | `404` | Membership not found | | `500` | Server error | --- ### Get Stripe invoices and billing history for a membership `GET /memberships/{membershipId}/invoices` **Parameters** | Name | In | Type | Required | Description | | -------------- | ----- | ------- | -------- | ----------- | | `membershipId` | path | string | Yes | | | `customerId` | query | string | Yes | | | `limit` | query | integer | No | | **Responses** | Code | Description | | ----- | --------------------------------------------------- | | `200` | Successfully retrieved invoices and billing history | | `400` | customerId is required | | `404` | Membership not found | --- ## Memberships - Billing ### Add a free month to membership `POST /memberships/{membershipId}/billing/add-free-month` Extends the current period end date by one billing cycle without charging **Parameters** | Name | In | Type | Required | Description | | -------------- | ---- | ------ | -------- | ----------------- | | `membershipId` | path | string | Yes | The membership ID | **Request body** | Field | Type | Required | Description | | ------------ | ------ | -------- | ------------------------------------------------- | | `customerId` | string | Yes | | | `reason` | string | No | Reason for adding free month (for audit purposes) | **Responses** | Code | Description | | ----- | ----------------------------- | | `200` | Free month added successfully | | `400` | customerId is required | | `404` | Membership not found | | `500` | Server error | --- ### Change billing date `POST /memberships/{membershipId}/billing/change-date` Changes the billing date by updating the current period end **Parameters** | Name | In | Type | Required | Description | | -------------- | ---- | ------ | -------- | ----------------- | | `membershipId` | path | string | Yes | The membership ID | **Request body** | Field | Type | Required | Description | | ---------------- | ------- | -------- | ---------------------------------------- | | `customerId` | string | Yes | | | `newBillingDate` | string | Yes | New billing date (must be in the future) | | `proRate` | boolean | No | Whether to pro-rate the price difference | | `reason` | string | No | | **Responses** | Code | Description | | ----- | --------------------------------- | | `200` | Billing date changed successfully | | `400` | Invalid request | | `404` | Membership not found | | `500` | Server error | --- ### Switch billing cycle `POST /memberships/{membershipId}/billing/switch-cycle` Switches between monthly and yearly billing cycles with pro-rating **Parameters** | Name | In | Type | Required | Description | | -------------- | ---- | ------ | -------- | ----------------- | | `membershipId` | path | string | Yes | The membership ID | **Request body** | Field | Type | Required | Description | | ----------------- | ------- | -------- | ----------- | | `customerId` | string | Yes | | | `newBillingCycle` | string | Yes | | | `proRate` | boolean | No | | **Responses** | Code | Description | | ----- | ----------------------------------- | | `200` | Billing cycle switched successfully | | `400` | Invalid request | | `404` | Membership not found | | `500` | Server error | --- ### Change membership price `POST /memberships/{membershipId}/billing/change-price` Changes the recurring price for an individual membership **Parameters** | Name | In | Type | Required | Description | | -------------- | ---- | ------ | -------- | ----------------- | | `membershipId` | path | string | Yes | The membership ID | **Request body** | Field | Type | Required | Description | | ------------ | ------- | -------- | ------------------ | | `customerId` | string | Yes | | | `newPrice` | number | Yes | New price in cents | | `proRate` | boolean | No | | | `reason` | string | No | | **Responses** | Code | Description | | ----- | -------------------------- | | `200` | Price changed successfully | | `400` | Invalid request | | `404` | Membership not found | | `500` | Server error | --- ### Refund a membership invoice payment `POST /memberships/{membershipId}/refund` --- ### Resend a membership invoice receipt email `POST /memberships/{membershipId}/invoices/{invoiceId}/resend` --- ## Memberships - Credits ### Get credit balance and history `GET /memberships/{membershipId}/credits` Retrieves the credit balance and transaction history for a membership **Parameters** | Name | In | Type | Required | Description | | -------------- | ----- | ------- | -------- | ----------------------------------- | | `membershipId` | path | string | Yes | The membership ID | | `customerId` | query | string | Yes | The customer ID | | `limit` | query | integer | No | Number of history entries to return | **Responses** | Code | Description | | ----- | ------------------------------ | | `200` | Successfully retrieved credits | | `400` | customerId is required | | `404` | Membership not found | | `500` | Server error | --- ### Adjust membership credits `POST /memberships/{membershipId}/credits/adjust` Manual credit adjustment for a membership (staff only) **Parameters** | Name | In | Type | Required | Description | | -------------- | ---- | ------ | -------- | ----------------- | | `membershipId` | path | string | Yes | The membership ID | **Request body** | Field | Type | Required | Description | | ------------- | ------ | -------- | ----------------------------------- | | `customerId` | string | Yes | | | `amount` | number | Yes | Positive to add, negative to deduct | | `description` | string | Yes | Reason for the adjustment | | `staffId` | string | No | | **Responses** | Code | Description | | ----- | ----------------------------------------------------------- | | `200` | Credit adjustment successful | | `400` | Missing required fields or would result in negative balance | | `404` | Membership not found | | `500` | Server error | --- ## Memberships - Family ### Add a family member `POST /memberships/{membershipId}/family` Adds a family member to a membership **Parameters** | Name | In | Type | Required | Description | | -------------- | ---- | ------ | -------- | ----------------- | | `membershipId` | path | string | Yes | The membership ID | **Request body** | Field | Type | Required | Description | | ------------ | ------ | -------- | ----------- | | `customerId` | string | Yes | | | `renterId` | string | Yes | | | `name` | string | No | | | `email` | string | Yes | | **Responses** | Code | Description | | ----- | ---------------------------------------------------------------------------------------- | | `200` | Family member added | | `400` | Missing required fields or family members not enabled or max reached or already a member | | `404` | Membership not found | | `500` | Server error | --- ### Remove a family member `DELETE /memberships/{membershipId}/family/{renterId}` Removes a family member from a membership **Parameters** | Name | In | Type | Required | Description | | -------------- | ----- | ------ | -------- | ----------------------- | | `membershipId` | path | string | Yes | The membership ID | | `renterId` | path | string | Yes | The renter ID to remove | | `customerId` | query | string | Yes | The customer ID | **Responses** | Code | Description | | ----- | -------------------------------------------------- | | `200` | Family member removed | | `400` | customerId is required | | `404` | Membership not found or renter not a family member | | `500` | Server error | --- ## Memberships - Organizations ### Get all organizations `GET /memberships/organizations` Retrieves all organizations for a customer **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | --------------- | | `customerId` | query | string | Yes | The customer ID | **Responses** | Code | Description | | ----- | ------------------------------------ | | `200` | Successfully retrieved organizations | | `400` | customerId is required | | `500` | Server error | --- ### Create an organization `POST /memberships/organizations` Creates a new organization for membership purposes **Request body** | Field | Type | Required | Description | | ---------------------- | ------- | -------- | ----------- | | `customerId` | string | Yes | | | `name` | string | Yes | | | `contactEmail` | string | Yes | | | `contactName` | string | Yes | | | `contactPhone` | string | No | | | `billingAddress` | object | No | | | `maxAuthorizedRenters` | integer | No | | **Responses** | Code | Description | | ----- | --------------------------------- | | `201` | Organization created successfully | | `400` | Missing required fields | | `500` | Server error | --- ### Get organization by ID `GET /memberships/organizations/{orgId}` Retrieves a specific organization with its membership details **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | ------------------- | | `orgId` | path | string | Yes | The organization ID | | `customerId` | query | string | Yes | The customer ID | **Responses** | Code | Description | | ----- | ----------------------------------- | | `200` | Successfully retrieved organization | | `400` | customerId is required | | `404` | Organization not found | | `500` | Server error | --- ### Update an organization `PATCH /memberships/organizations/{orgId}` Updates an existing organization's details **Parameters** | Name | In | Type | Required | Description | | ------- | ---- | ------ | -------- | ------------------- | | `orgId` | path | string | Yes | The organization ID | **Request body** | Field | Type | Required | Description | | ---------------------- | ------- | -------- | ----------- | | `customerId` | string | Yes | | | `name` | string | No | | | `contactEmail` | string | No | | | `contactName` | string | No | | | `contactPhone` | string | No | | | `billingAddress` | object | No | | | `maxAuthorizedRenters` | integer | No | | **Responses** | Code | Description | | ----- | --------------------------------- | | `200` | Organization updated successfully | | `400` | customerId is required | | `500` | Server error | --- ### Delete an organization `DELETE /memberships/organizations/{orgId}` Deletes an organization. Cannot delete if organization has an active membership. **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | ------------------- | | `orgId` | path | string | Yes | The organization ID | | `customerId` | query | string | Yes | The customer ID | **Responses** | Code | Description | | ----- | ------------------------------------------------------------ | | `200` | Organization deleted successfully | | `400` | customerId is required or organization has active membership | | `500` | Server error | --- ### Add authorized renter to organization `POST /memberships/organizations/{orgId}/members` Adds a renter to the organization's authorized renters list **Parameters** | Name | In | Type | Required | Description | | ------- | ---- | ------ | -------- | ------------------- | | `orgId` | path | string | Yes | The organization ID | **Request body** | Field | Type | Required | Description | | ------------ | ------ | -------- | ----------- | | `customerId` | string | Yes | | | `renterId` | string | Yes | | **Responses** | Code | Description | | ----- | ------------------------------------------------------------------------- | | `200` | Renter added to organization | | `400` | Missing required fields or renter already authorized or max limit reached | | `404` | Organization not found | | `500` | Server error | --- ### Get authorized renters for organization `GET /memberships/organizations/{orgId}/members` Retrieves all authorized renters for an organization with their details **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | ------------------- | | `orgId` | path | string | Yes | The organization ID | | `customerId` | query | string | Yes | The customer ID | **Responses** | Code | Description | | ----- | ------------------------------ | | `200` | Successfully retrieved members | | `400` | customerId is required | | `404` | Organization not found | | `500` | Server error | --- ### Remove authorized renter from organization `DELETE /memberships/organizations/{orgId}/members/{renterId}` Removes a renter from the organization's authorized renters list **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | ------------------- | | `orgId` | path | string | Yes | The organization ID | | `renterId` | path | string | Yes | The renter ID | | `customerId` | query | string | Yes | The customer ID | **Responses** | Code | Description | | ----- | -------------------------------- | | `200` | Renter removed from organization | | `400` | customerId is required | | `404` | Organization or renter not found | | `500` | Server error | --- ### Create membership for organization `POST /memberships/organizations/{orgId}/membership` Creates a membership for an organization **Parameters** | Name | In | Type | Required | Description | | ------- | ---- | ------ | -------- | ------------------- | | `orgId` | path | string | Yes | The organization ID | **Request body** | Field | Type | Required | Description | | -------------- | ------ | -------- | ----------- | | `customerId` | string | Yes | | | `tierId` | string | Yes | | | `billingCycle` | string | Yes | | **Responses** | Code | Description | | ----- | ------------------------------------------------------------------------------------------- | | `201` | Membership created successfully | | `400` | Missing required fields or tier doesn't support organizations or org already has membership | | `404` | Organization or tier not found | | `500` | Server error | --- ## Memberships - Tiers ### Get all membership tiers `GET /memberships/tiers` Retrieves all membership tiers for a customer, optionally filtered by active status **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------- | -------- | ------------------------ | | `customerId` | query | string | Yes | The customer ID | | `activeOnly` | query | boolean | No | Only return active tiers | **Responses** | Code | Description | | ----- | ---------------------------- | | `200` | Successfully retrieved tiers | | `400` | customerId is required | | `500` | Server error | --- ### Create a new membership tier `POST /memberships/tiers` Creates a new membership tier with pricing and benefits **Request body** | Field | Type | Required | Description | | -------------------- | ------- | -------- | ----------- | | `customerId` | string | Yes | | | `name` | string | Yes | | | `description` | string | No | | | `scope` | string | No | | | `locationIds` | array | No | | | `pricing` | object | No | | | `benefits` | object | No | | | `pausePolicy` | object | No | | | `familyOptions` | object | No | | | `allowedMemberTypes` | array | No | | | `displayOrder` | integer | No | | **Responses** | Code | Description | | ----- | -------------------------------- | | `201` | Tier created successfully | | `400` | customerId and name are required | | `500` | Server error | --- ### Get a specific membership tier `GET /memberships/tiers/{tierId}` Retrieves a specific membership tier by ID **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | --------------- | | `tierId` | path | string | Yes | The tier ID | | `customerId` | query | string | Yes | The customer ID | **Responses** | Code | Description | | ----- | --------------------------- | | `200` | Successfully retrieved tier | | `400` | customerId is required | | `404` | Tier not found | | `500` | Server error | --- ### Update a membership tier `PATCH /memberships/tiers/{tierId}` Updates an existing membership tier **Parameters** | Name | In | Type | Required | Description | | -------- | ---- | ------ | -------- | ----------- | | `tierId` | path | string | Yes | The tier ID | **Request body** | Field | Type | Required | Description | | --------------- | ------- | -------- | ----------- | | `customerId` | string | Yes | | | `name` | string | No | | | `description` | string | No | | | `isActive` | boolean | No | | | `displayOrder` | integer | No | | | `pricing` | object | No | | | `benefits` | object | No | | | `pausePolicy` | object | No | | | `familyOptions` | object | No | | **Responses** | Code | Description | | ----- | --------------------------------------------------- | | `200` | Tier updated successfully | | `400` | customerId is required or no valid fields to update | | `500` | Server error | --- ### Deactivate a membership tier `DELETE /memberships/tiers/{tierId}` Soft-deletes (deactivates) a membership tier. Cannot delete if tier has active memberships. **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | --------------- | | `tierId` | path | string | Yes | The tier ID | | `customerId` | query | string | Yes | The customer ID | **Responses** | Code | Description | | ----- | ----------------------------------------------------- | | `200` | Tier deactivated successfully | | `400` | customerId is required or tier has active memberships | | `500` | Server error | --- ## Memberships - Public ### Get public membership tiers for a location `GET /memberships/public/tiers/{locationId}` Retrieves active membership tiers for a location (no authentication required) **Parameters** | Name | In | Type | Required | Description | | ------------ | ---- | ------ | -------- | --------------- | | `locationId` | path | string | Yes | The location ID | **Responses** | Code | Description | | ----- | ---------------------------- | | `200` | Successfully retrieved tiers | | `404` | Location not found | | `500` | Server error | --- ### Create checkout session for membership signup `POST /memberships/public/checkout` Creates a Stripe checkout session for membership signup. If renter has existing payment method, creates subscription directly. **Request body** | Field | Type | Required | Description | | -------------- | ------ | -------- | --------------------------- | | `customerId` | string | Yes | | | `tierId` | string | Yes | | | `billingCycle` | string | Yes | | | `renterEmail` | string | Yes | | | `renterName` | string | No | | | `renterPhone` | string | No | | | `renterId` | string | No | Optional existing renter ID | | `successUrl` | string | No | | | `cancelUrl` | string | No | | **Responses** | Code | Description | | ----- | ------------------------------------------------ | | `200` | Checkout session or subscription created | | `400` | Missing required fields or Stripe not configured | | `404` | Tier or location not found | | `500` | Server error | --- ### Check membership signup status `GET /memberships/public/status/{sessionId}` Check the status of a membership signup by checkout session ID **Parameters** | Name | In | Type | Required | Description | | ----------- | ---- | ------ | -------- | ------------------------------ | | `sessionId` | path | string | Yes | The Stripe checkout session ID | **Responses** | Code | Description | | ----- | --------------------------- | | `200` | Membership status retrieved | | `404` | Membership not found | | `500` | Server error | --- ## Member Portal ### Get membership details `GET /portal/membership` Returns the current member's membership details, credits balance, tier information, and business info. Requires OTP session authentication. **Parameters** | Name | In | Type | Required | Description | | --------------- | ------ | ------ | -------- | ----------------- | | `x-otp-session` | header | string | Yes | OTP session token | **Responses** | Code | Description | | ----- | --------------------------------------------- | | `200` | Membership details retrieved successfully | | `401` | Unauthorized - invalid or missing OTP session | | `404` | Membership not found | | `500` | Internal server error | --- ### Get credit transaction history `GET /portal/membership/credits` Returns the member's credit transaction history, sorted by most recent first **Parameters** | Name | In | Type | Required | Description | | --------------- | ------ | ------- | -------- | ---------------------------------------- | | `x-otp-session` | header | string | Yes | OTP session token | | `limit` | query | integer | No | Maximum number of transactions to return | **Responses** | Code | Description | | ----- | --------------------------------------------- | | `200` | Credit transactions retrieved successfully | | `401` | Unauthorized - invalid or missing OTP session | | `500` | Internal server error | --- ### Pause membership `POST /portal/membership/pause` Pauses the member's subscription if the tier's pause policy allows it. Pauses the Stripe subscription collection. **Parameters** | Name | In | Type | Required | Description | | --------------- | ------ | ------ | -------- | ----------------- | | `x-otp-session` | header | string | Yes | OTP session token | **Responses** | Code | Description | | ----- | --------------------------------------------- | | `200` | Membership paused successfully | | `400` | Pausing not allowed or membership not active | | `401` | Unauthorized - invalid or missing OTP session | | `404` | Membership not found | | `500` | Internal server error | --- ### Resume paused membership `POST /portal/membership/resume` Resumes a paused membership and reactivates Stripe subscription collection **Parameters** | Name | In | Type | Required | Description | | --------------- | ------ | ------ | -------- | ----------------- | | `x-otp-session` | header | string | Yes | OTP session token | **Responses** | Code | Description | | ----- | --------------------------------------------- | | `200` | Membership resumed successfully | | `400` | Membership is not paused | | `401` | Unauthorized - invalid or missing OTP session | | `404` | Membership not found | | `500` | Internal server error | --- ### Cancel membership `POST /portal/membership/cancel` Schedules the membership for cancellation at the end of the current billing period. Respects minimum commitment periods. **Parameters** | Name | In | Type | Required | Description | | --------------- | ------ | ------ | -------- | ----------------- | | `x-otp-session` | header | string | Yes | OTP session token | **Request body** | Field | Type | Required | Description | | -------- | ------ | -------- | ---------------------------- | | `reason` | string | No | Optional cancellation reason | **Responses** | Code | Description | | ----- | ------------------------------------------------------------------------- | | `200` | Membership scheduled for cancellation | | `400` | Cancellation not allowed, already canceled, or minimum commitment not met | | `401` | Unauthorized - invalid or missing OTP session | | `404` | Membership not found | | `500` | Internal server error | --- ### Get payment management link `GET /portal/membership/payment` Returns a Stripe Customer Portal URL where the member can update their payment method **Parameters** | Name | In | Type | Required | Description | | --------------- | ------ | ------ | -------- | ----------------- | | `x-otp-session` | header | string | Yes | OTP session token | **Responses** | Code | Description | | ----- | -------------------------------------------------------------- | | `200` | Portal URL generated successfully | | `400` | No payment information found or payment management unavailable | | `401` | Unauthorized - invalid or missing OTP session | | `500` | Internal server error | --- ### Get member's bookings `GET /portal/bookings` Returns the member's booking history with optional filtering by status **Parameters** | Name | In | Type | Required | Description | | --------------- | ------ | ------- | -------- | ------------------------------------ | | `x-otp-session` | header | string | Yes | OTP session token | | `limit` | query | integer | No | Maximum number of bookings to return | | `status` | query | string | No | Filter bookings by status | **Responses** | Code | Description | | ----- | --------------------------------------------- | | `200` | Bookings retrieved successfully | | `401` | Unauthorized - invalid or missing OTP session | | `500` | Internal server error | --- ### Get booking details `GET /portal/bookings/{rentalId}` Returns detailed information about a specific booking **Parameters** | Name | In | Type | Required | Description | | --------------- | ------ | ------ | -------- | --------------------- | | `x-otp-session` | header | string | Yes | OTP session token | | `rentalId` | path | string | Yes | The booking rental ID | **Responses** | Code | Description | | ----- | --------------------------------------------------- | | `200` | Booking details retrieved successfully | | `401` | Unauthorized - invalid or missing OTP session | | `403` | Access denied - booking belongs to different member | | `404` | Booking not found | | `500` | Internal server error | --- ### Get saved payment methods `GET /portal/payment-methods` Returns the member's saved payment methods (credit cards) from Stripe **Parameters** | Name | In | Type | Required | Description | | --------------- | ------ | ------ | -------- | ----------------- | | `x-otp-session` | header | string | Yes | OTP session token | **Responses** | Code | Description | | ----- | --------------------------------------------- | | `200` | Payment methods retrieved successfully | | `401` | Unauthorized - invalid or missing OTP session | | `500` | Internal server error | --- --- # Payments API Source: https://docs.rentaltide.com/api-reference/payments/ > Manage promo codes, gift cards, and protection plans Endpoints for promotional codes, gift card management, and protection plan configuration. ## Promo & Gift Cards ### Get promo/gift cards for a customer `GET /promoGiftCards` Returns all promo codes and gift cards for a customer, or a specific one if promoCode is provided **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | ------------------------------------------------ | | `customerId` | query | string | Yes | The customer ID to retrieve promo/gift cards for | | `promoCode` | query | string | No | Optional specific promo code to retrieve | **Responses** | Code | Description | | ----- | --------------------------------------- | | `200` | Promo/gift cards retrieved successfully | | `400` | customerId is required | | `500` | Internal server error | --- ### Create a new promo/gift card `POST /promoGiftCards` Creates a new promo code or gift card. Requires either $Discount or %Discount in Details. **Request body** | Field | Type | Required | Description | | -------------- | ------ | -------- | ------------------------------ | | `promoCode` | string | Yes | | | `customerId` | string | Yes | | | `ExpiryDate` | string | Yes | | | `Details` | object | Yes | | | `inventoryIds` | array | No | | | `locationId` | string | No | | | `affiliateId` | string | No | Optional affiliate association | **Responses** | Code | Description | | ----- | ------------------------------------------- | | `201` | Promo/gift card created successfully | | `400` | Missing required fields or invalid discount | | `409` | Promo code already exists for this customer | | `500` | Internal server error | --- ### Update a promo/gift card `PATCH /promoGiftCards` Updates an existing promo/gift card. Supports updating affiliateId and discount fields. **Request body** | Field | Type | Required | Description | | ------------ | ------ | -------- | ---------------- | | `promoCode` | string | Yes | | | `customerId` | string | Yes | | | `Updates` | object | Yes | Fields to update | **Responses** | Code | Description | | ----- | -------------------------------------------- | | `200` | Promo/gift card updated successfully | | `400` | Missing required fields or invalid affiliate | | `404` | Promo code not found for this customer | | `500` | Internal server error | --- ### Delete a promo/gift card `DELETE /promoGiftCards` Deletes a promo/gift card by promo code and customer ID **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | ------------------------ | | `promoCode` | query | string | Yes | The promo code to delete | | `customerId` | query | string | Yes | The customer ID | **Responses** | Code | Description | | ----- | -------------------------------------- | | `200` | Promo/gift card deleted successfully | | `400` | promoCode and customerId are required | | `404` | Promo code not found for this customer | | `500` | Internal server error | --- ### Search promo codes across all customers `GET /promoGiftCards/search` Uses GSI to find all instances of a promo code across customers (for admin purposes) **Parameters** | Name | In | Type | Required | Description | | ----------- | ----- | ------ | -------- | ---------------------------- | | `promoCode` | query | string | Yes | The promo code to search for | **Responses** | Code | Description | | ----- | --------------------- | | `200` | Search results | | `400` | promoCode is required | | `500` | Internal server error | --- ### Check gift card balance `GET /promoGiftCards/balance` Check the remaining balance of a gift card or usage info for a promo code **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | -------------------------------------- | | `promoCode` | query | string | Yes | The promo/gift card code to check | | `customerId` | query | string | No | Optional customer ID for faster lookup | **Responses** | Code | Description | | ----- | ------------------------------------------ | | `200` | Balance information retrieved successfully | | `400` | promoCode is required | | `404` | Gift card or promo code not found | | `500` | Internal server error | --- ### Apply a promo code `POST /promoGiftCards/use` Tracks promo code usage and affiliate commissions when a promo code is applied **Request body** | Field | Type | Required | Description | | ------------- | ------ | -------- | ------------------------------------------- | | `promoCode` | string | Yes | | | `customerId` | string | Yes | The customer who owns the promo code | | `orderAmount` | number | Yes | The order amount to apply the discount to | | `userId` | string | No | Optional - the user applying the promo code | **Responses** | Code | Description | | ----- | ------------------------------------------------------------------- | | `200` | Promo code applied successfully | | `400` | Missing required fields, expired promo code, or usage limit reached | | `404` | Promo code not found for this customer | | `500` | Internal server error | --- ### Get promo codes for an affiliate `GET /promoGiftCards/affiliate/{affiliateId}` Retrieves all promo codes associated with a specific affiliate and analytics **Parameters** | Name | In | Type | Required | Description | | ------------- | ----- | ------ | -------- | ---------------- | | `affiliateId` | path | string | Yes | The affiliate ID | | `customerId` | query | string | Yes | The customer ID | **Responses** | Code | Description | | ----- | -------------------------------------------- | | `200` | Affiliate promo codes retrieved successfully | | `400` | customerId is required or invalid affiliate | | `500` | Internal server error | --- ## Public Gift Cards ### Create payment intent for gift card `POST /public/gift-card/create-payment-intent` Creates a Stripe payment intent for purchasing a gift card **Request body** | Field | Type | Required | Description | | ---------------------- | ------ | -------- | -------------------------------------- | | `amount` | number | Yes | Total amount including fees | | `giftCardAmount` | number | No | Gift card value amount | | `customerId` | string | Yes | | | `giftCardCode` | string | Yes | | | `recipientName` | string | No | | | `recipientEmail` | string | No | | | `message` | string | No | | | `expiryDate` | string | No | | | `currency` | string | No | | | `connectAccountId` | string | No | Stripe Connect account ID for transfer | | `applicationFeeAmount` | number | No | Platform fee amount | **Responses** | Code | Description | | ----- | ----------------------------------------- | | `200` | Payment intent created successfully | | `400` | Missing required fields or invalid amount | | `500` | Internal server error | --- ### Confirm gift card payment `POST /public/gift-card/confirm-payment` Confirms payment and creates the gift card after successful Stripe payment **Request body** | Field | Type | Required | Description | | ----------------- | ------ | -------- | --------------------------------------- | | `paymentIntentId` | string | Yes | The Stripe payment intent ID to confirm | **Responses** | Code | Description | | ----- | ---------------------------------------------------- | | `201` | Gift card created successfully | | `400` | Payment intent ID required or payment not successful | | `409` | Gift card code already exists | | `500` | Internal server error | --- ### Stripe webhook handler `POST /public/gift-card/webhook` Stripe webhook endpoint to handle payment events for gift cards (backup verification) **Responses** | Code | Description | | ----- | ------------------------------------------- | | `200` | Webhook received and processed | | `400` | Webhook not configured or invalid signature | --- ### Send gift card email `POST /public/gift-card/send-email` Sends a gift card via email to the recipient with redemption instructions **Request body** | Field | Type | Required | Description | | ---------------- | ------ | -------- | ----------- | | `giftCardCode` | string | Yes | | | `giftCardAmount` | number | Yes | | | `recipientEmail` | string | Yes | | | `recipientName` | string | No | | | `message` | string | No | | | `expiryDate` | string | No | | | `customerId` | string | Yes | | **Responses** | Code | Description | | ----- | ----------------------------------------------- | | `200` | Email sent successfully | | `400` | Missing required fields or invalid email format | | `500` | Email service error or failed to send | --- ### Charge saved card for gift card `POST /public/gift-card/charge-saved-card` Charges a saved payment method for gift card purchase **Request body** | Field | Type | Required | Description | | ---------------------- | ------ | -------- | -------------------------------------- | | `paymentMethodId` | string | Yes | Stripe payment method ID | | `amount` | number | Yes | | | `currency` | string | No | | | `customerId` | string | Yes | | | `stripeCustomerId` | string | No | | | `description` | string | No | | | `metadata` | object | No | | | `connectAccountId` | string | No | Stripe Connect account ID for transfer | | `applicationFeeAmount` | number | No | Platform fee amount | **Responses** | Code | Description | | ----- | ----------------------------------------- | | `200` | Payment processed successfully | | `400` | Missing required fields or invalid amount | | `500` | Internal server error | --- ## Protection Plans ### Get available protection plans `GET /api/v2/protection-plans` Returns protection plans for a specific industry **Parameters** | Name | In | Type | Required | Description | | ----------------- | ----- | ------- | -------- | -------------------------------------- | | `industry` | query | string | No | Industry type (defaults to marine) | | `locationId` | query | string | No | Location ID to filter by enabled plans | | `includeInactive` | query | boolean | No | Include inactive plans (admin only) | **Responses** | Code | Description | | ----- | ------------------------ | | `200` | List of protection plans | | `500` | Server error | --- ### Get available protection bundles `GET /api/v2/protection-bundles` Returns protection bundles for a specific industry **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | ---------------------------------------- | | `industry` | query | string | No | Industry type (defaults to marine) | | `locationId` | query | string | No | Location ID to filter by enabled bundles | **Responses** | Code | Description | | ----- | -------------------------- | | `200` | List of protection bundles | | `500` | Server error | --- ### Get a specific protection plan by code `GET /api/v2/protection-plans/{planCode}` **Parameters** | Name | In | Type | Required | Description | | ---------- | ---- | ------ | -------- | ----------- | | `planCode` | path | string | Yes | | **Responses** | Code | Description | | ----- | ----------------------- | | `200` | Protection plan details | | `404` | Plan not found | | `500` | Server error | --- ### Get a specific protection bundle by code with included plans `GET /api/v2/protection-bundles/{bundleCode}` **Parameters** | Name | In | Type | Required | Description | | ------------ | ---- | ------ | -------- | ----------- | | `bundleCode` | path | string | Yes | | **Responses** | Code | Description | | ----- | --------------------------------------------- | | `200` | Protection bundle details with included plans | | `404` | Bundle not found | | `500` | Server error | --- ### Get protection settings for a location `GET /api/v2/locations/{locationId}/protection-settings` **Parameters** | Name | In | Type | Required | Description | | ------------ | ---- | ------ | -------- | ----------- | | `locationId` | path | string | Yes | | **Responses** | Code | Description | | ----- | ------------------------------------- | | `200` | Location protection settings | | `404` | Settings not found (returns defaults) | | `500` | Server error | --- ### Update protection settings for a location `PUT /api/v2/locations/{locationId}/protection-settings` **Parameters** | Name | In | Type | Required | Description | | ------------ | ---- | ------ | -------- | ----------- | | `locationId` | path | string | Yes | | **Request body** | Field | Type | Required | Description | | -------------------- | ------ | -------- | ----------- | | `industry` | string | No | | | `enabledPlanCodes` | array | No | | | `enabledBundleCodes` | array | No | | | `planOverrides` | object | No | | **Responses** | Code | Description | | ----- | ----------------------------- | | `200` | Settings updated successfully | | `400` | Invalid request | | `500` | Server error | --- ### Enable a plan for a location `POST /api/v2/locations/{locationId}/protection-settings/plan/{planCode}` **Responses** | Code | Description | | ----- | ------------ | | `200` | Plan enabled | --- ### Disable a plan for a location `DELETE /api/v2/locations/{locationId}/protection-settings/plan/{planCode}` **Responses** | Code | Description | | ----- | ------------- | | `200` | Plan disabled | --- ### Enable a bundle for a location `POST /api/v2/locations/{locationId}/protection-settings/bundle/{bundleCode}` --- ### Disable a bundle for a location `DELETE /api/v2/locations/{locationId}/protection-settings/bundle/{bundleCode}` --- ### Set pricing override for a plan at a location `PUT /api/v2/locations/{locationId}/protection-settings/override/{planCode}` **Request body** | Field | Type | Required | Description | | ------------ | ------ | -------- | ----------- | | `percentage` | number | No | | | `maxCap` | number | No | | --- ### Remove pricing override for a plan at a location `DELETE /api/v2/locations/{locationId}/protection-settings/override/{planCode}` --- --- # Point of Sale API Source: https://docs.rentaltide.com/api-reference/pos/ > Process retail and rental transactions at the register Endpoints for managing the point-of-sale system including products, categories, transactions, and register operations. ## Point of Sale ### Get POS inventory items `GET /pos/inventory` Retrieves all POS inventory items for a location **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | -------------------------------- | | `locationId` | query | string | Yes | Location ID to get inventory for | **Responses** | Code | Description | | ----- | ---------------------------- | | `200` | List of inventory items | | `400` | Missing locationId parameter | | `500` | Server error | --- ### Create inventory item `POST /pos/inventory` Creates a new POS inventory item **Request body** | Field | Type | Required | Description | | ------------ | ------ | -------- | ----------- | | `locationId` | string | Yes | | | `name` | string | Yes | | | `category` | string | No | | | `taxRate` | number | No | | | `image` | string | No | | | `variants` | array | No | | | `tags` | array | No | | **Responses** | Code | Description | | ----- | ------------------------- | | `201` | Item created successfully | | `400` | Invalid request body | | `500` | Server error | --- ### Update inventory item `PUT /pos/inventory` Updates an existing POS inventory item **Request body** | Field | Type | Required | Description | | ------------ | ------ | -------- | ----------- | | `locationId` | string | Yes | | | `itemId` | string | Yes | | | `name` | string | No | | | `category` | string | No | | | `taxRate` | number | No | | | `variants` | array | No | | **Responses** | Code | Description | | ----- | ------------------------- | | `200` | Item updated successfully | | `400` | Missing required fields | | `500` | Server error | --- ### Update variant quantity `PATCH /pos/inventory` Updates the quantity of a specific variant in an inventory item **Request body** | Field | Type | Required | Description | | ------------ | ------ | -------- | --------------------------------- | | `locationId` | string | Yes | | | `itemId` | string | Yes | | | `variantId` | string | Yes | | | `quantity` | number | Yes | Quantity change (can be negative) | **Responses** | Code | Description | | ----- | ------------------------- | | `200` | Variant quantity updated | | `400` | Missing required fields | | `404` | Item or variant not found | | `500` | Server error | --- ### Delete inventory item `DELETE /pos/inventory` Deletes a POS inventory item **Request body** | Field | Type | Required | Description | | ------------ | ------ | -------- | ----------- | | `locationId` | string | Yes | | | `itemId` | string | Yes | | **Responses** | Code | Description | | ----- | ------------------------- | | `200` | Item deleted successfully | | `400` | Missing required fields | | `500` | Server error | --- ### Get current gas price `GET /pos/gas-price` Retrieves the current gas price for a location **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | -------------------------------- | | `locationId` | query | string | Yes | Location ID to get gas price for | **Responses** | Code | Description | | ----- | ------------------------------- | | `200` | Gas price returned successfully | | `400` | Missing locationId parameter | | `404` | Gas item not found | | `500` | Server error | --- ### Update till-specific inventory `PATCH /pos/inventory/till` Updates inventory quantity for a specific till/register **Request body** | Field | Type | Required | Description | | ------------ | ------ | -------- | ----------- | | `locationId` | string | Yes | | | `itemId` | string | Yes | | | `tillId` | string | Yes | | | `variantId` | string | Yes | | | `quantity` | number | Yes | | **Responses** | Code | Description | | ----- | ----------------------- | | `200` | Till inventory updated | | `400` | Missing required fields | | `404` | Item not found | | `500` | Server error | --- ### Get folders `GET /pos/folders` Retrieves all product folders for a location **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | ----------- | | `locationId` | query | string | Yes | Location ID | **Responses** | Code | Description | | ----- | ---------------------------- | | `200` | List of folders | | `400` | Missing locationId parameter | | `500` | Server error | --- ### Create folder `POST /pos/folders` Creates a new product folder **Request body** | Field | Type | Required | Description | | ------------ | ------ | -------- | ----------- | | `locationId` | string | Yes | | | `name` | string | Yes | | | `color` | string | No | | | `tillId` | string | No | | **Responses** | Code | Description | | ----- | --------------------------- | | `201` | Folder created successfully | | `400` | Missing required fields | | `500` | Server error | --- ### Update folder `PUT /pos/folders` Updates an existing product folder **Request body** | Field | Type | Required | Description | | ------------ | ------- | -------- | ----------- | | `locationId` | string | Yes | | | `folderId` | string | Yes | | | `name` | string | No | | | `color` | string | No | | | `favorite` | boolean | No | | **Responses** | Code | Description | | ----- | --------------------------- | | `200` | Folder updated successfully | | `400` | Missing required fields | | `500` | Server error | --- ### Delete folder `DELETE /pos/folders` Deletes a product folder and removes folder association from all products in it **Request body** | Field | Type | Required | Description | | ------------ | ------ | -------- | ----------- | | `locationId` | string | Yes | | | `folderId` | string | Yes | | **Responses** | Code | Description | | ----- | --------------------------- | | `200` | Folder deleted successfully | | `400` | Missing required fields | | `500` | Server error | --- ### Reorder folders `PUT /pos/folders/reorder` Updates the sort order of folders **Request body** | Field | Type | Required | Description | | ------------- | ------ | -------- | ----------- | | `locationId` | string | Yes | | | `folderOrder` | array | Yes | | **Responses** | Code | Description | | ----- | ------------------------------ | | `200` | Folders reordered successfully | | `400` | Missing required fields | | `500` | Server error | --- ### Duplicate folders `POST /pos/folders/duplicate` Duplicates folders from a source till to a target till **Request body** | Field | Type | Required | Description | | -------------- | ------ | -------- | ----------- | | `locationId` | string | Yes | | | `sourceTillId` | string | Yes | | | `targetTillId` | string | Yes | | **Responses** | Code | Description | | ----- | -------------------------------- | | `200` | Folders duplicated successfully | | `400` | Missing required fields | | `404` | No folders found for source till | | `500` | Server error | --- ### List transactions `GET /pos/transaction` Retrieves all POS transactions for a location, optionally filtered by till **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | -------------------------------- | | `locationId` | query | string | Yes | Location ID | | `tillId` | query | string | No | Filter by specific till/register | **Responses** | Code | Description | | ----- | ---------------------------- | | `200` | List of transactions | | `400` | Missing locationId parameter | | `500` | Server error | --- ### Create transaction `POST /pos/transaction` Creates a new POS transaction with items, discounts, taxes, and payment information **Request body** | Field | Type | Required | Description | | -------------------- | ------- | -------- | --------------------------------- | | `items` | array | Yes | Array of items in the transaction | | `locationId` | string | Yes | | | `userId` | string | Yes | | | `paymentType` | string | No | | | `accountId` | string | No | | | `discountPercentage` | number | No | | | `discountAmount` | number | No | | | `settleBooking` | boolean | No | | **Responses** | Code | Description | | ----- | -------------------------------- | | `201` | Transaction created successfully | | `400` | Invalid request body | | `500` | Server error | --- ### Get transaction by ID `GET /pos/transaction/{transactionId}` Retrieves a specific POS transaction by its ID **Parameters** | Name | In | Type | Required | Description | | --------------- | ---- | ------ | -------- | -------------- | | `transactionId` | path | string | Yes | Transaction ID | **Responses** | Code | Description | | ----- | ------------------------------- | | `200` | Transaction details | | `400` | Missing transactionId parameter | | `404` | Transaction not found | | `500` | Server error | --- ### Get all POS transactions for a rental `GET /pos/transactions/rental/{rentalId}` Retrieves all POS transactions associated with a specific rental/booking ID **Parameters** | Name | In | Type | Required | Description | | ---------- | ---- | ------ | -------- | --------------------- | | `rentalId` | path | string | Yes | The rental/booking ID | **Responses** | Code | Description | | ----- | ----------------------------------- | | `200` | List of transactions for the rental | | `400` | Missing rental ID | | `500` | Server error | --- ### Refund transaction `POST /pos/transaction/refund` Processes a full or partial refund for a POS transaction **Request body** | Field | Type | Required | Description | | --------------- | ------ | -------- | ---------------------------- | | `transactionId` | string | Yes | | | `refundType` | string | Yes | | | `amount` | number | No | Required for partial refunds | **Responses** | Code | Description | | ----- | ---------------------------------------------- | | `200` | Refund processed successfully | | `400` | Invalid request or transaction already settled | | `404` | Transaction not found | | `500` | Server error | --- ### Settle single transaction `PUT /pos/transaction/settle` Marks a single transaction as settled **Parameters** | Name | In | Type | Required | Description | | --------------- | ----- | ------ | -------- | ------------------------ | | `transactionId` | query | string | Yes | Transaction ID to settle | **Responses** | Code | Description | | ----- | ---------------------------------------- | | `200` | Transaction settled successfully | | `400` | Missing transactionId or already settled | | `404` | Transaction not found | | `500` | Server error | --- ### Settle transactions in date range `PUT /pos/transaction/settle-range` Settles all transactions within a date range, typically used for cash drawer closing **Request body** | Field | Type | Required | Description | | --------------- | ------ | -------- | ----------- | | `locationId` | string | Yes | | | `startDate` | string | No | | | `endDate` | string | No | | | `drawerId` | string | No | | | `countedCash` | number | No | | | `expectedCash` | number | No | | | `difference` | number | No | | | `cashBreakdown` | object | No | | **Responses** | Code | Description | | ----- | --------------------------------- | | `200` | Transactions settled successfully | | `400` | Missing locationId | | `500` | Server error | --- ### Create Stripe payment intent `POST /pos/create_payment` Creates a Stripe payment intent for card-present payments **Request body** | Field | Type | Required | Description | | ---------- | ------- | -------- | --------------- | | `amount` | integer | Yes | Amount in cents | | `currency` | string | No | | **Responses** | Code | Description | | ----- | ---------------------- | | `200` | Payment intent created | | `400` | Error creating payment | --- ### Create Stripe account link `POST /pos/account_link` Creates a Stripe Connect account onboarding link **Request body** | Field | Type | Required | Description | | -------------- | ------ | -------- | ------------------------ | | `account` | string | Yes | Connected account ID | | `stripeRegion` | string | No | Stripe region (US or CA) | **Responses** | Code | Description | | ----- | ------------------------- | | `200` | Account link URL returned | | `500` | Server error | --- ### Charge saved customer `POST /pos/charge_customer` Charges a saved customer using their stored payment method **Request body** | Field | Type | Required | Description | | -------------------- | ------- | -------- | --------------- | | `amount` | integer | Yes | Amount in cents | | `currency` | string | No | | | `stripe_customer_id` | string | Yes | | | `payment_method` | string | Yes | | | `fee_amount` | number | No | | | `connect_id` | string | No | | **Responses** | Code | Description | | ----- | ------------------ | | `200` | Payment successful | | `500` | Server error | --- ### Create Stripe Connect account `POST /pos/account` Creates a new Stripe Express connected account **Request body** | Field | Type | Required | Description | | -------------- | ------ | -------- | ----------- | | `country` | string | No | | | `stripeRegion` | string | No | | **Responses** | Code | Description | | ----- | ---------------------------- | | `200` | Account created successfully | | `500` | Server error | --- ### Create Stripe account session `POST /pos/account_session` Creates a Stripe account session for embedded Connect components **Request body** | Field | Type | Required | Description | | -------------- | ------ | -------- | -------------------- | | `account` | string | Yes | Connected account ID | | `stripeRegion` | string | No | | **Responses** | Code | Description | | ----- | -------------------------------------- | | `200` | Account session client secret returned | | `400` | Missing account parameter | | `500` | Server error | --- ### Create Stripe Express Dashboard login link `POST /pos/dashboard_link` Creates a login link for the connected account to access their full Stripe Dashboard with reports and analytics **Request body** | Field | Type | Required | Description | | -------------- | ------ | -------- | -------------------- | | `account` | string | Yes | Connected account ID | | `stripeRegion` | string | No | | **Responses** | Code | Description | | ----- | ---------------------------- | | `200` | Dashboard login URL returned | | `400` | Missing account parameter | | `500` | Server error | --- ### Create terminal connection token `POST /pos/connection_token` Creates a Stripe Terminal connection token for reader initialization **Responses** | Code | Description | | ----- | -------------------------------- | | `200` | Connection token secret returned | | `500` | Server error | --- ### Create payment intent for reader `POST /pos/create_payment_intent` Creates a Stripe payment intent for terminal reader payments with support for connected accounts **Request body** | Field | Type | Required | Description | | ------------------------- | ------- | -------- | --------------- | | `amount` | integer | Yes | Amount in cents | | `currency` | string | No | | | `connected_account_id` | string | No | | | `fee_in_cents` | integer | No | | | `use_destination_charges` | boolean | No | | **Responses** | Code | Description | | ----- | ---------------------- | | `200` | Payment intent created | | `500` | Server error | --- --- # Public API Source: https://docs.rentaltide.com/api-reference/public/ > Public-facing endpoints for booking widgets and customer self-service Public endpoints that power the customer-facing booking widget, cancellation flows, participant management, and membership enrollment. These endpoints do not require admin authentication. ## Public API ### Get customer inventory data `GET /public/customer` Retrieves all inventory items for a customer including locations, pricing, and bookings. Response is AES encrypted. **Parameters** | Name | In | Type | Required | Description | | ------------- | ----- | ------ | -------- | --------------- | | `customer_id` | query | string | Yes | The customer ID | **Responses** | Code | Description | | ----- | ----------------------------- | | `200` | Encrypted inventory data | | `400` | Missing customer_id parameter | | `500` | Server error | --- ### Get minimal inventory info for embed widget `GET /public/widget-info` Returns unencrypted minimal boat data (name, image, price, capacity, category) for use by the embed-booking.js widget on third-party sites. **Parameters** | Name | In | Type | Required | Description | | -------------- | ----- | ------ | -------- | ----------- | | `customer_id` | query | string | Yes | | | `inventory_id` | query | string | Yes | | **Responses** | Code | Description | | ----- | --------------------------- | | `200` | Minimal inventory info | | `400` | Missing required parameters | | `404` | Inventory not found | --- ### Get booking details `GET /public/booking` Retrieves details for a specific booking by transaction ID **Parameters** | Name | In | Type | Required | Description | | --------------- | ----- | ------ | -------- | ------------------------- | | `TransactionId` | query | string | Yes | The rental/transaction ID | **Responses** | Code | Description | | ----- | ------------------------------- | | `200` | Booking details | | `400` | Missing TransactionId parameter | | `500` | Server error | --- ### Update booking `PATCH /public/booking` Updates booking fields using dynamic field paths **Request body** | Field | Type | Required | Description | | ---------- | ------ | -------- | ----------------------------------------------------------- | | `rentalId` | string | Yes | | | `data` | object | No | Key-value pairs of fields to update (supports dot notation) | **Responses** | Code | Description | | ----- | ------------------------ | | `200` | Updated booking data | | `400` | Missing data or rentalId | | `500` | Server error | --- ### Get order with all line items `GET /public/order/{orderId}` Resolves orderId as bookingId, bundleGroupId, or single rentalId and returns grouped line items **Parameters** | Name | In | Type | Required | Description | | --------- | ---- | ------ | -------- | ---------------------------------------------------- | | `orderId` | path | string | Yes | The order ID (bookingId, bundleGroupId, or rentalId) | **Responses** | Code | Description | | ----- | --------------------- | | `200` | Order with line items | | `404` | Order not found | | `500` | Server error | --- ### Check asset availability `GET /public/check-availability` Checks if a specific asset is available during a time range **Parameters** | Name | In | Type | Required | Description | | ----------------- | ----- | ------- | -------- | -------------------------------------------- | | `inventoryId` | query | string | Yes | The inventory ID | | `assetId` | query | string | Yes | The asset ID | | `startUtc` | query | integer | Yes | Start time as Unix timestamp | | `endUtc` | query | integer | Yes | End time as Unix timestamp | | `excludeRentalId` | query | string | No | Rental ID to exclude from availability check | **Responses** | Code | Description | | ----- | --------------------------- | | `200` | Availability status | | `400` | Missing required parameters | | `500` | Server error | --- ### Get available staff `GET /public/available-staff` Retrieves staff members available for a location with a specific skill during a time range **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | -------------------------------------------------------- | | `locationId` | query | string | Yes | The location ID | | `skill` | query | string | Yes | The required skill (coach, captain, trainer, operations) | | `startTime` | query | string | Yes | Start time in ISO format | | `endTime` | query | string | Yes | End time in ISO format | **Responses** | Code | Description | | ----- | --------------------------- | | `200` | List of available staff | | `400` | Missing required parameters | | `500` | Server error | --- ### Get available staff for date range `GET /public/available-staff-range` Retrieves staff availability by skill for each day in a date range **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | ------------------------ | | `locationId` | query | string | Yes | The location ID | | `start` | query | string | Yes | Start date in ISO format | | `end` | query | string | Yes | End date in ISO format | **Responses** | Code | Description | | ----- | ----------------------------------- | | `200` | Staff availability by day and skill | | `400` | Missing required parameters | | `500` | Server error | --- ### Add to waitlist `POST /public/waitlist` Adds a customer to the waitlist for an inventory item **Request body** | Field | Type | Required | Description | | -------------- | ------- | -------- | ----------- | | `firstName` | string | Yes | | | `lastName` | string | Yes | | | `email` | string | Yes | | | `date` | string | Yes | | | `time` | string | No | | | `duration` | integer | No | | | `inventoryId` | string | Yes | | | `locationId` | string | Yes | | | `customerId` | string | No | | | `addons` | array | No | | | `boatAddons` | array | No | | | `giftCardCode` | string | No | | | `refAffiliate` | string | No | | **Responses** | Code | Description | | ----- | ----------------------------------- | | `201` | Waitlist entry created successfully | | `400` | Missing required fields | | `500` | Server error | --- ### Save cart recovery data `POST /public/cartRecovery` Saves or updates cart recovery data for abandoned cart emails **Request body** | Field | Type | Required | Description | | ------------- | ------ | -------- | ----------- | | `id` | string | Yes | | | `firstName` | string | No | | | `lastName` | string | No | | | `email` | string | Yes | | | `bookingInfo` | object | No | | | `locationId` | string | Yes | | | `cartData` | object | No | | | `customerId` | string | No | | **Responses** | Code | Description | | ----- | ---------------------------------------- | | `200` | Cart recovery data saved | | `400` | Missing required fields or invalid email | | `500` | Server error | --- ### Get cart recovery data `GET /public/cartRecovery/{id}` Retrieves cart recovery data by stable ID **Parameters** | Name | In | Type | Required | Description | | ---- | ---- | ------ | -------- | -------------------- | | `id` | path | string | Yes | The cart recovery ID | **Responses** | Code | Description | | ----- | ---------------------------- | | `200` | Cart recovery data | | `400` | Recovery ID required | | `404` | Cart recovery data not found | | `500` | Server error | --- ### Mark cart recovery as completed `DELETE /public/cartRecovery/{id}` Marks a cart recovery record as completed (booking was finished) **Parameters** | Name | In | Type | Required | Description | | ---- | ---- | ------ | -------- | -------------------- | | `id` | path | string | Yes | The cart recovery ID | **Responses** | Code | Description | | ----- | --------------------------------- | | `200` | Cart recovery marked as completed | | `400` | Recovery ID required | | `500` | Server error | --- ### Get cart recovery analytics `GET /public/cartRecovery/analytics/{locationId}` Retrieves cart recovery analytics for a location **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | ----------------- | | `locationId` | path | string | Yes | The location ID | | `startDate` | query | string | No | Start date filter | | `endDate` | query | string | No | End date filter | **Responses** | Code | Description | | ----- | -------------- | | `200` | Analytics data | | `500` | Server error | --- ### Get monthly availability `GET /public/availability` Retrieves availability for each day in a month for an inventory item **Parameters** | Name | In | Type | Required | Description | | ------------- | ----- | ------ | -------- | ------------------------------ | | `inventoryId` | query | string | Yes | The inventory ID | | `locationId` | query | string | Yes | The location ID | | `month` | query | string | Yes | Month in YYYY-MM format | | `timezone` | query | string | No | Timezone for date calculations | **Responses** | Code | Description | | ----- | -------------------------------- | | `200` | Daily availability for the month | | `400` | Missing required parameters | | `404` | Inventory or location not found | | `500` | Server error | --- ### Get custom code integration `GET /public/getCustomCode` Returns custom code integration settings for a customer. Returns 204 if not configured. **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | --------------- | | `customerId` | query | string | Yes | The customer ID | **Responses** | Code | Description | | ----- | ---------------------------- | | `200` | Custom code configuration | | `204` | Custom code not configured | | `400` | Missing customerId parameter | | `500` | Server error | --- ### Get Google Tag Manager configuration `GET /public/getGTM` Returns GTM configuration for a customer. Returns 204 if not configured. **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | --------------- | | `customerId` | query | string | Yes | The customer ID | **Responses** | Code | Description | | ----- | ---------------------------- | | `200` | GTM configuration | | `204` | GTM not configured | | `400` | Missing customerId parameter | | `500` | Server error | --- ### Get Meta Conversion API configuration `GET /public/getMetaConversion` Returns Meta Conversion API (Facebook Pixel) configuration. Returns 204 if not configured. **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | --------------- | | `customerId` | query | string | Yes | The customer ID | **Responses** | Code | Description | | ----- | ------------------------------ | | `200` | Meta Conversion configuration | | `204` | Meta Conversion not configured | | `400` | Missing customerId parameter | | `500` | Server error | --- ### Get TikTok Pixel configuration `GET /public/getTikTokPixel` Returns TikTok Pixel configuration for a customer. Returns 204 if not configured. **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | --------------- | | `customerId` | query | string | Yes | The customer ID | **Responses** | Code | Description | | ----- | ---------------------------- | | `200` | TikTok Pixel configuration | | `204` | TikTok Pixel not configured | | `400` | Missing customerId parameter | | `500` | Server error | --- ### Get WhatsApp Business configuration `GET /public/getWhatsApp` Returns WhatsApp Business configuration for a customer **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | --------------- | | `customerId` | query | string | Yes | The customer ID | **Responses** | Code | Description | | ----- | --------------------------------------------- | | `200` | WhatsApp Business configuration | | `400` | Missing customerId parameter | | `404` | Customer not found or WhatsApp not configured | | `500` | Server error | --- ### Add protection plan to booking `POST /public/bookings/{rentalId}/protection-plans` Adds a protection plan to an existing booking and charges the customer **Parameters** | Name | In | Type | Required | Description | | ---------- | ---- | ------ | -------- | --------------------- | | `rentalId` | path | string | Yes | The rental/booking ID | **Request body** | Field | Type | Required | Description | | ---------------- | ------ | -------- | ----------- | | `planId` | string | Yes | | | `planName` | string | Yes | | | `percentage` | number | No | | | `minimum` | number | No | | | `price` | number | No | | | `bookingTotal` | number | No | | | `calculatedCost` | number | Yes | | **Responses** | Code | Description | | ----- | -------------------------------------------- | | `200` | Protection plan added successfully | | `400` | Missing required fields or no payment method | | `404` | Booking not found | | `500` | Server error | --- ### Add a tip to a booking `POST /public/bookings/{rentalId}/tip` Processes a tip for a completed booking using the customer's stored payment method **Parameters** | Name | In | Type | Required | Description | | ---------- | ---- | ------ | -------- | --------------------- | | `rentalId` | path | string | Yes | The rental/booking ID | **Request body** | Field | Type | Required | Description | | ------------ | ------ | -------- | ----------------------------------------------------- | | `amount` | number | Yes | The tip amount in the booking's currency | | `percentage` | number | No | The tip percentage (if calculated from booking total) | **Responses** | Code | Description | | ----- | --------------------------------- | | `200` | Tip processed successfully | | `400` | Invalid request or payment failed | | `404` | Booking not found | | `500` | Server error | --- ### Get Apple Wallet pass data `GET /public/bookings/{rentalId}/apple-wallet` Generates Apple Wallet pass data including QR code for a booking **Parameters** | Name | In | Type | Required | Description | | ---------- | ---- | ------ | -------- | --------------------- | | `rentalId` | path | string | Yes | The rental/booking ID | **Responses** | Code | Description | | ----- | ---------------------- | | `200` | Apple Wallet pass data | | `404` | Booking not found | | `500` | Server error | --- ### Download Apple Wallet pass file `GET /public/bookings/{rentalId}/apple-wallet/download` Downloads the Apple Wallet pass file (.pkpass) for a booking **Parameters** | Name | In | Type | Required | Description | | ---------- | ---- | ------ | -------- | --------------------- | | `rentalId` | path | string | Yes | The rental/booking ID | **Responses** | Code | Description | | ----- | --------------------------- | | `200` | PKPass file download | | `404` | Booking not found | | `500` | Server error | | `501` | Apple Wallet not configured | --- ### Get Google Wallet pass data `GET /public/bookings/{rentalId}/google-wallet` Generates Google Wallet pass save URL for a booking **Parameters** | Name | In | Type | Required | Description | | ---------- | ---- | ------ | -------- | --------------------- | | `rentalId` | path | string | Yes | The rental/booking ID | **Responses** | Code | Description | | ----- | ---------------------- | | `200` | Google Wallet save URL | | `404` | Booking not found | | `500` | Server error | --- ### Get detailed day availability `GET /public/day-availability` Retrieves detailed availability for a specific day including time slots and bookings **Parameters** | Name | In | Type | Required | Description | | ------------- | ----- | ------ | -------- | ------------------------------ | | `inventoryId` | query | string | Yes | The inventory ID | | `locationId` | query | string | Yes | The location ID | | `date` | query | string | Yes | Date in YYYY-MM-DD format | | `timezone` | query | string | No | Timezone for date calculations | **Responses** | Code | Description | | ----- | ------------------------------- | | `200` | Day availability details | | `400` | Missing required parameters | | `404` | Inventory or location not found | | `500` | Server error | --- ### Get time slot popularity data `GET /public/time-slot-popularity` Returns historical booking popularity data for time slots. Used for "Best Selling" badges. **Parameters** | Name | In | Type | Required | Description | | ------------- | ----- | ------- | -------- | --------------------------------------- | | `inventoryId` | query | string | Yes | The inventory ID | | `locationId` | query | string | Yes | The location ID | | `dayOfWeek` | query | string | No | Day of week for day-specific popularity | | `duration` | query | integer | No | Rental duration in hours | **Responses** | Code | Description | | ----- | --------------------------- | | `200` | Time slot popularity data | | `400` | Missing required parameters | | `404` | Location not found | | `500` | Server error | --- ### Fetch reviews for a location `POST /public/locations/{locationId}/reviews` Public endpoint to fetch reviews from connected platforms (Google, TripAdvisor) for a location **Parameters** | Name | In | Type | Required | Description | | ------------ | ---- | ------ | -------- | --------------- | | `locationId` | path | string | Yes | The location ID | **Request body** | Field | Type | Required | Description | | ------------------- | ----- | -------- | ----------- | | `reviewConnections` | array | Yes | | **Responses** | Code | Description | | ----- | -------------------------------- | | `200` | Reviews from connected platforms | | `400` | Missing reviewConnections array | | `500` | Server error | --- ### Upload document for booking `POST /public/bookings/{rentalId}/documents` Upload insurance or ownership documents for a booking. No authentication required. **Parameters** | Name | In | Type | Required | Description | | ---------- | ---- | ------ | -------- | --------------------- | | `rentalId` | path | string | Yes | The rental/booking ID | **Responses** | Code | Description | | ----- | ------------------------------ | | `200` | Document uploaded successfully | | `400` | Missing or invalid parameters | | `404` | Booking not found | | `500` | Server error | --- ### AI customer assistant `POST /public/customer-sidekick` Customer-facing AI assistant for booking-specific questions **Request body** | Field | Type | Required | Description | | ---------- | ------ | -------- | ----------- | | `rentalId` | string | Yes | | | `message` | string | Yes | | **Responses** | Code | Description | | ----- | ----------------------- | | `200` | AI response | | `400` | Missing required fields | | `500` | Server error | --- ### AI boat recommendation engine `POST /public/boat-concierge` AI-powered boat recommendation engine to help customers find the perfect boat **Request body** | Field | Type | Required | Description | | --------------------- | ------ | -------- | ----------- | | `customerId` | string | Yes | | | `message` | string | Yes | | | `conversationHistory` | array | No | | | `selectedDate` | string | No | | | `locationId` | string | No | | **Responses** | Code | Description | | ----- | -------------------------- | | `200` | AI recommendation response | | `400` | Missing required fields | | `500` | Server error | --- ### Get public customer settings `GET /public/customer/{customerId}/public` Get public customer settings (loyalty, etc.) for checkout **Parameters** | Name | In | Type | Required | Description | | ------------ | ---- | ------ | -------- | --------------- | | `customerId` | path | string | Yes | The customer ID | **Responses** | Code | Description | | ----- | ------------------------ | | `200` | Public customer settings | | `400` | Missing customerId | | `404` | Customer not found | | `500` | Server error | --- ### Get saved payment methods `GET /public/payment-methods` Get saved payment methods for a Stripe customer **Parameters** | Name | In | Type | Required | Description | | ------------------ | ----- | ------ | -------- | ---------------------- | | `stripeCustomerId` | query | string | Yes | The Stripe customer ID | **Responses** | Code | Description | | ----- | ------------------------ | | `200` | List of payment methods | | `400` | Missing stripeCustomerId | | `500` | Server error | --- ## Public Cancellation ### Request cancellation OTP `POST /public/bookings/{rentalId}/cancellation-otp` Request an OTP code for booking cancellation. Sends OTP to the booking's email address. **Parameters** | Name | In | Type | Required | Description | | ---------- | ---- | ------ | -------- | --------------------- | | `rentalId` | path | string | Yes | The rental/booking ID | **Responses** | Code | Description | | ----- | --------------------------------------------- | | `200` | OTP sent successfully | | `400` | Missing rentalId or no valid email on booking | | `404` | Booking not found | | `500` | Server error | --- ### Verify cancellation OTP `POST /public/bookings/{rentalId}/verify-cancellation-otp` Verify OTP and return a session token for cancellation **Parameters** | Name | In | Type | Required | Description | | ---------- | ---- | ------ | -------- | --------------------- | | `rentalId` | path | string | Yes | The rental/booking ID | **Request body** | Field | Type | Required | Description | | ----------- | ------ | -------- | ----------- | | `sessionId` | string | Yes | | | `code` | string | Yes | | **Responses** | Code | Description | | ----- | ------------------------------- | | `200` | OTP verified successfully | | `400` | Invalid or expired session/code | | `500` | Server error | --- ### Check cancellation eligibility `GET /public/bookings/{rentalId}/cancellation-eligibility` Check if a booking is eligible for self-service cancellation. No authentication required. **Parameters** | Name | In | Type | Required | Description | | ---------- | ---- | ------ | -------- | --------------------- | | `rentalId` | path | string | Yes | The rental/booking ID | **Responses** | Code | Description | | ----- | ------------------------------- | | `200` | Cancellation eligibility status | | `400` | Missing rentalId | | `404` | Booking not found | | `500` | Server error | --- ### Cancel booking `POST /public/bookings/{rentalId}/cancel` Customer self-service cancellation endpoint. Requires OTP verification via X-OTP-Session header. **Parameters** | Name | In | Type | Required | Description | | --------------- | ------ | ------ | -------- | ----------------------------------- | | `rentalId` | path | string | Yes | The rental/booking ID | | `X-OTP-Session` | header | string | Yes | OTP session token from verification | **Request body** | Field | Type | Required | Description | | -------- | ------ | -------- | ----------------------- | | `reason` | string | No | Reason for cancellation | **Responses** | Code | Description | | ----- | ----------------------------------------------------- | | `200` | Booking cancelled successfully | | `400` | Missing rentalId or booking already cancelled | | `401` | Invalid or expired session | | `403` | Not permitted to cancel or cancellation window closed | | `404` | Booking not found | | `500` | Server error | --- ## Public Participants ### Get booking participants `GET /public/booking/participants` Get all participants for a booking with their waiver status **Parameters** | Name | In | Type | Required | Description | | ---------- | ----- | ------ | -------- | --------------------- | | `rentalId` | query | string | Yes | The rental/booking ID | **Responses** | Code | Description | | ----- | --------------------------------------- | | `200` | List of participants with waiver status | | `400` | Missing rentalId parameter | | `404` | Booking not found | | `500` | Server error | --- ### Add or update participant `POST /public/booking/participants` Add a new participant or update an existing one for a booking **Request body** | Field | Type | Required | Description | | ------------- | ------ | -------- | ----------- | | `rentalId` | string | Yes | | | `participant` | object | Yes | | **Responses** | Code | Description | | ----- | -------------------------------------- | | `200` | Participant added/updated successfully | | `400` | Missing required fields | | `404` | Booking not found | | `500` | Server error | --- ### Update participant `PUT /public/booking/participants` Update an existing participant for a booking **Request body** | Field | Type | Required | Description | | ------------- | ------ | -------- | ----------- | | `rentalId` | string | Yes | | | `participant` | object | Yes | | **Responses** | Code | Description | | ----- | ----------------------------------------- | | `200` | Participant updated successfully | | `400` | Missing required fields or participant ID | | `404` | Booking or participant not found | | `500` | Server error | --- ### Delete participant `DELETE /public/booking/participants/{participantId}` Remove a participant from a booking **Parameters** | Name | In | Type | Required | Description | | --------------- | ---- | ------ | -------- | ---------------------------- | | `participantId` | path | string | Yes | The participant ID to delete | **Request body** | Field | Type | Required | Description | | ---------- | ------ | -------- | ----------- | | `rentalId` | string | Yes | | **Responses** | Code | Description | | ----- | -------------------------------- | | `200` | Participant deleted successfully | | `400` | Missing required fields | | `404` | Booking not found | | `500` | Server error | --- ### Send waiver email `POST /public/booking/send-waiver-email` Send a waiver completion email to a participant **Request body** | Field | Type | Required | Description | | --------------- | ------ | -------- | ----------- | | `rentalId` | string | No | | | `participantId` | string | No | | | `email` | string | Yes | | | `firstName` | string | No | | | `lastName` | string | No | | | `waiverUrl` | string | Yes | | | `locationId` | string | No | | **Responses** | Code | Description | | ----- | ------------------------------ | | `200` | Waiver email sent successfully | | `400` | Missing required fields | | `500` | Server error | --- ### Send waiver SMS `POST /public/booking/send-waiver-sms` Send a waiver completion SMS to a participant **Request body** | Field | Type | Required | Description | | --------------- | ------ | -------- | ----------- | | `rentalId` | string | No | | | `participantId` | string | No | | | `phoneNumber` | string | Yes | | | `firstName` | string | No | | | `lastName` | string | No | | | `waiverUrl` | string | Yes | | | `locationId` | string | No | | **Responses** | Code | Description | | ----- | ---------------------------- | | `200` | Waiver SMS sent successfully | | `400` | Missing required fields | | `500` | Server error | --- ### Process participant payment `POST /public/booking/process-payment` Process a payment for a participant's share of the booking **Request body** | Field | Type | Required | Description | | --------------- | ------ | -------- | ----------- | | `rentalId` | string | Yes | | | `participantId` | string | Yes | | | `paymentSplit` | object | Yes | | **Responses** | Code | Description | | ----- | -------------------------------- | | `200` | Payment processed successfully | | `400` | Missing required fields | | `404` | Booking or participant not found | | `500` | Server error | --- ### Create payment intent `POST /public/booking/create-payment-intent` Create a Stripe payment intent for a participant payment **Request body** | Field | Type | Required | Description | | ----------------- | ------ | -------- | --------------- | | `rentalId` | string | Yes | | | `participantId` | string | Yes | | | `paymentMethodId` | string | Yes | | | `amount` | number | Yes | Amount in cents | | `paymentSplit` | object | Yes | | **Responses** | Code | Description | | ----- | ----------------------------------------- | | `200` | Payment intent created successfully | | `400` | Missing required fields or payment failed | | `404` | Booking or participant not found | | `500` | Server error | --- ## Public Memberships ### Get public membership tiers `GET /public/memberships/tiers/{locationId}` Get public membership tiers for a location (no auth required). Only returns tiers marked as showToPublic=true. **Parameters** | Name | In | Type | Required | Description | | ------------ | ---- | ------ | -------- | --------------- | | `locationId` | path | string | Yes | The location ID | **Responses** | Code | Description | | ----- | ------------------------------- | | `200` | List of public membership tiers | | `404` | Location not found | | `500` | Server error | --- ### Create membership checkout session `POST /public/memberships/checkout` Create a Stripe checkout session for membership signup (no auth required) **Request body** | Field | Type | Required | Description | | -------------- | ------- | -------- | ----------- | | `customerId` | string | Yes | | | `tierId` | string | Yes | | | `billingCycle` | string | Yes | | | `renterEmail` | string | Yes | | | `renterName` | string | No | | | `renterPhone` | string | No | | | `renterId` | string | No | | | `successUrl` | string | No | | | `cancelUrl` | string | No | | | `locationId` | string | No | | | `isInternal` | boolean | No | | **Responses** | Code | Description | | ----- | --------------------------------------------------------- | | `200` | Checkout session created or membership activated directly | | `400` | Missing required fields or tier not available | | `404` | Tier or location not found | | `500` | Server error | --- ### Get membership details `GET /public/memberships/details/{membershipId}` Get membership details by membership ID (for success page after direct subscription) **Parameters** | Name | In | Type | Required | Description | | -------------- | ---- | ------ | -------- | ----------------- | | `membershipId` | path | string | Yes | The membership ID | **Responses** | Code | Description | | ----- | -------------------- | | `200` | Membership details | | `404` | Membership not found | | `500` | Server error | --- ### Check membership status `GET /public/memberships/status/{sessionId}` Check status of a membership signup by checkout session ID **Parameters** | Name | In | Type | Required | Description | | ----------- | ---- | ------ | -------- | ------------------------------ | | `sessionId` | path | string | Yes | The Stripe checkout session ID | **Responses** | Code | Description | | ----- | -------------------- | | `200` | Membership status | | `404` | Membership not found | | `500` | Server error | --- ### Activate membership `POST /public/memberships/activate` Activate a membership after successful Stripe checkout (no auth required). Called from the success page after Stripe redirects back. **Request body** | Field | Type | Required | Description | | ----------- | ------ | -------- | ------------------------------ | | `sessionId` | string | Yes | The Stripe checkout session ID | **Responses** | Code | Description | | ----- | ------------------------------------------ | | `200` | Membership activated successfully | | `400` | Missing sessionId or payment not completed | | `404` | Membership not found for this session | | `500` | Server error | --- ## Scanner ### Scan a license `GET /scanner/scan` Triggers the license scanner and parses the scanned license data. **Responses** | Code | Description | | ----- | ------------------------------------------- | | `200` | License scanned successfully | | `404` | No license scanned or scanner not triggered | | `500` | Scanner error | --- --- # Slips API Source: https://docs.rentaltide.com/api-reference/slips/ > Manage marina slips, reservations, contracts, and tenant access Endpoints for managing marina slip inventory, reservations, contracts, waitlists, guest access, subscriptions, and tenant portal operations. ## Slips ### Get all slips for a location `GET /slips` **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | ----------- | | `locationId` | query | string | Yes | | | `status` | query | string | No | | | `unitType` | query | string | No | | | `section` | query | string | No | | --- ### Create a new slip `POST /slips` Creates a new slip. Requires an active slip subscription. If adding this slip exceeds the current quota, additional slips ($10/slip/month) will be automatically billed. --- ### Get available slips matching criteria `GET /slips/availability` --- ### Get distinct sections for a location `GET /slips/sections` --- ### Get slip status counts for a location `GET /slips/stats` --- ### Search slips by unit number or name `GET /slips/search` --- ### Bulk create slips with a prefix and number range `POST /slips/bulk-create` --- ### Bulk update multiple slips `PUT /slips/bulk` --- ### Rename a section across all slips `PUT /slips/sections/rename` --- ### Get sections with slip counts for a location `GET /slips/sections/counts` --- ### Delete a section (clear section from all slips) `DELETE /slips/sections/{name}` --- ### Get a single slip by ID `GET /slips/{id}` --- ### Update a slip `PUT /slips/{id}` --- ### Delete a slip (soft delete by setting status to out_of_service) `DELETE /slips/{id}` --- ### Update slip status `PATCH /slips/{id}/status` --- ## Slip Reservations ### Get reservations with filters `GET /slip-reservations` --- ### Create a new reservation `POST /slip-reservations` --- ### Get reservation statistics `GET /slip-reservations/stats` --- ### Get reservations due for billing `GET /slip-reservations/due-billing` --- ### Get reservations expiring soon `GET /slip-reservations/expiring` --- ### Check if a unit is available for dates `GET /slip-reservations/check-availability` --- ### Get reservation by reservation number `GET /slip-reservations/by-number/{reservationNumber}` --- ### Get a single reservation by ID `GET /slip-reservations/{id}` --- ### Update a reservation `PUT /slip-reservations/{id}` --- ### Permanently delete a cancelled reservation and all associated data `DELETE /slip-reservations/{id}` --- ### Recalculate totalAmount based on current pricing fields `POST /slip-reservations/{id}/recalculate-total` --- ### Confirm a pending reservation `POST /slip-reservations/{id}/confirm` --- ### Send bill to customer with hold timer `POST /slip-reservations/{id}/send-bill` --- ### Check in a reservation `POST /slip-reservations/{id}/check-in` --- ### Check out a reservation `POST /slip-reservations/{id}/check-out` --- ### Cancel a reservation `POST /slip-reservations/{id}/cancel` --- ### Transfer reservation to a different unit `POST /slip-reservations/{id}/transfer` --- ### Mark contract as signed `POST /slip-reservations/{id}/contract-signed` --- ### Send a message to slip reservation customer (staff) `POST /slip-reservations/{id}/messages` --- ### Get messages for a slip reservation (staff) `GET /slip-reservations/{id}/messages` --- ### Record a payment for a slip reservation `POST /slip-reservations/{id}/record-payment` --- ### Get payment history for a slip reservation `GET /slip-reservations/{id}/payments` --- ### Charge a saved credit card for a slip reservation `POST /slip-reservations/{id}/charge-card` --- ### Record a terminal or tap-to-pay payment for a slip reservation `POST /slip-reservations/{id}/terminal-charge` --- ### Recognize deferred revenue for a slip reservation `POST /slip-reservations/{id}/recognize-revenue` --- ### Refund a slip reservation payment `POST /slip-reservations/{id}/refund` --- ## Slip Contracts ### Get contract templates for a location `GET /slip-contracts/templates` --- ### Create a new contract template `POST /slip-contracts/templates` --- ### Get available template variables `GET /slip-contracts/templates/variables` --- ### Get a specific contract template `GET /slip-contracts/templates/{id}` --- ### Update a contract template `PUT /slip-contracts/templates/{id}` --- ### Delete a contract template `DELETE /slip-contracts/templates/{id}` --- ### Duplicate a contract template (including defaults) `POST /slip-contracts/templates/{id}/duplicate` --- ### Get all contracts for a reservation `GET /slip-contracts/reservation/{reservationId}` --- ### Get reservations with pending contracts `GET /slip-contracts/pending` --- ### Get reservations with signed contracts `GET /slip-contracts/signed` --- ### Get contract statistics `GET /slip-contracts/stats` --- ### Generate a contract for a reservation `POST /slip-contracts/generate` --- ### Send contract for signature `POST /slip-contracts/send` --- ### Mark contract as signed `POST /slip-contracts/sign` --- ### Resend contract for signature `POST /slip-contracts/resend` --- ### Void a contract `POST /slip-contracts/void` --- ### Regenerate PDF for a signed contract `POST /slip-contracts/regenerate-pdf` --- ## Slip Waitlist ### Get waitlist entries for a location `GET /slips/waitlist` **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | ----------- | | `locationId` | query | string | Yes | | | `status` | query | string | No | | --- ### Add to waitlist `POST /slips/waitlist` --- ### Get waitlist statistics for a location `GET /slips/waitlist/stats` --- ### Get waitlist entries for a specific renter `GET /slips/waitlist/renter/{renterId}` --- ### Get a single waitlist entry `GET /slips/waitlist/{id}` --- ### Update a waitlist entry `PUT /slips/waitlist/{id}` --- ### Delete a waitlist entry `DELETE /slips/waitlist/{id}` --- ### Make an offer to a waitlist entry `POST /slips/waitlist/{id}/offer` --- ### Accept an offer `POST /slips/waitlist/{id}/accept` --- ### Decline an offer `POST /slips/waitlist/{id}/decline` --- ### Cancel a waitlist entry `POST /slips/waitlist/{id}/cancel` --- ### Find matching waitlist entries for an available unit `GET /slips/waitlist/match/{unitId}` --- ## Slip Guest Access ### Get guest access entries for a location `GET /slips/guest-access` **Parameters** | Name | In | Type | Required | Description | | --------------- | ----- | ------ | -------- | ----------- | | `locationId` | query | string | Yes | | | `reservationId` | query | string | No | | | `status` | query | string | No | | --- ### Create a new guest access pass `POST /slips/guest-access` --- ### Get guest access statistics `GET /slips/guest-access/stats` --- ### Verify a guest access code `GET /slips/guest-access/verify/{accessCode}` --- ### Get a single guest access entry `GET /slips/guest-access/{id}` --- ### Update a guest access entry `PUT /slips/guest-access/{id}` --- ### Delete a guest access entry `DELETE /slips/guest-access/{id}` --- ### Record a guest check-in `POST /slips/guest-access/{id}/check-in` --- ### Mark guest ID as verified `POST /slips/guest-access/{id}/verify-id` --- ### Revoke guest access `POST /slips/guest-access/{id}/revoke` --- ### Expire old guest passes for a location `POST /slips/guest-access/expire` --- ## Slip Settings ### Get slip booking settings for a location `GET /slip-settings/{locationId}` Returns the slip booking configuration with defaults merged --- ### Update slip booking settings for a location `PUT /slip-settings/{locationId}` --- ### Get available contract templates for a location `GET /slip-settings/{locationId}/templates` --- ### Reset slip booking settings to defaults `POST /slip-settings/{locationId}/reset` --- ## Slip Subscription ### Get current slip subscription status `GET /slip-subscription/status` --- ### Create Stripe checkout session for slip subscription `POST /slip-subscription/create-checkout` --- ### Add more slips to existing subscription (auto-bill per slip) `POST /slip-subscription/add-slips` --- ### Create Stripe customer portal session for subscription management `POST /slip-subscription/portal` --- ### Cancel slip subscription at end of billing period `POST /slip-subscription/cancel` --- ## Slip Customer Portal ### Get current session info `GET /slip-portal/session` --- ### Get customer's reservations `GET /slip-portal/reservations` --- ### Get reservation details `GET /slip-portal/reservations/:id` --- ### Update vessel information for a reservation `PUT /slip-portal/reservations/:id/vessel` --- ### Get contract for signing `GET /slip-portal/reservations/:id/contract` --- ### Sign contract `POST /slip-portal/reservations/:id/contract/sign` --- ### Get document requirements and submitted documents `GET /slip-portal/reservations/:id/documents` --- ### Upload a document `POST /slip-portal/reservations/:id/documents` --- ### Get message thread `GET /slip-portal/reservations/:id/messages` --- ### Send a message `POST /slip-portal/reservations/:id/messages` --- ### Upload a document file to S3 `POST /slip-portal/upload` --- ### Get saved payment methods `GET /slip-portal/payment-methods` --- ### Create a SetupIntent to add a new payment method `POST /slip-portal/setup-intent` --- ### Pay for a reservation `POST /slip-portal/reservations/:id/pay` --- ### Create a PaymentIntent for a reservation (for Stripe Elements) `POST /slip-portal/reservations/:id/create-payment-intent` --- ### Get guest access list for a reservation `GET /slip-portal/reservations/:id/guest-access` --- ### Add a guest access pass `POST /slip-portal/reservations/:id/guest-access` --- ### Revoke guest access `DELETE /slip-portal/reservations/:id/guest-access/:guestId` --- ### Get haul services for a reservation `GET /slip-portal/reservations/:id/haul-services` --- ### Request a haul service `POST /slip-portal/reservations/:id/haul-services` --- ### Cancel a haul service request `POST /slip-portal/reservations/:id/haul-services/:serviceId/cancel` --- ### Confirm a scheduled haul service `POST /slip-portal/reservations/:id/haul-services/:serviceId/confirm` --- ## Public Slips ### Get all active maps with pins for a location `GET /public/slips/maps/{locationId}` --- ### Get slips as a list (for list view) `GET /public/slips/list/{locationId}` --- ### Get single slip details `GET /public/slips/{slipId}` --- ### Check slip availability for date range `GET /public/slips/{slipId}/availability` --- ### Join the waitlist for a slip `POST /public/slips/{slipId}/waitlist` --- ### Calculate price for a date range `POST /public/slips/calculate-price` --- ### Create a slip reservation (initiates checkout flow) `POST /public/slips/book` Creates a reservation using location-level booking settings for payment, approval, and documents --- ### Get document requirements and submission status `GET /public/slips/reservations/{reservationId}/documents` --- ### Submit a document for a reservation `POST /public/slips/reservations/{reservationId}/documents` Accepts document metadata (actual file upload handled separately via S3 presigned URL) --- ### Get location info for slip booking widget `GET /public/slips/location/{locationId}` Returns location details with slip booking configuration --- --- # Staff API Source: https://docs.rentaltide.com/api-reference/staff/ > Manage staff accounts, permissions, and schedules Endpoints for managing user accounts, staff roles and permissions, and staff scheduling. ## Users ### Get current user data `GET /user` Returns user data including locations, permissions, and settings **Responses** | Code | Description | | ----- | -------------------------------- | | `200` | User data retrieved successfully | | `401` | Unauthorized | | `500` | Internal server error | --- ### Create a new user `POST /user` Creates a new user via Auth0 and stores the record in DynamoDB **Request body** | Field | Type | Required | Description | | ------------- | ------ | -------- | ----------- | | `email` | string | Yes | | | `customerId` | string | Yes | | | `name` | string | Yes | | | `role` | string | No | | | `permissions` | array | No | | | `locations` | array | No | | | `userSkills` | array | No | | **Responses** | Code | Description | | ----- | ------------------------- | | `201` | User created successfully | | `400` | Missing required fields | | `500` | Internal server error | --- ### Update current user `PATCH /user` Updates the authenticated user's record in DynamoDB **Request body** | Field | Type | Required | Description | | ----------------- | ------ | -------- | ----------- | | `profileName` | string | No | | | `locations` | array | No | | | `userPermissions` | array | No | | | `userSkills` | array | No | | **Responses** | Code | Description | | ----- | ------------------------- | | `200` | User updated successfully | | `401` | Unauthorized | | `500` | Internal server error | --- ### Delete a user `DELETE /user` Deletes the user from Auth0 and DynamoDB **Request body** | Field | Type | Required | Description | | ----- | ------ | -------- | --------------------- | | `id` | string | Yes | The user ID to delete | **Responses** | Code | Description | | ----- | ------------------------- | | `200` | User deleted successfully | | `400` | User ID is required | | `500` | Internal server error | --- ### Accept terms and conditions `POST /user/accept-terms` Records the user's acceptance of terms of service, provider terms, and privacy policy **Responses** | Code | Description | | ----- | --------------------------- | | `200` | Terms accepted successfully | | `401` | Unauthorized | | `500` | Internal server error | --- ### Check if user needs to accept terms `GET /user/terms-status` Returns whether the user has accepted the current version of terms **Responses** | Code | Description | | ----- | ---------------------- | | `200` | Terms status retrieved | | `401` | Unauthorized | --- ### Download user's personal data as PDF `GET /user/export/my-data` Exports all personal data associated with the authenticated user as a formatted PDF (GDPR/privacy compliance) **Responses** | Code | Description | | ----- | -------------------------------------- | | `200` | User data exported successfully as PDF | | `401` | Unauthorized | | `500` | Internal server error | --- ### Get audit logs for a specific user `GET /user/{userId}/audit-logs` Returns activity logs for a user (requires admin permissions) **Parameters** | Name | In | Type | Required | Description | | -------- | ----- | ------- | -------- | ----------- | | `userId` | path | string | Yes | | | `limit` | query | integer | No | | | `offset` | query | integer | No | | **Responses** | Code | Description | | ----- | ------------------------------------ | | `200` | Audit logs retrieved successfully | | `401` | Unauthorized | | `403` | Forbidden - insufficient permissions | | `500` | Internal server error | --- ### Register an Expo push token `POST /user/push-token` Stores an Expo push token for the authenticated user to enable push notifications **Request body** | Field | Type | Required | Description | | ------- | ------ | -------- | ------------------------------------------------- | | `token` | string | Yes | The Expo push token (e.g. ExponentPushToken[xxx]) | **Responses** | Code | Description | | ----- | ---------------------------------- | | `200` | Push token registered successfully | | `400` | Token is required | | `401` | Unauthorized | | `500` | Internal server error | --- ### Remove an Expo push token `DELETE /user/push-token` Removes an Expo push token for the authenticated user **Request body** | Field | Type | Required | Description | | ------- | ------ | -------- | ----------------------------- | | `token` | string | Yes | The Expo push token to remove | **Responses** | Code | Description | | ----- | ------------------------------- | | `200` | Push token removed successfully | | `400` | Token is required | | `401` | Unauthorized | | `500` | Internal server error | --- ## User Management ### Get users by customer ID `GET /userManagement` Retrieves all users associated with a customer ID. If no customerId is provided, uses the authenticated user's customerId. **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | ------------------------------ | | `customerId` | query | string | No | Customer ID to query users for | **Responses** | Code | Description | | ----- | ------------------------------------------------ | | `200` | Users retrieved successfully | | `400` | Customer ID not found for the authenticated user | | `401` | Unauthorized | | `404` | User not found | | `500` | Internal server error | --- ### Create a new user `POST /userManagement` Creates a new user via Auth0 and stores the record in DynamoDB **Request body** | Field | Type | Required | Description | | ------------- | ------- | -------- | ----------- | | `email` | string | Yes | | | `customerId` | string | Yes | | | `name` | string | Yes | | | `userRole` | string | No | | | `permissions` | array | No | | | `locations` | array | No | | | `userSkills` | array | No | | | `isSetup` | boolean | No | | **Responses** | Code | Description | | ----- | ------------------------- | | `201` | User created successfully | | `400` | Missing required fields | | `409` | User already exists | | `500` | Internal server error | --- ### Update a user `PATCH /userManagement` Updates the user record in DynamoDB **Request body** | Field | Type | Required | Description | | ----- | ------ | -------- | ----------------- | | `id` | string | Yes | User ID to update | **Responses** | Code | Description | | ----- | ------------------------- | | `200` | User updated successfully | | `400` | User ID is required | | `500` | Internal server error | --- ### Delete a user `DELETE /userManagement` Deletes the user from Auth0 and DynamoDB **Request body** | Field | Type | Required | Description | | ----- | ------ | -------- | ----------------- | | `id` | string | Yes | User ID to delete | **Responses** | Code | Description | | ----- | ------------------------- | | `200` | User deleted successfully | | `400` | User ID is required | | `500` | Internal server error | --- ### Find available phone numbers `POST /userManagement/find-phone-numbers` Searches for available phone numbers by country and area code **Request body** | Field | Type | Required | Description | | ---------- | ------ | -------- | ------------------- | | `country` | string | Yes | Country code | | `areaCode` | string | Yes | Area code to search | **Responses** | Code | Description | | ----- | ---------------------------------------- | | `200` | Available numbers retrieved successfully | | `400` | Country and area code are required | | `500` | Internal server error | --- ### Purchase a phone number `POST /userManagement/purchase-phone-number` Purchases a phone number and assigns it to a location with default IVR configuration **Request body** | Field | Type | Required | Description | | ------------- | ------ | -------- | ----------------------------------- | | `phoneNumber` | string | Yes | Phone number to purchase | | `locationId` | string | Yes | Location ID to assign the number to | **Responses** | Code | Description | | ----- | ---------------------------------------- | | `200` | Phone number purchased successfully | | `400` | Phone number and locationId are required | | `500` | Internal server error | --- ### Resend staff invitation email `POST /userManagement/{id}/resend-invitation` Sends a password change email to the staff member so they can set their password **Parameters** | Name | In | Type | Required | Description | | ---- | ---- | ------ | -------- | ----------- | | `id` | path | string | Yes | User ID | **Responses** | Code | Description | | ----- | ---------------------------------- | | `200` | Invitation email sent successfully | | `404` | User not found | | `500` | Internal server error | --- ## Staff Schedule ### Create a new staff schedule `POST /staffSchedule` Creates a new schedule entry for a staff member at a location **Request body** | Field | Type | Required | Description | | ------------------- | ------- | -------- | ------------------------------- | | `customerId` | string | Yes | | | `locationId` | string | Yes | | | `staffId` | string | Yes | | | `startTime` | string | Yes | | | `endTime` | string | Yes | | | `recurring` | boolean | No | | | `recurrencePattern` | object | No | Pattern for recurring schedules | | `templateId` | string | No | | **Responses** | Code | Description | | ----- | ----------------------------- | | `201` | Schedule created successfully | | `400` | Missing required fields | | `500` | Server error | --- ### Get staff schedules `GET /staffSchedule` Retrieves schedules by locationId or customerId **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | ---------------------------------------------------------- | | `locationId` | query | string | No | The location ID (either locationId or customerId required) | | `customerId` | query | string | No | The customer ID (either locationId or customerId required) | **Responses** | Code | Description | | ----- | ------------------------------------- | | `200` | Successfully retrieved schedules | | `400` | At least one query parameter required | | `500` | Server error | --- ### Update a staff schedule `PUT /staffSchedule/{id}` Updates details of an existing staff schedule **Parameters** | Name | In | Type | Required | Description | | ---- | ---- | ------ | -------- | --------------- | | `id` | path | string | Yes | The schedule ID | **Request body** | Field | Type | Required | Description | | ------------------- | ------- | -------- | ----------- | | `startTime` | string | No | | | `endTime` | string | No | | | `recurring` | boolean | No | | | `recurrencePattern` | object | No | | **Responses** | Code | Description | | ----- | ----------------------------- | | `200` | Schedule updated successfully | | `400` | No fields to update | | `500` | Server error | --- ### Delete a staff schedule `DELETE /staffSchedule/{id}` Removes a staff schedule. Only the owner (matching customerId) can delete. **Parameters** | Name | In | Type | Required | Description | | ---- | ---- | ------ | -------- | --------------- | | `id` | path | string | Yes | The schedule ID | **Responses** | Code | Description | | ----- | ----------------------------------- | | `200` | Schedule deleted successfully | | `403` | Forbidden - no permission to delete | | `404` | Schedule not found | | `500` | Server error | --- --- # Waivers API Source: https://docs.rentaltide.com/api-reference/waivers/ > Manage waivers and in-house waiver templates Endpoints for managing waiver templates, retrieving signed waivers, and configuring in-house waiver flows. ## Waivers ### Get waiver URL by location `GET /waiverUrl` Retrieves the waiver URL and logo URL for a given location ID **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | ------------------------------------------ | | `locationId` | query | string | Yes | The location ID to retrieve waiver URL for | **Responses** | Code | Description | | ----- | ------------------------------------------------ | | `200` | Waiver URL and logo URL retrieved successfully | | `400` | Invalid or missing locationId | | `404` | Waiver URL not found for the provided locationId | | `500` | Internal server error | --- ### Validate a waiver number `GET /waiverNumberValidation` Validates a waiver number (PIN) and returns the waiver details if found and pending **Parameters** | Name | In | Type | Required | Description | | -------------- | ----- | ------ | -------- | ---------------------------------------------- | | `waiverNumber` | query | string | Yes | The waiver number (PIN) to validate | | `locationId` | query | string | Yes | The location ID to validate the waiver against | **Responses** | Code | Description | | ----- | --------------------------------------------------------- | | `200` | Waiver number validated successfully | | `400` | Invalid or missing waiverNumber or locationId | | `404` | Waiver number not found or duplicate waiver numbers found | | `500` | Internal server error | --- ## In-House Waivers ### Get location logo `GET /inHouseWaiver/logo/{locationId}` Retrieves the logo URL for a specific location **Parameters** | Name | In | Type | Required | Description | | ------------ | ---- | ------ | -------- | ---------------------------------------- | | `locationId` | path | string | Yes | The location ID to retrieve the logo for | **Responses** | Code | Description | | ----- | ------------------------------- | | `200` | Logo URL retrieved successfully | | `404` | Location not found | | `500` | Failed to fetch location logo | --- ### List waiver templates by location `GET /inHouseWaiver/waiver/templates/location/{locationId}` Retrieves all waiver templates for a specific location ID **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | ----------------------------------------- | | `locationId` | path | string | Yes | The location ID to retrieve templates for | | `fn` | query | string | No | First name (for tracking) | | `ln` | query | string | No | Last name (for tracking) | | `em` | query | string | No | Email (for tracking) | **Responses** | Code | Description | | ----- | -------------------------------------------- | | `200` | List of waiver templates | | `500` | Failed to fetch waiver templates by location | --- ### Create a waiver template `POST /inHouseWaiver/waiver/template` Creates a new waiver template. Requires authentication. **Request body** | Field | Type | Required | Description | | ------------- | ------ | -------- | ----------- | | `title` | string | Yes | | | `description` | string | No | | | `sections` | array | Yes | | | `customerId` | string | Yes | | | `locationId` | string | Yes | | | `assignTo` | array | No | | **Responses** | Code | Description | | ----- | ------------------------------------------- | | `201` | Template created successfully | | `403` | Unauthorized to create this waiver template | | `500` | Failed to create waiver template | --- ### Get a waiver template by ID `GET /inHouseWaiver/waiver/template/{templateId}` Retrieves a specific waiver template by its template ID **Parameters** | Name | In | Type | Required | Description | | ------------ | ---- | ------ | -------- | --------------------------- | | `templateId` | path | string | Yes | The template ID to retrieve | **Responses** | Code | Description | | ----- | -------------------------------------- | | `200` | Waiver template retrieved successfully | | `404` | Waiver template not found | | `500` | Failed to fetch waiver template | --- ### Update a waiver template `PUT /inHouseWaiver/waiver/template/{templateId}` Updates an existing waiver template. Requires authentication. **Parameters** | Name | In | Type | Required | Description | | ------------ | ---- | ------ | -------- | ------------------------- | | `templateId` | path | string | Yes | The template ID to update | **Request body** | Field | Type | Required | Description | | ------------- | ------ | -------- | ----------- | | `title` | string | No | | | `description` | string | No | | | `sections` | array | No | | | `customerId` | string | Yes | | | `locationId` | string | No | | | `assignTo` | array | No | | **Responses** | Code | Description | | ----- | ------------------------------------------- | | `200` | Template updated successfully | | `403` | Unauthorized to update this waiver template | | `404` | Waiver template not found | | `500` | Failed to update waiver template | --- ### Delete a waiver template `DELETE /inHouseWaiver/waiver/template/{templateId}` Deletes a waiver template. Requires authentication. **Parameters** | Name | In | Type | Required | Description | | ------------ | ---- | ------ | -------- | ------------------------- | | `templateId` | path | string | Yes | The template ID to delete | **Responses** | Code | Description | | ----- | ------------------------------------------- | | `200` | Template deleted successfully | | `403` | Unauthorized to delete this waiver template | | `404` | Waiver template not found | | `500` | Failed to delete waiver template | --- ### List all waiver templates `GET /inHouseWaiver/waiver/templates` Lists all waiver templates for the authenticated user's customer. Requires authentication. **Parameters** | Name | In | Type | Required | Description | | ------------ | ----- | ------ | -------- | -------------------------------------- | | `locationId` | query | string | Yes | The location ID to filter templates by | **Responses** | Code | Description | | ----- | ------------------------------- | | `200` | List of waiver templates | | `400` | Location ID is required | | `500` | Failed to list waiver templates | --- ### Sign a waiver `POST /inHouseWaiver/waiver/sign` Signs a waiver internally with form data, generates a PDF, and stores the signature record **Request body** | Field | Type | Required | Description | | --------------- | ------ | -------- | ------------------------------------------------------- | | `templateId` | string | Yes | The waiver template ID to sign | | `firstName` | string | Yes | | | `lastName` | string | Yes | | | `dob` | string | No | Date of birth | | `userEmail` | string | No | | | `phoneNumber` | string | No | | | `addressLine` | string | No | | | `formData` | object | Yes | Form responses including signatures as base64 data URLs | | `ipAddress` | string | No | | | `userAgent` | string | No | | | `waiverNumber` | string | No | | | `transactionId` | string | No | | | `tid` | string | No | | | `bookingData` | object | No | | | `assignTo` | string | No | | **Responses** | Code | Description | | ----- | -------------------------------------------------- | | `201` | Waiver signed successfully | | `404` | Waiver template not found | | `409` | Signature ID already exists (duplicate submission) | | `500` | Failed to sign waiver | --- ### Get a signed waiver by ID `GET /inHouseWaiver/waiver/sign/{signatureId}` Retrieves a signed waiver record by its signature ID **Parameters** | Name | In | Type | Required | Description | | ------------- | ---- | ------ | -------- | ---------------------------- | | `signatureId` | path | string | Yes | The signature ID to retrieve | **Responses** | Code | Description | | ----- | ------------------------------------ | | `200` | Signed waiver retrieved successfully | | `404` | Signed waiver not found | | `500` | Failed to fetch signed waiver | --- ### Get waiver signature info `GET /inHouseWaiver/waiver/sign/info/{signatureId}` Returns collected information about a signed waiver **Parameters** | Name | In | Type | Required | Description | | ------------- | ---- | ------ | -------- | -------------------------------- | | `signatureId` | path | string | Yes | The signature ID to get info for | **Responses** | Code | Description | | ----- | ---------------------------------- | | `200` | Waiver info retrieved successfully | | `404` | Signed waiver not found | | `500` | Failed to fetch waiver info | --- ### Verify waiver status `GET /inHouseWaiver/waiver/verify/{signatureId}` Verifies the status of a signed waiver including PDF existence and transaction update status **Parameters** | Name | In | Type | Required | Description | | ------------- | ---- | ------ | -------- | -------------------------- | | `signatureId` | path | string | Yes | The signature ID to verify | **Responses** | Code | Description | | ----- | ------------------------------ | | `200` | Waiver status verified | | `404` | Waiver signature not found | | `500` | Failed to verify waiver status | --- --- # Core features Source: https://docs.rentaltide.com/core/ > Dashboard, bookings, calendar, customers, messages, and support The core features you use every day to run your rental business. {% cardGroup cols=2 %} {% card title="Dashboard" href="/core/dashboard/" /%} {% card title="Bookings" href="/core/bookings/" /%} {% card title="Calendar" href="/core/calendar/" /%} {% card title="Customers" href="/core/customers/" /%} {% card title="Messages" href="/core/messages/" /%} {% card title="Support channel" href="/core/support-channel/" /%} {% /cardGroup %} --- # Bookings Source: https://docs.rentaltide.com/core/bookings/ > Central hub for viewing, filtering, and managing all reservations in a searchable data grid with inline status updates The Bookings page is your central command center for managing every reservation across your business. It displays all bookings in a sortable, filterable data grid with server-side pagination, inline status editing, order grouping, and quick actions for rescheduling. --- ## Bookings data grid The grid displays one row per booking. When a customer places a multi-item order, those items are grouped under a collapsible parent row showing the order ID and total item count. Click the expand arrow to reveal individual line items within the order. ### Columns | Column | Description | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Booking ID** | Unique identifier. Clicking it navigates to the booking detail page. Multi-item orders display a cart icon and an item count chip. | | **Inventory Name** | The asset type name, or the assigned asset nickname if an asset has been assigned | | **Quantity** | Number of units reserved | | **Assignment** | Staff member assigned to this booking | | **Price** | Total price for the booking | | **Outstanding** | Remaining balance owed. Shows `$0.00` in green when fully paid, or the amount in red. A green checkmark appears if an auto-charge is scheduled; a warning icon appears if auto-charge has failed. | | **First Name** | Customer first name (sortable) | | **Last Name** | Customer last name (sortable) | | **Phone Number** | Customer phone number | | **Start Date** | Reservation start date and time, formatted for the location's timezone and date format | | **Booking Date** | When the reservation was originally placed | | **Status** | Current pipeline stage, displayed as a clickable colored chip | Additional columns are available through the column visibility menu: | Column | Description | | -------------- | --------------------------------------------------------------------------------------------------------------------------------------- | | **Email** | Customer email address | | **End Date** | Reservation end date and time | | **Subtotal** | Pre-tax subtotal | | **Tax** | Tax amount | | **Deposit** | Deposit amount collected | | **Fees** | Total fee amount | | **Discount** | Total discount applied | | **Promo Code** | Gift card or promo code used | | **Affiliate** | Affiliate source for the booking | | **Type** | Booking type (hourly, daily, multi-day, etc.) | | **Documents** | Upload status chip for required documents (insurance, ownership proof). Shows a fraction like `1/2` with color indicating completeness. | --- ## Searching and filtering ### Quick search Use the search bar at the top of the grid to filter across all visible fields. Results update as you type. ### Advanced filters Click the filter bar to add structured filters. Each filter consists of a field, operator, and value. Available filters: | Filter | What you can search by | | ------------------- | ------------------------------------- | | **First Name** | Customer first name | | **Last Name** | Customer last name | | **Booking ID** | Exact or partial booking ID | | **Inventory Name** | Asset type or name | | **Price** | Total price with comparison operators | | **Quantity** | Number of units | | **Phone Number** | Customer phone | | **Email** | Customer email | | **Start Date** | Reservation date range | | **Booking Date** | Date the booking was placed | | **Promo Code** | Gift card or promo code | | **Affiliate** | Affiliate source | | **Discount Amount** | Discount value | | **Booking Type** | Type (hourly, daily, etc.) | Multiple filters can be combined and are applied server-side for accurate results across all data. ### Status quick filter A row of colored status chips appears above the grid. Click any chip to instantly filter the grid to that pipeline stage -- for example, **Booked**, **Check In**, **On Lake**, **Returned**, **Complete**, **Cancelled**, or **No Show**. Click the chip again to clear the filter. --- ## Saved views Save your current combination of filters and column visibility as a named view for quick access. 1. Set up the filters and column arrangement you want. 2. Open the **Saved Views** dropdown. 3. Click **Save Current View** and enter a name. 4. To restore a saved view later, select it from the dropdown. 5. To remove a saved view, click the delete icon next to its name. Saved views are stored on your user profile and persist across sessions and devices. --- ## Changing booking status Click any status chip in the grid to open a dropdown of all available pipeline stages. Select a new status to update the booking immediately. If the booking belongs to a multi-item order and you update the parent row, all items in the order are updated together via a batch status change. The pipeline stages are configurable per location. If your location uses a custom pipeline, the dropdown reflects your custom stage names and colors. The default pipeline stages are: | Stage | Description | | ----------------------- | -------------------------------------- | | **Booked** | Reservation confirmed | | **Check In** | Customer has arrived | | **Rundown Ready** | Boat rundown can begin | | **Rundown In Progress** | Staff is conducting the safety rundown | | **On Lake** | Customer is actively on the water | | **Returned** | Equipment has been returned | | **Check Out** | Final checkout processing | Terminal statuses (**Complete**, **No Show**, **Cancelled**, **Preauth Held**) appear at the bottom of the dropdown. {% callout type="warning" %} If a stage has unmet requirements (such as waiver not signed or deposit not collected), a confirmation dialog appears listing the missing items. You can override and proceed or cancel the status change. {% /callout %} --- ## Order grouping Bookings that belong to the same order are automatically grouped. The parent row shows: - A cart icon and item count chip (e.g., "3 items") - The order ID (click to navigate to the order detail page) - Combined pricing from the order - The order-level status Click the expand arrow on the parent row to see each individual booking line item indented beneath it. Child rows display in a subdued style with their own inventory name, status, and pricing. --- ## Date navigation Use the controls in the header to navigate through dates: - **Left / Right arrows** to move one day forward or back - **Today** button to jump to the current date - **Date picker** icon to jump to any specific date --- ## Quick reschedule Use the context menu on a booking row to open the **Quick Reschedule** dialog. This lets you change the start date and time without opening the full booking detail page. The customer can be notified automatically of the change. --- ## Pagination The grid uses server-side pagination. Navigate between pages using the controls at the bottom. As you move to later pages, additional data is fetched automatically. Adjust the page size to show more or fewer rows per page. --- ## Creating a new booking Click the **New Booking** button (plus icon) in the page header. This navigates to the booking page where you can create a reservation. {% callout type="tip" %} The bookings grid respects the location selector in the sidebar. Switch to **All Locations** to see bookings across every location, or pick a specific location to narrow results. Column visibility settings are also saved per user. {% /callout %} --- # Calendar Source: https://docs.rentaltide.com/core/calendar/ > Visual resource calendar for bookings and tours with drag-and-drop rescheduling and quick booking The Calendar page provides a visual timeline of every booking across your fleet. Each inventory type is displayed as a swim lane with its assets as sub-lanes, so you can see exactly which asset is booked and when. Create new bookings by clicking empty slots, drag existing bookings to reschedule, and switch between rental and tour views. --- ## View modes Toggle between three view modes using the buttons in the calendar toolbar: | View | Description | | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Day** | Multi-day horizontal timeline starting from the selected date. Shows a configurable number of days (starting at 3) with horizontal scrolling. Each hour is a column. | | **Week** | Single-day view showing the selected date's full hourly breakdown. Each inventory type is a row, with sub-rows for individual assets. | | **Month** | High-level monthly grid showing booking counts per day per inventory item. | ### Day view zoom In day view, use the **zoom in** and **zoom out** buttons to adjust the column width. This is helpful when you have many bookings packed into a short window, or when you want to see more days at once. --- ## Rentals vs. tours The calendar supports two modes, selectable via the toggle in the toolbar: - **Rentals** -- Shows standard rental bookings on the resource timeline. - **Tours** -- Switches to the tour calendar view, showing tour sessions and their capacity. Tour sessions display departure times, capacity fill, and booking counts. --- ## Navigating dates | Control | Action | | ---------------- | ----------------------------------------- | | **Left arrow** | Move back one day | | **Right arrow** | Move forward one day | | **Today** button | Jump to the current date | | **Date picker** | Open a calendar popup to jump to any date | The calendar automatically centers on the location's configured core hours (e.g., 8:00 AM to 8:00 PM). When **All Locations** is selected, it uses the earliest start time and latest end time across all your locations. --- ## Reading the calendar Each swim lane represents one inventory type (e.g., "Pontoon Boat"). If that inventory type has multiple physical assets, each asset appears as a sub-lane within the swim lane. Booking blocks show: - Customer name - Booking time span - Status color coding Hover over any booking block to see a quick summary tooltip with customer details, pricing, and status. --- ## Creating a booking from the calendar 1. Click an empty time slot on any asset lane. 2. A booking form dialog opens with the inventory, date, and time pre-populated. 3. Search for an existing customer or enter new customer details. 4. Review the price breakdown (calculated server-side). 5. Choose a payment method and confirm. ### Quick Book The calendar also offers a **Quick Book** option for fast reservations. Quick Book creates a booking and generates a payment link that can be sent to the customer via email, SMS, or both. The customer completes payment through the link. {% callout type="tip" %} Quick Book is ideal for phone reservations where you want to confirm the slot immediately and let the customer pay on their own time. {% /callout %} --- ## Rescheduling with drag and drop Drag any booking block to a different time slot or asset lane. When you release, a confirmation dialog appears showing the old and new times. Confirm to save the change. The calendar checks for overbooking conflicts when you drag. Each booking has a layover buffer (configurable per inventory type, defaulting to 30 minutes) that prevents bookings from being placed too close together on the same asset. {% callout type="warning" %} If a drag would create a conflict with an existing booking on the same asset (accounting for layover time), the calendar warns you before saving. You can force the overbooking if needed. {% /callout %} --- ## Filtering Use the filter controls in the toolbar to narrow what the calendar displays: | Filter | Description | | -------------------- | -------------------------------------------------------------------- | | **Inventory** | Show only specific inventory types. Select "ALL" to show everything. | | **Search** | Text search to find bookings by customer name or booking ID | | **Seating capacity** | Slider to filter by minimum seating capacity | | **Staff** | Filter bookings by assigned staff member | --- ## Time format The calendar respects the time format setting from your location configuration. It supports both 12-hour (AM/PM) and 24-hour formats. The format automatically updates when you switch locations. --- ## Ghost bookings When navigating to the calendar from a booking detail page (via URL parameter), a "ghost" outline of that booking appears on the calendar to help you locate it visually. The calendar auto-scrolls to the correct date. --- ## Timezone handling All times on the calendar are displayed in the selected location's timezone. When switching between locations in different timezones, the calendar adjusts automatically. The timezone is derived from the location's settings and applied globally during your calendar session. {% callout type="tip" %} The calendar works well on tablets for dock-side operations. On mobile devices, the view automatically switches to day view for the best experience on smaller screens. {% /callout %} --- # Customers Source: https://docs.rentaltide.com/core/customers/ > Searchable customer database with booking history, financial accounts, license scanning, and customer management The Customers page is a searchable, paginated database of every renter who has interacted with your business. View a customer's full rental history, manage their contact information, track their financial standing, and access documents like signed waivers -- all from a single profile. --- ## Customer table The main view displays all customers in a sortable table with server-side pagination and search. ### Columns | Column | Description | | ---------------- | ----------------------------------------------------------------------------- | | **Avatar** | Initials-based avatar with a color based on status | | **Name** | Full name (first and last), clickable to open the customer profile | | **Email** | Email address | | **Phone** | Phone number | | **Status** | Current customer status displayed as a colored indicator | | **Total Spend** | Lifetime revenue from this customer | | **Bookings** | Total number of bookings | | **Last Booking** | Date of the most recent reservation | | **Risk Score** | Computed risk score (color-coded: green under 30, yellow 30-70, red above 70) | | **Balance** | Outstanding account balance from the ledger (debit and credit) | | **Actions** | Menu with View, Delete, and other options | ### Search Type in the search bar to find customers by name, email, phone number, or any text field. Search is debounced (waits for you to stop typing before querying) and runs server-side, so it works across all customers regardless of pagination. ### Status filter Use the status dropdown to filter the table by customer standing: | Status | Description | | ----------- | -------------------------------------------- | | **All** | Show all customers | | **New** | Recently added, no completed bookings yet | | **Good** | Customer in good standing | | **VIP** | High-value or frequent customer | | **Warning** | Flagged for attention (e.g., past incidents) | | **Owing** | Has an outstanding balance | | **Banned** | Blocked from making new bookings | ### Sorting Click any column header to sort ascending or descending. The sort is applied server-side for accurate ordering across all pages. ### Pagination Navigate between pages using the pagination controls at the bottom. The table displays 20 customers per page. The total customer count and filtered count are displayed above the table. --- ## Adding a customer 1. Click the **Add Customer** button (person-plus icon) in the page header. 2. Choose an account creation mode: - **Basic** -- Enter first name, last name, email, and phone number only - **Full** -- Enter all details including address, date of birth, ID type, ID number, and expiry date 3. Fill in the required fields and click **Add Renter**. ### License scanning In Full mode, you can use the built-in license scanner to capture a driver's license via your device camera. The scan auto-populates the customer's name, address, date of birth, ID number, and expiry date, saving significant time during check-in. --- ## Customer profile Click any customer row to open their full profile page. The profile is organized into sections: ### Contact information Displays and allows editing of: - First name, last name, email, phone number, address, and date of birth - Profile photo (can be uploaded) - Customer status (changeable via dropdown) - Customer group assignment (Gas, VIP, Staff, Military, Seniors, or No Group) ### Financial overview | Field | Description | | ----------------------- | ----------------------------------------------------------------------- | | **Total Spend** | Lifetime revenue from this customer | | **Outstanding Balance** | Current amount owed, clickable to view the full ledger breakdown | | **Store Credit** | Toggle to enable/disable store credit, with an adjustable credit amount | | **First Booked** | Date of the customer's first reservation | ### Booking history Paginated list of all reservations associated with this customer, including rental date, inventory name, status, and total amount. Each booking links to its detail page. ### POS purchases Separate paginated list of point-of-sale transactions (retail, food, etc.) that are not rental bookings. ### Notes Add internal notes to a customer's profile. Notes are visible only to staff and include timestamps. Notes are paginated with 5 per page. You can also upload files (photos, documents) that are attached as notes with clickable links. ### Waivers View all signed waivers for this customer, with pagination. Each waiver entry shows the signing date and can be opened for review. ### ID verification View the customer's ID verification status, including license scans and face comparison results if configured. ### Memberships If the customer has an active membership, their membership details and loyalty badge are displayed. ### Slip reservations For marina operations, shows any active slip reservations associated with this customer. ### Dependants View and manage dependants linked to this customer account. ### Saved payment methods View the customer's saved payment methods on file (stored in Stripe). --- ## Customer status management From the customer profile, you can change their status using the status dropdown: | Status | Color | Effect | | ----------- | -------- | ------------------------------------------------------------------------ | | **Good** | Green | Standard customer in good standing | | **VIP** | Purple | High-value customer; may receive special pricing via customer groups | | **Warning** | Orange | Flagged for staff attention | | **Owing** | Red | Has outstanding balance | | **Banned** | Dark red | Blocked from booking. A ban confirmation dialog appears before applying. | --- ## Exporting customers Click the **Export** button in the table header to download customer data. Choose between: - **CSV** -- Spreadsheet-compatible format - **JSON** -- Structured data format The export respects your current search and filter settings, so you can export a targeted subset of customers. The downloaded file is timestamped and includes any active filter in the filename. {% callout type="tip" %} The customer table includes financial accounting data by default, showing each customer's debit, credit, and net balance. Use the status filter to quickly find customers who owe money by selecting **Owing**. {% /callout %} --- ## Duplicate management A separate **Duplicate Manager** page is available for identifying and merging duplicate customer records. Duplicates are typically caused by customers booking with different email addresses. Merging combines all booking history, notes, and financial data into a single profile. {% callout type="warning" %} Deleting a customer is permanent. Customers with existing booking history should be set to **Banned** status rather than deleted, to preserve their rental records and financial history. {% /callout %} --- # Dashboard Source: https://docs.rentaltide.com/core/dashboard/ > Your personalized home screen with key business metrics, charts, and operational alerts at a glance The dashboard is the first screen you see after logging in. It displays real-time business metrics, revenue trends, booking activity, and operational alerts -- all organized into a customizable, drag-and-drop widget grid. Each staff member maintains their own layout, so changes you make will not affect other users. --- ## Dashboard header The header greets you by name and provides quick-action buttons: | Button | What it does | | --------------------------- | ------------------------------------------------------------------------------------------------------------- | | **New Booking** | Opens the booking page to create a new reservation | | **Manage Fleet** | Navigates to the inventory page | | **Theme** (paintbrush icon) | Opens the theme customization popover where you can change colors, fonts, border radius, and toggle dark mode | --- ## Available widgets The dashboard is built from modular widgets. Each widget can be toggled on or off and repositioned by dragging. ### Booking and operations widgets | Widget | Description | | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- | | **Revenue Stats** | 7-day revenue total with a gradient area chart showing daily revenue trends | | **Tickets Stats** | 7-day booking count with an animated bar chart showing daily ticket volume | | **Inventory Stats** | Count of active inventory types with a horizontal bar chart of usage | | **Recent Bookings** | Table of the six most recently booked reservations, showing customer name, asset, date booked, rental date, total price, and status | | **Certification Alerts** | Lists staff certifications that are expiring or have already expired | | **Pricing Season Gaps** | Flags inventory items that have no pricing season configured for the next three months | | **Terminal Orders** | Shows recent Stripe Terminal (in-person) transactions | ### Analytics widgets | Widget | Description | | -------------------------- | ------------------------------------------------------------------------------------------------------ | | **Year-over-Year Revenue** | Compares current year revenue against the previous year on a chart | | **Revenue Correlation** | Dual-axis chart plotting daily revenue against booking count, with the calculated average ticket value | | **Booking Activity** | GitHub-style heatmap showing booking volume over time | | **Demand Forecast** | AI-predicted daily renter volume for the next five days | | **Top Inventory** | Ranked list of your most-booked asset types over the past seven days | | **Daily Briefing** | AI-generated operations summary for today covering bookings, weather, and staffing | | **Maintenance Alerts** | AI-predicted maintenance needs for your fleet | ### Financial / Ledger widgets | Widget | Description | | ----------------------- | ---------------------------------------------------------- | | **Cash Flow Trends** | Chart of cash inflows and outflows over recent periods | | **Account Breakdown** | Pie chart breaking down revenue by GL account category | | **Recent Transactions** | List of the latest ledger transactions across all accounts | ### Messaging widget | Widget | Description | | ------------------- | -------------------------------------------------------------------------------------------------------- | | **Unread Messages** | Shows up to five conversations with unread customer messages, with quick links to open each conversation | --- ## Customizing your layout 1. Click the **gear icon** in the dashboard header to open the widget management panel. 2. Toggle individual widgets on or off using their switches. 3. Drag any widget card by its header to reposition it within the grid. 4. Resize widgets by dragging the bottom-right corner handle. 5. Click **Reset to Defaults** to restore the original layout. Your layout preferences are saved to your user profile automatically. If the RentalTide team releases a layout update, your grid will reset once to include new default widgets. {% callout type="tip" %} The dashboard auto-refreshes booking data to keep metrics current. Revenue and ticket charts cover a rolling 7-day window ending today. {% /callout %} --- ## Location filtering The dashboard respects your location selector in the sidebar. When a specific location is selected, all widgets show data scoped to that location. When **All Locations** is selected, widgets aggregate data across every location. --- ## Banners and onboarding The dashboard may show contextual banners depending on your account state: | Banner | When it appears | | -------------------- | --------------------------------------------------------------------------------- | | **Connect Account** | One or more locations are missing a Stripe Connect account for payment processing | | **Settings Wizard** | A new location has not completed initial setup | | **Inventory Wizard** | The selected location has zero inventory configured | | **Welcome Tour** | First-time users are guided through the main features of RentalTide | Banners can be dismissed individually and will not reappear once closed. --- ## Kiosk mode When a non-manager staff member is logged in through kiosk mode, the dashboard is restricted to only the **Recent Bookings** table and **Unread Messages** widgets. This keeps the view focused on day-to-day operations without exposing sensitive financial data. --- ## Permissions Widget visibility is governed by your user role and the **dashboardWidgetPermissions** setting configured by your admin. Admin and SuperAdmin users can see all widgets regardless of permission settings. Standard staff may only see widgets their admin has enabled for them. --- # Messages Source: https://docs.rentaltide.com/core/messages/ > Unified two-pane inbox for all customer conversations across bookings and slip reservations The Messages page is a unified inbox for all customer communication. Every conversation tied to a booking or slip reservation lives in one place, organized as a two-pane layout with conversation threads on the left and the active conversation on the right. --- ## Layout The page uses a split-pane design: - **Left pane** -- Scrollable list of all conversations, sorted by most recent message. Each entry shows the customer name, inventory or order name, last message preview, timestamp, and an unread badge. - **Right pane** -- Full message thread for the selected conversation. Messages appear in chronological order with clear visual distinction between staff messages and customer messages. On mobile devices, the layout stacks vertically. Tap a conversation to view it, and use the back arrow to return to the conversation list. --- ## Conversation list Each conversation entry displays: | Field | Description | | -------------------------- | ------------------------------------------------------------------------------ | | **Avatar** | Color-coded customer initial | | **Customer name** | Full name of the renter | | **Inventory / Order name** | The asset name for single bookings, or "Order (N items)" for multi-item orders | | **Last message** | Preview text of the most recent message | | **Timestamp** | Relative time (e.g., "2 hours ago") for the last message | | **Unread badge** | Count of unread customer messages | | **Status chip** | Current booking status | ### Searching conversations Use the search bar at the top of the conversation list to filter by customer name, inventory name, or message content. Results update as you type. --- ## Order-level conversations When a customer places a multi-item order, all messages from every line item in that order are merged into a single conversation. This prevents the same customer from appearing as 15 separate threads when they booked 15 items in one order. The conversation shows "Order (N items)" as the inventory name and aggregates all messages with deduplication. --- ## Slip reservation messages Messages from slip reservations (marina slip tenants) appear alongside booking conversations. They are visually distinguished by a boat icon next to the slip name. Sending messages to slip reservations uses a separate endpoint, but the interface is identical. --- ## Reading messages Click any conversation to view the full message thread. Messages display: | Element | Description | | ------------------ | ----------------------------------------------------------- | | **Sender** | "You" for staff messages, customer name for renter messages | | **Timestamp** | Date and time the message was sent | | **Message body** | Full text of the message | | **Read indicator** | Checkmark showing the message has been read | Messages from customers appear on the left side. Messages from staff appear on the right side with a different background color. --- ## Sending a message 1. Select a conversation from the left pane. 2. Type your message in the compose area at the bottom of the right pane. 3. Press **Enter** or click the **Send** button. Messages are sent immediately. The conversation list re-sorts to move the active conversation to the top. The customer receives the message via the same channel they originally used (email notification tied to their booking). {% callout type="tip" %} Messages you send from the booking detail page also appear in this inbox, so you always have a complete conversation history in one place. {% /callout %} --- ## Unread tracking When you open a conversation, all unread messages from the customer are automatically marked as read. The unread badge on the conversation entry clears, and the backend is updated so the read state persists across devices. The unread count also feeds into the **Unread Messages** widget on the dashboard, so you can see at a glance how many conversations need attention. --- ## Auto-refresh The messages page polls for new messages every 10 seconds and also refreshes when you switch back to the browser tab. This ensures you see new customer messages promptly without needing to manually refresh. --- ## Navigating to booking details From any conversation, you can navigate directly to the associated booking detail page by clicking the booking reference. This is useful when a customer message requires you to check pricing, reschedule, or process a payment. {% callout type="warning" %} Messages cannot be deleted from the customer-facing thread. All sent messages are permanent and visible to both staff and the customer. Internal notes should be added to the booking detail page rather than sent as messages. {% /callout %} --- # Support channel Source: https://docs.rentaltide.com/core/support-channel/ > Real-time internal team messaging with threads, reactions, file sharing, search, and video huddles The Support Channel is a real-time, Slack-style messaging space for your internal team. Each location gets its own dedicated channel where staff can coordinate operations, share updates, and jump on video calls -- all without leaving RentalTide. --- ## Getting started Each location has its own support channel. When you navigate to the Support Channel page, it automatically loads the channel for your currently selected location. - If no channel exists yet for a location, one is created automatically the first time you visit. - If automatic creation does not succeed, click the **Create Channel** button to set it up manually. - When **All Locations** is selected in the sidebar, the page prompts you to select a specific location, since each channel is location-scoped. --- ## Channel header The header bar at the top of the channel displays: | Element | Description | | -------------------- | -------------------------------------------------------------------------------- | | **Channel name** | The name of the channel (prefixed with #), typically matching your location name | | **Online indicator** | Shows how many team members are currently online in this channel | | **Search** | Opens a search overlay to find messages by keyword | | **Saved messages** | Opens the saved messages panel to view bookmarked messages | | **Huddle** | Start or join a live video huddle | | **Slack link** | Connect or disconnect a Slack channel for cross-platform messaging (admin only) | --- ## Sending messages Type your message in the composer at the bottom of the channel and press **Enter** to send. Messages appear instantly for all staff members connected to the channel via WebSocket. The message composer supports: | Feature | Description | | -------------------- | ------------------------------------------------------------------------ | | **Text messages** | Standard text messages sent in real time | | **File attachments** | Click the attachment icon to upload images, PDFs, and other documents | | **Typing indicator** | Other users see a "typing..." indicator when you are composing a message | --- ## Message list Messages appear in chronological order with automatic date separators between different days. Each message displays: | Element | Description | | -------------------- | --------------------------------------------- | | **Author name** | Name of the staff member who sent the message | | **Author avatar** | Profile picture or initials | | **Timestamp** | Time the message was sent | | **Message body** | Full text content | | **Reactions** | Emoji reactions added by team members | | **Thread indicator** | Shows reply count if the message has a thread | Older messages are loaded automatically as you scroll up (infinite scroll with pagination). --- ## Threads Threads keep focused conversations organized without cluttering the main channel timeline. 1. Hover over any message to reveal the action bar. 2. Click the **thread** icon to open the thread panel on the right side. 3. Reply within the thread. Thread replies do not appear in the main channel view. 4. The original message shows a reply count indicator so others can see there is an active thread. On mobile, the thread panel replaces the main message view. Use the back button to return to the channel. --- ## Emoji reactions Add quick reactions to any message without adding to the message stream. 1. Hover over a message to reveal the action bar. 2. Click the **emoji** icon to open the emoji picker. 3. Select an emoji to add your reaction. 4. Click an existing reaction to toggle it on or off. Multiple users can react with the same emoji, and the count is displayed next to the reaction. --- ## Message actions Hovering over a message reveals additional actions: | Action | Description | | ------------------- | --------------------------------------------------------------------------- | | **Reply in thread** | Open a thread for focused discussion | | **React** | Add an emoji reaction | | **Save** | Bookmark the message for later reference | | **Delete** | Remove the message (available for your own messages or if you are an admin) | --- ## Search Click the **search icon** in the channel header to open the search overlay. Type keywords to search through all messages in the current channel. Click a search result to jump to that message in the timeline. If the result is within a thread, the thread panel opens automatically. --- ## Saved messages Click the **bookmark icon** in the channel header to open the Saved Messages panel. This shows all messages you have bookmarked for quick reference. Saved messages persist across sessions. --- ## Video huddles Huddles are lightweight video calls that any channel member can start or join. 1. Click the **headphones icon** in the channel header to start a huddle. 2. Other staff members see a notification and can click **Join** to enter the call. 3. During a huddle, you have controls for: | Control | Description | | ------------------- | ----------------------------------------- | | **Mute / Unmute** | Toggle your microphone | | **Camera On / Off** | Toggle your video feed | | **Screen Share** | Share your screen with other participants | | **Leave** | Exit the huddle | The huddle bar appears at the bottom of the message area when a huddle is active, showing participant tiles and control buttons. {% callout type="tip" %} Huddles are ideal for quick coordination -- like discussing a customer situation or walking through a process with a remote team member. They require no scheduling and start instantly. {% /callout %} --- ## Slack integration Admins can link a RentalTide support channel to an external Slack channel for cross-platform messaging. 1. Click the **Slack icon** in the channel header. 2. Enter the Slack channel ID you want to link. 3. Click **Link Channel**. 4. Messages posted in either RentalTide or Slack will appear in both places. To unlink, click the Slack icon again and select **Unlink Channel**. {% callout type="warning" %} Slack integration requires your Slack workspace to have the RentalTide app installed. Contact your administrator if the link fails. {% /callout %} --- ## Real-time updates The support channel uses WebSocket connections for real-time message delivery. Messages, reactions, typing indicators, and huddle status all update instantly without polling. If the connection drops (e.g., due to a network issue), the channel reconnects automatically. --- ## Permissions All staff members at a location can view and send messages in that location's channel. Message deletion is restricted to the message author or admin/owner users. Slack linking and unlinking is available only to admin and owner roles. {% callout type="tip" %} Support channel conversations are entirely internal. Customers never see these messages. Use the **Messages** page for customer-facing communication instead. {% /callout %} --- # Fleet & business Source: https://docs.rentaltide.com/fleet/ > Manage your inventory, availability, waivers, memberships, and bundles The fleet and business section is where you build and maintain everything customers can book. Create inventory items, control when they are available, collect digital waivers, offer membership tiers, and package items into discounted bundles. {% cardGroup cols=3 %} {% card title="Inventory" href="/fleet/inventory/" /%} {% card title="Availability" href="/fleet/availability/" /%} {% card title="Waivers" href="/fleet/waivers/" /%} {% card title="Memberships" href="/fleet/memberships/" /%} {% card title="Bundles" href="/fleet/bundles/" /%} {% /cardGroup %} --- # Availability Source: https://docs.rentaltide.com/fleet/availability/ > Override default schedules with date-specific blocks, capacity limits, and bulk changes The availability overrides page gives you fine-grained control over when and how many units of each inventory item can be booked. A two-dimensional grid shows inventory items on rows and dates on columns, with color-coded cells indicating override status at a glance. --- ## Reading the grid The grid displays a scrollable date range (14 days on desktop, 5 on mobile) with each inventory item as a row. Navigate forward and backward using the arrow buttons, or jump to today. | Cell indicator | Meaning | | -------------- | ------------------------------------------------------------------------------------- | | Red chip | Fully blocked -- zero units available for that date | | Orange chip | Partially restricted -- fewer units available than total capacity | | Blue chip | Custom availability -- modified but not fully restricted | | No indicator | Default schedule applies -- all units available per the item's standard configuration | Each cell chip shows the number of available units (e.g., "0" for a full block, "2" for a partial restriction). Clicking a cell opens the override dialog pre-filled with that item and date. --- ## Creating an override 1. Click any cell on the grid, or click the **+ New Override** button. 2. Select the **inventory item** from the dropdown (pre-filled if you clicked a cell). 3. Optionally select an **asset type** to restrict only units of a specific type (e.g., "Premium" jet skis). 4. Enter a **name** for the override (e.g., "Maintenance Window", "Private Event"). 5. Set **max available** -- the maximum number of units that can be booked during this period. Set to 0 for a full block. 6. Choose the **start date** and **end date** for the override. 7. Toggle **active** on or off. 8. Toggle **call to book** if customers should be able to request a booking by phone even though online booking is blocked. 9. Add optional **notes** visible to staff. 10. Click **Save**. ### Override fields | Field | Description | | --------------------- | -------------------------------------------------------------------------------- | | Inventory item | Which fleet item this override applies to | | Asset type | Optionally restrict only a specific asset type within the item | | Name | Internal label for the override (e.g., "Holiday Block", "Fleet Maintenance") | | Max available | Maximum bookable units during the override period. Set to 0 for a complete block | | Start date / End date | Date range the override applies to (inclusive) | | Active | Whether the override is currently enforced | | Call to book | Allow phone-based booking even when online booking is blocked | | Notes | Internal notes visible to staff only | --- ## Editing and deleting overrides Click an existing override cell to open it for editing. All fields can be modified. To delete an override, click the delete button and confirm the action. --- ## Priority rules When multiple settings overlap, the system resolves conflicts as follows: 1. **Active overrides take priority** over inactive overrides on the same date. 2. Among active overrides on the same date and item, the **most restrictive** (lowest max available) wins. 3. **Date-specific overrides** always take priority over the item's default schedule. 4. If an item has both a block (max available = 0) and a partial restriction on the same date, the block wins. --- ## Bulk overrides To apply the same override across multiple dates: 1. Click **+ New Override**. 2. Set a broad **start date** and **end date** range. 3. The override applies to every date within that range for the selected inventory item. This is useful for blocking an entire week for maintenance, reducing capacity across your fleet for a slow season, or opening extended availability for a holiday weekend. --- ## Call to book When an override has **call to book** enabled, the booking widget shows the item as "Call to Book" rather than fully blocked. Customers see a phone number and are directed to call your team to arrange the booking manually. This is useful for high-value bookings, group events, or dates that need manual coordination. {% callout type="tip" %} Plan ahead for holidays, maintenance windows, and special events by setting overrides months in advance. Overrides are reflected on the booking widget in real time, so customers always see accurate availability. Use the date range feature to apply blocks across your entire fleet for seasonal closures. Asset type filtering lets you take specific unit types out of rotation while keeping others available. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Customers booking when they should not be** -- Verify that the override is set on the correct inventory item and date range. Check that the override is marked as **active**. Also confirm that no other override with a higher max available exists for the same date. **Override not applying** -- Confirm the date range is correct and that the override is active. Check whether the location-level operating hours are also restricting availability. **Cannot see all items** -- The grid loads all published inventory for the selected location. Switch locations using the location selector in the header. If an item is missing, verify it is published and assigned to the current location. **Partial restriction showing wrong count** -- The max available count on the override must be less than the item's total capacity to have an effect. If max available is equal to or greater than total capacity, the override has no practical impact. {% /callout %} --- # Bundles Source: https://docs.rentaltide.com/fleet/bundles/ > Package multiple inventory items, gift cards, or memberships into discounted bundles Bundles let you group multiple items into a single bookable package with a built-in discount. Create themed offerings like a "Family Fun Package" or "Sunset Adventure" that include inventory items, gift cards, or membership tiers at a better price than purchasing each one individually. --- ## Creating a bundle 1. Navigate to **Marketing > Bundles** and click **+ New Bundle**. 2. Enter a **name** and **description** for the package. 3. Choose a **discount type** (see table below). 4. Set the **discount value** (percentage or fixed price amount). 5. **Add items** -- select inventory items, gift cards, or membership tiers to include. 6. Configure each item's quantity and optional per-item settings. 7. Optionally set availability constraints (start/end dates, max redemptions, location). 8. Toggle the bundle **active** or inactive. 9. Save the bundle. --- ## Item types Bundles can contain three types of items: | Item type | Description | | ---------- | ------------------------------------------ | | Inventory | A bookable rental item from your fleet | | Gift card | A prepaid gift card with a specified value | | Membership | A membership tier enrollment | Each item in the bundle has a **quantity** and can optionally be marked as a **free item** (included at no charge) or given a **per-item discount percentage** when using the per-item discount model. --- ## Discount types | Discount type | How it works | | -------------- | ------------------------------------------------------------------------------------------------------------- | | Percentage off | Reduces the combined price of all items by a percentage (e.g., 15% off the total) | | Fixed price | Sets a flat price for the entire bundle regardless of individual item rates | | Free item | One or more items in the bundle are marked as free -- the customer pays for the remaining items at full price | --- ## Bundle settings | Field | Description | | --------------- | ---------------------------------------------------------------------- | | Name | Display name shown to customers on the booking widget | | Description | Short description explaining what the bundle includes | | Discount type | How the discount is calculated (percentage, fixed price, or free item) | | Discount value | The percentage or dollar amount of the discount | | Location | Optionally restrict the bundle to a specific location | | Active | Whether the bundle is currently available for purchase | | Start date | Optional date when the bundle becomes available | | End date | Optional date when the bundle expires | | Max redemptions | Optional cap on how many times the bundle can be purchased | --- ## Customer experience 1. The customer visits the booking widget and sees the bundle as a bookable option alongside individual items. 2. They select the bundle and choose their date and time. 3. All items in the bundle are added to the cart with the discount applied automatically. 4. The customer completes checkout as a single transaction. Behind the scenes, each item in the bundle creates its own booking record linked by a shared **bundle group ID**. This means each asset is tracked individually on the operations boards (manifest, journey board, nav board) while the customer sees one unified order. --- ## Redemption tracking Each bundle card on the management page shows: - **Redemption count** -- how many times the bundle has been purchased - **Status** -- active, inactive, or expired (based on dates and max redemptions) - **Discount summary** -- the type and value of the applied discount - **Items included** -- list of inventory items, gift cards, and memberships in the bundle {% callout type="tip" %} Bundles work well for family packages, adventure combos, and corporate group bookings. Individual items within a bundle are managed separately on the manifest and journey board, so your operations team tracks each asset independently. Use the start/end date fields to create limited-time promotional bundles. The max redemptions cap creates scarcity for special offers. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Bundle not showing on the booking widget** -- All inventory items in the bundle must be available on the selected date. If any single item is blocked or sold out, the entire bundle is unavailable for that date. Also verify the bundle is marked as active and the current date falls within any configured start/end date range. **Discount not applying correctly** -- Double-check the discount type and value in the bundle configuration. For percentage discounts, verify the percentage is set on the bundle level, not on individual items (unless using per-item discount mode). **Bundle shows as expired** -- Check whether the end date has passed or the max redemptions cap has been reached. Update the dates or increase the cap to re-activate. {% /callout %} --- # Inventory Source: https://docs.rentaltide.com/fleet/inventory/ > Create and manage your fleet of boats, equipment, and rentable assets Inventory is where you define every asset your customers can book -- jet skis, pontoons, kayaks, paddleboards, or any other equipment. A guided wizard walks you through creating each item across two phases (inventory setup and pricing), and once published, it appears on your booking widget automatically. --- ## Creating an item Click **+ Add Inventory** to open the inventory wizard. The wizard is divided into two phases: inventory setup and pricing configuration. Each phase is broken into categories, and each category contains one or more steps. ### Phase 1: Inventory setup | Category | Steps | What you configure | | ------------------- | --------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Basics | Name & Location, Photos, Description, Booking Type | The item's name, location assignment, category, uploaded images, a rich-text description, and whether it is a **Rental** (customers book a unit for a duration) or a **Tour** (customers book seats on a guided trip) | | Capacity & Assets | Capacity & Quantity, Restrictions & Rules, Asset Tracking | People per unit, total units available, minimum booking quantity, buffer time between bookings, minimum age, staff approval requirement, phone-only booking, and individual asset tracking with serial numbers or unit IDs | | Payments & Deposits | Deposits & Payments, Staff Assignments | Security deposit amount, booking deposit percentage, minimum deposit dollar amount, auto-charge remaining balance days before rental, and required staff skills | | Enhancements | Add-ons, Amenities, Custom Questions, Waiver | Optional extras customers can purchase, highlighted features included with the rental, intake questions collected during checkout, and waiver template selection | | Review | Review & Save | Summary of all settings before saving the inventory item | ### Phase 2: Pricing configuration | Category | Steps | What you configure | | ------------- | ---------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Pricing Model | Pricing Model, Season Details | Choose from Daily, Hourly, Daily + Hourly, Category (per-person), Guest-Count Tiered, or Custom pricing. Set up your default season with name and date range | | Pricing | Opening Schedule, Daily Pricing, Hourly Pricing, Category Pricing, Discounts, Advanced Pricing | Operating hours per day of week, daily rates, hourly rates with time slots, per-person category rates (Adult, Child, Senior), multi-day/multi-hour/quantity discounts, and lead-time pricing rules | | Finalize | Pricing Review & Save | Review the full pricing configuration before saving | {% callout type="tip" %} Steps marked as conditional (Daily Pricing, Hourly Pricing, Category Pricing) only appear when the corresponding pricing model is selected. The wizard automatically skips steps that do not apply to your chosen model. {% /callout %} --- ## Booking types When creating an inventory item, you choose one of two booking types: - **Rental** -- customers book a unit for a duration. Best for boats, kayaks, jet skis, and equipment where each customer gets exclusive use of the asset. - **Tour** -- customers book seats on a guided trip. Best for tours, charters, and excursions where multiple customers share the same departure. Switching between types resets type-specific fields. Tours do not support "Sell By Assets" mode, and rentals do not support private tour settings. --- ## Managing inventory Switch between views depending on your workflow: - **Grid view** -- visual cards with photos, category, capacity, and pricing details at a glance - **List view** -- compact table for scanning many items quickly - **Bulk editor** -- edit multiple items at once using a spreadsheet-style interface for pricing, status, and availability Click any item to open the detail panel, where changes auto-save as you make them. ### Additional management tools | Tool | What it does | | ------------------- | ----------------------------------------------------------------------------------------- | | Bulk Pricing Matrix | Side-by-side pricing comparison and bulk editing across all inventory items | | Dry Dock Manager | Take assets out of service for maintenance, with conflict detection for existing bookings | | Asset Pool Manager | Manage shared asset pools across inventory items | | Pricing Seasons | Create seasonal pricing schedules with date ranges and independent rate tables | | Import from Website | Import inventory details from an existing website using AI-powered extraction | | Reorder | Drag items to change the display order on the booking widget | | Duplicate | Clone an existing item to quickly create similar equipment | --- ## Pricing models RentalTide supports flexible pricing structures that can be combined: | Model | Description | | ------------------ | ------------------------------------------------------------------------------------------------------- | | Daily | Per-day rate with optional multi-day discounts. Different rates for each day of the week | | Hourly | Per-hour rate with fixed time slots. Configure minimum and maximum hours, and multi-hour discount tiers | | Daily + Hourly | Offer both daily and hourly rates simultaneously | | Category | Different prices per person type (Adult, Child, Senior, etc.) | | Guest-Count Tiered | Flat rate tiers based on group size (e.g., 1-4 guests = $200, 5-8 guests = $350) | | Custom | Mix and match any combination of the above pricing modes | ### Pricing seasons Each inventory item supports multiple pricing seasons with independent date ranges and their own rate tables. Seasons can have separate opening schedules, daily rates, hourly rates, and discount structures. When a booking date falls within a season's range, that season's pricing applies automatically. ### Advanced pricing - **Lead-time pricing** -- adjust rates based on how far in advance a customer books - **Schedule exceptions** -- override standard pricing for specific dates (holidays, events) - **Weather rules** -- dynamic pricing adjustments based on weather conditions --- ## Add-ons Add-ons are optional extras that customers can include with their booking. Each add-on has a name, price, and optional configuration: | Setting | Description | | ---------------- | -------------------------------------------- | | Name | Display name shown to customers | | Price | Dollar amount charged | | Required | Automatically included and cannot be removed | | Multiply by time | Price scales with the rental duration | | Per booking | Flat charge regardless of quantity | You can add up to 20 add-ons per inventory item. --- ## Capacity and restrictions | Field | Description | | ------------------------ | -------------------------------------------------------------------- | | People per unit | Maximum number of passengers or riders per unit | | Capacity | Total number of units available for booking | | Minimum booking quantity | Minimum number of tickets a customer must purchase | | Buffer time | Minutes between when one booking ends and the next can begin | | Minimum age | Customers below this age cannot book | | Require staff approval | Bookings require manual staff approval before confirmation | | Phone-only booking | Customers must call to complete a booking (disables online checkout) | --- ## Asset tracking Enable asset tracking to manage individual units with serial numbers or IDs. When enabled: 1. Define **asset types** to categorize units (e.g., "Standard", "Premium", "Electric"). 2. **Generate assets** in bulk by specifying a prefix and count (e.g., "JetSki-1", "JetSki-2", etc.). 3. Individual assets appear on the manifest and can be assigned to specific bookings. --- ## Deposits and payments | Field | Description | | ---------------------------- | --------------------------------------------------------------------------- | | Security deposit ($) | Refundable amount charged for potential damages | | Booking deposit (%) | Percentage of total collected upfront to secure the booking | | Minimum deposit ($) | Floor amount for the booking deposit regardless of percentage | | Auto-charge remaining (days) | Automatically charge the remaining balance this many days before the rental | {% callout type="note" %} **Heads up on platform fees for deposit-plan bookings:** when the customer pays a deposit now and the balance is auto-charged later, the **full booking's platform fee is collected on the deposit charge, not split across both payments**. This is intentional — it guarantees the fee is captured even if the customer eventually pays the balance in cash at the counter. Your deposit payout will look smaller than a simple percentage of the deposit amount would suggest; the balance payout has no platform fee. See [Deposit payment plans](/admin/store-settings#deposit-payment-plans) for a worked example. {% /callout %} {% callout type="tip" %} Use high-quality photos -- they are the first thing customers see. Set buffer time between bookings to allow for cleaning and preparation. Archive items instead of deleting them to preserve booking history. Drag items to reorder how they appear on the booking page. Use the **Duplicate** feature to create a copy of an existing item when adding similar equipment. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Item not appearing on booking widget** -- The item must be published and have available dates configured. Check that the status is set to active and that the schedule includes upcoming dates. **Pricing looks wrong** -- Check whether a promo code, membership discount, or seasonal pricing rule is overriding the base rate. Verify which pricing season is active for the booking date. **Cannot delete an item** -- Items with booking history cannot be deleted. Archive the item instead to remove it from the booking page while preserving records. **Photos not uploading** -- Verify the image format (JPG, PNG, WebP) and file size. Large files may time out on slower connections. **Wizard progress lost** -- The wizard saves your progress at each phase boundary (after "Review & Save"). If you leave mid-step, return to the wizard to resume where you left off. {% /callout %} --- # Memberships Source: https://docs.rentaltide.com/fleet/memberships/ > Create membership tiers with recurring billing, discount rules, credits, and a self-service member portal Memberships let you offer recurring subscription plans to your customers. Define tiers with monthly or annual billing, automatic discounts, booking credits, inventory restrictions, and family plans. Members manage their own subscriptions through a self-service portal, and billing is handled automatically through Stripe. --- ## Page layout The memberships page is organized into two tabs: - **Tiers** -- create and manage membership tier definitions - **Members** -- view and manage all enrolled members across all tiers --- ## Creating a tier Click **+ New Tier** to open the tier form. The form is organized into tabbed sections. ### General settings | Field | Description | | ----------- | ---------------------------------------------------------------------------------------- | | Name | Tier name shown to customers (e.g., "Gold", "Family Plan", "VIP") | | Description | Description displayed on the membership signup page | | Image | Optional hero image for the tier card | | Scope | **All Locations** or **Specific Locations** -- controls where this tier's benefits apply | | Location(s) | When scope is "Specific Locations", select which locations the tier covers | ### Pricing | Field | Description | | ------------- | ------------------------------------------- | | Billing cycle | **Monthly** or **Yearly** recurring billing | | Price | Dollar amount charged per billing cycle | ### Discount rules | Field | Description | | -------------------------- | ------------------------------------------------------------------------------------------ | | Discount type | **Percentage** off booking total or **Fixed Amount** deducted | | Discount value | The percentage or dollar amount of the discount | | Inventory restriction mode | **Only these inventory items** (include list) or **All except these items** (exclude list) | | Inventory items | Select which items the discount applies to or is excluded from | Members receive the discount automatically at checkout when logged into their membership -- no promo code needed. ### Credits | Field | Description | | -------------- | -------------------------------------------------------------------------------------- | | Credit type | **Dollar Credits**, **Free Hours**, or **Free Bookings** | | Credit amount | Number of credits granted per renewal period | | Renewal period | **Monthly** or **Yearly** -- how often credits refresh | | Usage model | **Deduct from total price** or **Free hours** (does not count against rental duration) | | Expiry policy | **Expire at period end**, **Roll over indefinitely**, or **Roll over with cap** | | Rollover cap | Maximum number of credits that can carry forward (when using "Roll over with cap") | ### Family plan | Field | Description | | ----------- | --------------------------------------------------------------------------------------------------- | | Family mode | **Add-on members** (each has own benefits), **Shared credits** (pool credits together), or **Both** | --- ## Managing members The **Members** tab shows a searchable, sortable table of all enrolled members. ### Member table columns | Column | Description | | ------------ | ------------------------------------ | | Member | Name, email, and avatar | | Tier | Which membership tier they belong to | | Status | Current membership status | | Joined | Date the membership started | | Next billing | Date of the next recurring charge | | Actions | Menu with available operations | ### Member actions | Action | Description | | -------------- | ---------------------------------------------------------------------------------------- | | View details | Open the member detail drawer with full profile, credit history, and billing information | | Pause | Temporarily suspend the membership -- billing stops, benefits pause | | Resume | Reactivate a paused membership | | Cancel | End the membership at the current billing period | | Manage billing | Open billing management to update payment method or view payment history | ### Adding a member manually Click **+ Add Member** to enroll a customer directly. Enter the customer's name, email, and select a tier. The system creates the Stripe subscription and sends a welcome notification. --- ## Membership statuses | Status | Description | | --------- | ---------------------------------------------------------------------------- | | Active | Membership is current, billing is up to date, and all benefits are available | | Paused | Temporarily suspended at the member's or admin's request | | Cancelled | Membership has been ended and benefits are no longer available | | Past Due | Payment failed on the most recent billing cycle | --- ## Member portal Members access a self-service portal through a unique URL. After verifying their email with a one-time password (OTP), they can: - View their current tier and benefits - Check remaining credits and booking history - Update their payment method - Pause or cancel their membership --- ## Organizations Memberships support organization-level accounts for corporate or group memberships. Organizations can have multiple members under a single billing entity, with shared or individual credit pools depending on the tier configuration. --- ## Data export Export your member list in **CSV** or **JSON** format from the Members tab. The export includes member name, email, tier, status, join date, and billing information. {% callout type="tip" %} Membership discounts apply automatically on the booking widget when the customer is logged in -- no promo code needed. The "Members Save" badge on the booking page encourages sign-ups by showing the discount amount. Credits refresh on each billing date according to the renewal period. Customers can log into their membership during checkout to apply benefits. Use inventory restrictions to create tier-specific access to premium equipment. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Discount not applying** -- The customer must be logged into their membership account during checkout. The discount does not apply to guest bookings. Also check that the inventory item is not excluded from the tier's discount rules. **Credits not refreshing** -- Credits refresh on the billing date, not the calendar month. Check the member's next billing date in the member detail drawer. **Customer cannot access the portal** -- Share the portal URL with the customer and ensure their email address matches the membership record. The OTP is sent to the email on file. **Payment failed** -- Stripe handles recurring billing. A failed payment moves the membership to "Past Due" status. The customer is notified by email and can update their card through the member portal or the billing management modal. {% /callout %} --- # Waivers Source: https://docs.rentaltide.com/fleet/waivers/ > Build digital waiver templates with drag-and-drop sections, signatures, and multi-language support Waivers let you collect legally binding digital signatures from customers before they arrive. Build custom templates with a drag-and-drop editor, assign them to specific locations or inventory items, and view signed copies with timestamps, signature images, and device information. --- ## Template list The waiver list page shows all templates for the selected location. Each card displays the template title, description, and the location it belongs to. When viewing "All Locations," templates from every location are aggregated and labeled with their respective location names. Available actions on each template card: | Action | Description | | ---------------- | ------------------------------------------------------- | | Edit | Open the template in the waiver builder | | Delete | Permanently remove the template (requires confirmation) | | Copy to Location | Duplicate the template to one or more other locations | --- ## Building a template Click **+ New Template** or **Edit** on an existing template to open the waiver builder. The builder uses a drag-and-drop interface powered by a sortable list. Drag sections to reorder them, click to expand and edit content, or add new sections from the field type palette. ### Field types | Field type | Icon | Description | | -------------- | -------- | ----------------------------------------------------------------------------------------- | | Header | Title | Section heading or title text | | Rich Text | Text | Rich HTML content block for terms, conditions, safety instructions, or any formatted text | | Signature | Draw | Digital signature pad where the signer draws their signature | | Checkbox Group | Checkbox | One or more checkboxes for required or optional agreements | | Radio Group | Radio | Multiple-choice questions where the signer picks one option | | Text Field | Text | Free-form text input (e.g., emergency contact name, medical conditions) | | Date | Calendar | Date picker field | | Number | Numbers | Numeric input field | | Time | Clock | Time picker field | | Dependants | People | Section for listing dependants or minors the signer is responsible for | ### Section properties Each section can be configured with: - **Content** -- the text or HTML displayed to the signer - **Name** -- internal field name for data reference - **Required** -- whether the field must be completed before submission - **Placeholder** -- hint text shown in empty input fields - **Options** -- choices for checkbox groups and radio groups - **Page** -- which page of a multi-page waiver this section belongs to ### Editing workflow 1. Click **Add Section** and choose a field type from the palette. 2. The new section appears at the bottom of the list. Click it to expand. 3. Edit the content using the rich text editor (for Rich Text fields) or configure options. 4. Drag sections to reorder using the drag handle. 5. Use **Duplicate** to clone a section with the same content and settings. 6. Click **Save** to persist all changes. --- ## Multi-language support Templates support multiple languages. The system currently supports: | Language | Code | | ----------------- | ---- | | English | en | | Spanish (Espanol) | es | | French (Francais) | fr | Set a **primary language** on the template, then add translations for the title, description, and each section. The waiver automatically displays in the customer's preferred language when available. --- ## Assigning waivers Waivers can be assigned at two levels: - **Location-level** -- every booking at the location requires the waiver. - **Inventory-level** -- only bookings for specific items require the waiver. Select the waiver template during the inventory wizard's "Waiver" step. When a customer books an item with an assigned waiver, they are prompted to sign during the checkout flow. The waiver can also be signed via: - A **kiosk QR code** on-site that pre-fills customer information from the booking - The **pre-arrival check-in link** sent in the booking confirmation email - The **Next Steps** page accessible from the customer's booking details --- ## Viewing signed waivers Completed waivers are stored with: - Customer name and email - Signature image captured from the signature pad - Timestamp of when the waiver was signed - IP address and device information - The exact template version that was signed Access signed waivers from the booking detail page or from the customer record. --- ## Copying templates across locations Use **Copy to Location** to duplicate a waiver template to one or more locations. The copy operation runs sequentially across selected locations with a progress indicator. Changes to the copy do not affect the original template. {% callout type="tip" %} Keep waiver text concise and focused on the essentials -- long waivers reduce completion rates. Use the preview mode to see exactly what the customer will see before publishing. The dependants field type lets group leaders sign on behalf of minors. Multi-page templates help organize longer waivers into logical sections without overwhelming the signer. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Waiver not appearing during checkout** -- Confirm the waiver is assigned to the correct location or inventory item. Verify the template has been saved (not left in draft state). **Signature not saving** -- The customer must draw a clear mark in the signature field. A blank or nearly blank signature pad will not be accepted. **Template changes were lost** -- Waiver templates must be explicitly saved. Click **Save** after making changes -- navigating away from the builder without saving discards edits. **Rich text formatting looks different** -- The builder uses a rich text editor that produces HTML. Complex formatting from external sources (Word, Google Docs) may not translate perfectly. Paste as plain text and reformat within the editor for best results. **Copy to location failed** -- Ensure you have admin permissions at the target location. The copy operation requires write access to the destination location's waiver templates. {% /callout %} --- # Quick Start Source: https://docs.rentaltide.com/getting-started/ > Get your first RentalTide location up and accepting bookings in four steps # Quick start RentalTide is a full-stack management platform for watercraft rental operators and marinas. It handles bookings, point of sale, fleet tracking, staffing, and financial reporting in one place. Follow these four steps to go from sign-up to accepting your first booking. --- ## 1. Create your account Sign up at [app.rentaltide.com](https://app.rentaltide.com). You will be asked for your name, email, and a password. After verifying your email you will land on the setup wizard. {% callout type="tip" title="Single sign-on" %} RentalTide supports Google and Apple sign-in. You can link these to your account later from the Admin settings page. {% /callout %} --- ## 2. Set up your first location A **location** represents one physical site — a dock, marina, or rental counter. Each location has its own timezone, operating hours, tax rates, and Stripe account. 1. Enter your business name and address. 2. Choose your timezone and set your operating hours for each day of the week. 3. Configure your tax rates and optional fees (fuel surcharge, cleaning fee, etc.). You can add more locations at any time from **Admin > Locations**. {% callout type="note" %} Operating hours control which time slots appear on your public booking page. You can override hours for holidays or special events from the calendar. {% /callout %} --- ## 3. Add your inventory Inventory items are the assets your customers rent — jet skis, pontoons, kayaks, paddleboards, or slip spaces. For each item you will set: - **Name and category** (e.g., "Yamaha EX" in the "Jet Ski" category) - **Pricing** — hourly, half-day, full-day, multi-day, or seasonal rates - **Quantity** — how many units are available for booking - **Photos and description** — shown on the public booking page Head to **Fleet > Inventory** to create your first item. {% callout type="tip" title="Bundles" %} Want to offer a "Sunset Package" that includes a pontoon and a cooler? Create a bundle under **Marketing > Bundles** to group items at a discounted price. {% /callout %} --- ## 4. Accept bookings Once your location and inventory are configured, your public booking page is live. Share the link directly or embed the booking widget on your website. Bookings appear in real time on the **Core > Bookings** page and the **Operations > Journey Board**. From there you can: - Confirm or decline pending bookings - Collect payment or send payment links - Assign specific assets to each reservation - Check customers in and track their journey {% callout type="check" title="You are all set" %} Your location is now accepting bookings. Continue to the [initial setup guide](/getting-started/setup/) for Stripe onboarding, staff invitations, and waiver configuration. {% /callout %} --- # AI access and scraping Source: https://docs.rentaltide.com/getting-started/ai-access/ > How to feed RentalTide docs to AI assistants, scrape them programmatically, and use the per-page AI tools # AI access and scraping We have intentionally made the RentalTide docs friendly for AI assistants and for anyone scraping them programmatically. If you are using Claude, ChatGPT, Perplexity, Cursor, or any other tool that benefits from large amounts of context, this page is for you. --- ## Per-page tools Every page on this site has two buttons immediately below the page title: - **Copy as Markdown** — copies the raw Markdown source of the current page to your clipboard. Paste it into any AI assistant to give it the full context of the page. - **Open in AI** — opens the current page in Claude, ChatGPT, or Perplexity with the page content already in the prompt — no web-browsing tool required. For short pages the full content is inlined into the chat input. For longer pages, the content is copied to your clipboard and the assistant is prompted to ask you to paste it. Also exposes a "View raw Markdown" option that opens the source `.md` file in a new tab. These buttons are designed to make it trivial to bring a docs page into whatever AI workflow you already use, even when the assistant cannot fetch URLs. --- ## Raw Markdown URLs Every page on the site is available as raw Markdown by prefixing the path with `/raw` and appending `.md`: | Rendered page | Raw Markdown | | ---------------------------------------------------------- | -------------------------------------------------------------- | | `https://docs.rentaltide.com/getting-started/caching/` | `https://docs.rentaltide.com/raw/getting-started/caching.md` | | `https://docs.rentaltide.com/fleet/inventory/` | `https://docs.rentaltide.com/raw/fleet/inventory.md` | | `https://docs.rentaltide.com/api-reference/bookings/` | `https://docs.rentaltide.com/raw/api-reference/bookings.md` | The raw files are plain UTF-8 Markdown with YAML frontmatter at the top. They are regenerated on every build, so they always match what is on the rendered page. --- ## llms.txt and llms-full.txt We follow the [llms.txt](https://llmstxt.org/) convention for AI-friendly site indexing. - **[llms.txt](/llms.txt)** — a structured site index with links to every section of the docs, plus key concept summaries and pricing. Intended as a small, high-signal entry point that an LLM can read in one pass. - **[llms-full.txt](/llms-full.txt)** — a single file containing the concatenated Markdown of every page on the site. Use this if you want to feed the entire docs corpus to an LLM in one shot. The file is approximately 800 KB and is regenerated on every build. Both files are linked from our [robots.txt](/robots.txt) using the `Llms-txt` and `Llms-full-txt` extensions. --- ## Crawler policy We **welcome** AI crawlers and large language model indexers. The following user agents are explicitly allowed in our [robots.txt](/robots.txt): - `GPTBot`, `ChatGPT-User`, `OAI-SearchBot` (OpenAI) - `ClaudeBot`, `Claude-Web`, `anthropic-ai` (Anthropic) - `PerplexityBot`, `Perplexity-User` (Perplexity) - `Google-Extended` (Google AI training) - `Applebot-Extended` (Apple Intelligence) - `CCBot` (Common Crawl) - `Bytespider` (ByteDance) - `cohere-ai` (Cohere) - `Meta-ExternalAgent`, `Meta-ExternalFetcher` (Meta) - `DuckAssistBot` (DuckDuckGo) - `YouBot` (You.com) - `Diffbot` If you operate an AI crawler not on this list and you want to index our docs, you are welcome to do so under the default `User-agent: *` allow rule. --- ## Sitemap A complete [sitemap.xml](/sitemap.xml) lists every page on the site. Use it to discover all available URLs programmatically. --- ## Asking the docs AI The docs site itself has a built-in AI assistant. Click the "Ask AI" button in the top navigation, type your question, and it will answer using the full docs corpus as context. Useful when you want a quick answer without leaving the page. If the assistant ever gets something wrong, please use the thumbs-down button on its response — those reports go straight to our team and help improve the bot. --- ## Programmatic API access For programmatic access to RentalTide data itself (not just docs), see the [API reference](/api-reference/). Every endpoint is documented with request and response examples that LLMs can use directly to generate working integration code. If you have feedback on what would make the docs more useful for AI-assisted workflows, [reach out to support](/core/support-channel/) — we will keep iterating. --- # Caching and data freshness Source: https://docs.rentaltide.com/getting-started/caching/ > How RentalTide caches data, why the 5-minute window exists, and how to force a refresh # Caching and data freshness RentalTide caches certain types of data in your browser to keep pages fast and to avoid repeatedly hitting our servers for information that rarely changes. Most caches use a **5-minute window**. If you make a change in one tab and do not see it reflected in another tab right away, the cache is almost always the reason. This page explains what is cached, why, and how to force a refresh when you need the very latest data. --- ## Why we cache Every page in RentalTide reads from many sources at once: bookings, inventory, location settings, pricing rules, customer records, staff lists, tax rates, and more. Loading all of that fresh from the database on every page navigation would make the app feel slow and put unnecessary load on the platform. Caching solves three problems at once: - **Page loads stay fast.** Navigating between bookings, calendar, and the journey board feels instant because shared data is already in memory. - **Server load stays low.** A typical operations day involves thousands of page loads per location. Without caching, every one would re-query the database for the same settings. - **Bandwidth is reduced.** This matters most for staff on mobile devices or slow Wi-Fi at the dock. The tradeoff is a short delay between making a change in the admin panel and seeing it reflected on customer-facing pages or other staff devices. We chose 5 minutes as the default because it is short enough that operational mistakes self-correct quickly, but long enough that the performance benefit is real. --- ## What is cached The list below covers the data that is most commonly cached in the browser. This is not exhaustive — many pages use short-lived (under 30 second) caches for live data like the journey board and rundown. ### 5-minute cache (most common) | Data | Where it shows up | | -------------------------- | ------------------------------------------------------------------ | | Pricing | Booking widget, walk-up flow, POS register, checkout | | Inventory settings | Fleet pages, availability checks, asset detail panels | | Location settings | Tax rates, operating hours, fees, deposit rules | | Customer settings | Admin settings page, staff permissions, terminal configuration | | Analytics dashboards | All eight analytics tabs | | Year-over-year revenue | Operations homepage revenue comparison | | Today's hub | Daily ops page (today's rentals and tour sessions) | ### Longer-lived caches | Data | Cache duration | Why it's longer | | -------------------------- | ------------------------- | ---------------------------------------------------------------- | | Stripe Capital eligibility | 24 hours | Computed from 84 days of charge history; expensive to recompute | | Access tokens | Until token expiry | Auth tokens refresh proactively 5 minutes before they expire | | Logos, photos, attachments | Browser default (often hours) | Static files served from our CDN with long cache headers | ### Short-lived caches (under 1 minute) Some live data uses very short caches that you will rarely notice — pricing calculations dedupe within 500ms, slip waitlist data refreshes every 30 seconds, etc. These exist mainly to prevent the same network request from firing multiple times when several components on the same page need the same data. --- ## What is **not** cached The following data is always fresh and reflects the database immediately: - **Booking creation and payment.** When a customer books or pays, the record is written to the database in the same request. No staff member will ever see a booking go missing because of a cache. - **POS transactions.** Every sale, refund, and till adjustment is recorded immediately. - **Ledger entries and accounting.** Financial state is always read from the source of truth. - **Walk-up state and timing.** The "left" and "back" timestamps update in real time. - **Calendar and journey board status.** These poll for changes frequently so other staff devices see updates within seconds. --- ## When the cache will surprise you The most common moments where the cache becomes visible: - **You changed pricing on an inventory item and the booking widget still shows the old price.** Wait up to 5 minutes, or have the customer hard-refresh the page. - **You updated tax rates in store settings and walk-up still applies the old rate.** Refresh the walk-up tab, or wait 5 minutes. - **You added a new staff member and they don't appear in the schedule dropdown on another device.** Have the other device refresh. - **You created a new promo code and a test booking won't accept it.** Promo codes propagate immediately for new bookings but cached pricing tables on already-open tabs may take up to 5 minutes to refresh. If you are unsure whether you are seeing a cache issue or a real bug, **force a refresh first** (see below). If the problem persists after a forced refresh, it is not a cache issue. --- ## How to force a refresh You have several options, from least to most disruptive: ### 1. Use the page's refresh button Many pages — analytics, reporting, the journey board, and the home dashboard — have a refresh icon in the page header. Clicking it bypasses the cache and fetches the latest data for that page only. ### 2. Navigate away and back Closing a page and reopening it from the sidebar will typically refresh its data. This works because most caches are tied to component mounts. ### 3. Hard-refresh the browser A hard refresh clears the in-memory cache for the current tab and forces all data to reload from the server. - **Mac:** `Cmd + Shift + R` - **Windows / Linux:** `Ctrl + Shift + R` - **iOS / Android:** Pull down to refresh, or close and reopen the tab ### 4. Log out and back in This is the most thorough option. It clears the access token cache as well as the data caches, and is appropriate if you suspect a permissions issue is being cached. {% callout type="tip" title="Customer-facing pages" %} If a customer reports seeing old pricing or stale availability on your booking widget, ask them to hard-refresh their browser. The widget caches data on their device the same way the admin app does on yours. {% /callout %} --- ## Frequently asked **Will my customers see stale pricing for 5 minutes after I change a price?** Possibly, if they had your booking page open when you made the change. New visitors will see the new price immediately. Existing visitors will see it within 5 minutes, or sooner if they navigate or refresh. **Does caching affect payment processing?** No. Payment processing always uses live pricing computed on the server at the moment of payment. A cached price shown on the booking page is only ever a display value — the final charge is recalculated server-side before any money moves. **Can I disable caching for my location?** Not currently. The cache is a platform-wide design choice and turning it off would significantly slow down the app for everyone using your location. If you have a use case where 5 minutes is too long, [contact support](/core/support-channel/) and we can discuss the specifics. **My change still hasn't appeared after 10 minutes. What now?** This is not a cache issue. Check the audit log for the relevant page to confirm the change was saved, and reach out to [support](/core/support-channel/) if needed. --- ## Summary - Most data is cached in your browser for **5 minutes** to keep page loads fast. - Bookings, payments, and POS transactions are **never cached** — they are always live. - To force fresh data: click a page's refresh button, navigate away and back, or hard-refresh the browser. - Final charges are always recalculated server-side, so cached pricing on a display page cannot cause an incorrect charge. --- # Data privacy and AI usage Source: https://docs.rentaltide.com/getting-started/privacy/ > Our commitment that we do not and will not sell your data, what we do collect, how we use it, and how to opt out of AI training # Data privacy and AI usage We treat your business data and your customers' personal information as a responsibility, not an asset to be monetized. This page explains in plain language what we do — and do not — do with the data you store in RentalTide. For the formal legal record, see the [Privacy Policy](https://rentaltide.com/legal/privacy-policy) and [AI Usage and Data Commitment](https://rentaltide.com/legal/ai-usage) on rentaltide.com. If you have any privacy question that this page does not answer, email [privacy@rentaltide.com](mailto:privacy@rentaltide.com) and a human will respond. --- ## We do not sell your data. We never will. This is the simplest and most important commitment we make to you and your customers. - We do not sell customer lists, booking history, payment data, or any other information you put into RentalTide. - We do not share your data with advertisers, marketers, or data brokers. - We do not allow third parties to use your data for their own commercial purposes. - We will not do these things in the future. If our business model ever changes, this page changes first, and you will be notified directly. ### Why we can promise this RentalTide makes money from a transparent platform fee on rentals and from credit card processing. As long as you are running rentals and accepting payments through us, we are aligned: we succeed when you succeed. There is no incentive for us to monetize your data on the side, and we have explicitly chosen a business model that keeps it that way. We believe that businesses that sell their customers' data lose the trust of those customers, eventually lose the customers themselves, and ultimately damage the entire industry. That is not a tradeoff we are willing to make. --- ## What we do collect To operate the platform, we collect and store: - **Business data**: location settings, inventory, pricing, bookings, transactions, staff records, and financial reports. - **Customer data**: names, contact information, payment methods, waiver signatures, and rental history — entered either by you or by your customers during the booking flow. - **Operational telemetry**: page views, performance metrics, and error reports that help us keep the platform fast and reliable. - **Support communications**: messages exchanged with our support team. All of this is used **only** to operate, support, secure, and improve the RentalTide platform for you. --- ## Who we share data with (sub-processors) To run the platform, we share specific data with trusted infrastructure providers, only as required to deliver the service: | Provider | What they handle | | ----------------- | ---------------------------------------------------------------- | | Amazon Web Services | Database hosting, file storage, compute infrastructure | | Stripe | Payment processing, payouts, and Stripe Capital | | Auth0 | Authentication and login | | SendGrid / Twilio | Email and SMS delivery to your customers | | Pinecone | Vector search for documentation and customer support | Each of these providers is contractually bound by their own data processing agreements, and is used only for the specific operational purpose listed above. None of them resell or repurpose your data. --- ## AI usage — full disclosure We are an AI-forward platform. We use machine learning internally to make the product better — for things like: - Improving the docs AI chatbot at the bottom-right of every page. - Suggesting smarter pricing recommendations and demand forecasts. - Detecting unusual patterns that might indicate fraud or operational problems. - Auto-categorizing support requests and routing them to the right person faster. To do this well, we sometimes use **limited, masked data** from the platform to train and evaluate these systems internally. ### What "limited and masked" means When we use platform data for internal AI training or evaluation: - **Personally identifiable information is removed or redacted** before it reaches any training pipeline. This includes customer names, email addresses, phone numbers, physical addresses, payment card numbers, and waiver signatures. - **Free-text fields** (notes, messages, descriptions) are reviewed and redacted of any identifying detail before use. - **Financial figures** may be used in aggregate or scaled form but are never tied back to a specific customer. - We use **only the smallest subset of data needed** to accomplish a specific improvement, not bulk dumps. - This data is **never sold, licensed, or shared** with third-party AI providers for their own model training. ### Your right to opt out If you would prefer that **none** of your business's data — masked or otherwise — be used for our internal AI training or evaluation, you can opt out at any time. Email **[privacy@rentaltide.com](mailto:privacy@rentaltide.com)** with the subject line "AI training opt-out" and include the email address associated with your RentalTide account. We will exclude your data from all future internal AI training runs within 30 days and confirm the change in writing. Opting out has no effect on the quality of service you receive. The platform behaves identically whether you opt in or out. --- ## Customer data and end-user rights Your customers — the people who book rentals through your booking page — have rights under privacy laws like GDPR (Europe) and CCPA (California). If a customer of yours contacts us directly with a privacy request, we will route them back to you, since you are the data controller for your customer data and we are the data processor. To help you respond to those requests, RentalTide provides: - A full data export tool ([Admin → Storage → Export](/admin/storage/)). - Account deletion tools that scrub customer records when requested. - Audit logs so you can see exactly when and how a customer's data was accessed. --- ## Security We use industry-standard practices: encryption in transit (TLS 1.2+), encryption at rest, role-based access controls, audit logging, and continuous vulnerability scanning. Stripe and AWS are PCI DSS compliant, so payment card data never touches our application servers directly. If you discover a security issue, please email [security@rentaltide.com](mailto:security@rentaltide.com) rather than filing a public issue. We respond to all reports within one business day. --- ## Questions, requests, or concerns For anything privacy-related, write to [privacy@rentaltide.com](mailto:privacy@rentaltide.com). A real human reads every message. Specifically, you can email us to: - Opt out of internal AI training. - Request a copy of all data we hold about your business. - Request deletion of your account and all associated data. - Ask for the current list of sub-processors and their contact information. - Report a suspected privacy issue. We aim to respond within two business days and resolve substantive requests within 30 days. --- # Reliability technical appendix Source: https://docs.rentaltide.com/getting-started/reliability-technical/ > Infrastructure details, RTO and RPO targets, and the specific architecture choices behind RentalTide's continuity guarantees # Reliability technical appendix This page is for technical decision makers — IT, security, procurement — who want the architecture behind the [reliability overview](/getting-started/reliability/). It documents where RentalTide runs, what we replicate, how fast we recover, and what dependencies sit outside our direct control. --- ## Hosting and regions RentalTide is hosted entirely on Amazon Web Services. We do not operate any on-premise servers and do not store production data on employee devices. | Component | Primary region | Notes | | ------------------------------------------ | -------------- | ---------------------------------------------------------- | | Application servers (API + web) | `us-east-1` | Containerised, autoscaled across three Availability Zones | | Primary database (PostgreSQL Aurora) | `us-east-1` | Multi-AZ, synchronous replication | | Object storage (photos, attachments, PDFs) | `us-east-1` | S3 with versioning and cross-region replication | | Background jobs and scheduled tasks | `us-east-1` | Lambda, run independently of the web tier | | Static site delivery (booking widget, docs)| Global edge | CloudFront, served from 400+ points of presence worldwide | | Backups (snapshots and continuous) | `us-east-1` + `us-west-2` | Cross-region replication for disaster recovery | The booking widget and customer-facing checkout pages are served from CloudFront's global edge, so a `us-east-1` regional event does not take the booking widget offline immediately — pages still render from cached assets, and any submission queues up against the API layer. --- ## Database resilience The primary database is Aurora Serverless v2 PostgreSQL. - **Synchronous replication across three Availability Zones.** A write is acknowledged only when it is durable on storage in two zones. Loss of a single zone is invisible to the application. - **Automatic failover within a region.** If the writer node becomes unhealthy, Aurora promotes a reader to writer in under 60 seconds. - **Continuous backup.** Every write is shipped to S3 in near-real-time. Point-in-time restore is available for any second within the last seven days. - **Daily automated snapshots.** Retained for 35 days. - **Cross-region snapshot replication.** Daily snapshots are copied to `us-west-2` for full-region disaster recovery. For full-region recovery, the recovery point objective is bounded by replication lag to `us-west-2`, which is typically under five minutes. --- ## Application tier The application tier runs as containers on AWS ECS Fargate behind an Application Load Balancer. - **Autoscaled across three Availability Zones.** A single AZ loss removes roughly one-third of capacity; autoscaling refills within minutes. - **Health checks every 15 seconds.** Failing instances are removed from the load balancer automatically. - **Rolling deploys.** New container versions are rolled out a fraction at a time. Health checks gate progression. A bad deploy stops itself before reaching full fleet. - **Automatic rollback.** Deploys that fail health checks revert to the previous task definition without manual intervention. - **Zero-downtime deploys.** New containers come up healthy before old containers are drained. --- ## Recovery time and recovery point objectives Recovery time objective (RTO) is the maximum acceptable time from incident start to service restoration. Recovery point objective (RPO) is the maximum acceptable data loss measured in time. | Failure scenario | RTO target | RPO target | Mechanism | | ------------------------------------------------- | ----------- | ---------- | ---------------------------------------------------------- | | Single application instance crash | 60 seconds | Zero | Container restart, load balancer reroute | | Single Availability Zone failure | 2 minutes | Zero | Multi-AZ Aurora and ECS distribute traffic to healthy AZs | | Failed deploy | 5 minutes | Zero | Automated rollback to previous task definition | | Aurora writer node failure | 90 seconds | Zero | Aurora failover promotes a reader | | Application-level bug (data corruption) | 30 minutes | Bounded by detection time | Targeted SQL repair using journal_entries audit log | | Catastrophic data corruption | 6 hours | 5 minutes | Point-in-time restore from continuous backup | | Full region outage (`us-east-1`) | 4 hours | 5 minutes | Restore from cross-region snapshot in `us-west-2` | RTO and RPO targets are reviewed quarterly and tested via game days at least twice per year. --- ## Audit and reconstruction Beyond raw database backups, RentalTide maintains an append-only journal (`journal_entries`) for every financial mutation: payments, refunds, fees, taxes, AR adjustments. This is double-entry by design. This means: - The cache columns on `rental_bookings` (amount paid, outstanding balance, amount refunded) can be reconstructed from the journal at any time. - A bug that corrupts cache fields without corrupting the journal is recoverable by re-running the cache sync from journal entries. - Forensic queries (who paid what, when, on which booking) survive any cache corruption. We treat `journal_entries` as the source of truth. The reliability of that table is the reliability of your books. --- ## External dependencies RentalTide depends on a handful of external SaaS providers. We hold ourselves to the union of their availability, so we choose them carefully. | Provider | What we use it for | Their stated SLA | Failure behaviour | | ----------------- | ---------------------------------------- | ---------------- | ---------------------------------------------------------- | | Stripe | Payments, terminals, Connect | 99.99% | Card capture and refunds fail with clear errors; no data loss | | Auth0 | Staff authentication | 99.9% | Existing sessions stay valid; new sign-ins blocked | | SendGrid | Transactional email | 99.95% | Emails queue; retried for 72 hours | | Twilio | SMS and voice | 99.95% | SMS retries; voice routing degrades to next provider | | AWS | Compute, storage, database | 99.99% per AZ | Multi-AZ design tolerates single-AZ loss invisibly | | OpenAI / Anthropic| AI features (docs bot, phone, summaries) | 99.9% | AI features degrade gracefully; core ops unaffected | A failure of any single external provider does not take RentalTide down. The most common visible effect is one feature (typically payment capture or outbound email) showing transient errors while the provider recovers. --- ## Backups and retention | Asset | Frequency | Retention | Storage location | | --------------------------- | ---------------- | --------- | -------------------------- | | Aurora continuous backup | Real-time | 7 days | S3, `us-east-1` | | Aurora daily snapshots | Daily, 04:00 UTC | 35 days | S3, `us-east-1` | | Cross-region snapshot copy | Daily | 35 days | S3, `us-west-2` | | S3 object versioning | Every write | Indefinite | S3, `us-east-1` | | S3 cross-region replication | Every write | Indefinite | S3, `us-west-2` | | Application logs | Real-time | 90 days | CloudWatch, `us-east-1` | | Audit / journal entries | Real-time | Indefinite | Aurora `journal_entries` table | Backups are encrypted at rest with AWS-managed keys. Cross-region replication uses separate keys per region to limit the blast radius of a key compromise. --- ## Security controls relevant to availability Availability is also a security concern. We protect against: - **DDoS** — AWS Shield Standard is always on. CloudFront absorbs volumetric attacks at the edge. - **Credential theft** — Auth0 enforces MFA for staff accounts, and bearer tokens are short-lived (1 hour) with rotating refresh tokens. - **Insider risk** — production database access requires SSO and is audited. No engineer has standing access to customer data; access is just-in-time and logged. - **Ransomware** — backups are immutable for their retention period (S3 Object Lock on snapshots). --- ## Status, communication, and runbooks When something goes wrong, you will hear from us in these places: - **`status.rentaltide.com`** — public status page, updated within minutes of detection. This is the source of truth for the platform overall. - **Your support channel** — Slack (for partner-tier customers) or email, with location-specific impact and ETA. - **Postmortems** — every incident with more than 15 minutes of customer impact gets a written postmortem within 5 business days, in the format described in our [internal COE template](https://github.com/anthropics/claude-code). Internally, we maintain detailed runbooks for each failure mode under `/docs/contingency/` in our codebase. These cover region failover, internet outage procedures, server crash response, and physical-disaster business continuity. They are not public, but the executive summaries are available on request for procurement and security reviews. --- ## Game days and chaos testing Twice a year (typically March and September, ahead of peak season), we run game-day exercises that test: - Aurora writer failover under load - ECS task termination across an entire AZ - Point-in-time database restore into a separate environment - Cross-region snapshot restore - Incident response paging, status page updates, and customer communication Results from each game day are recorded internally and fed back into our recovery time objectives. --- ## Reporting and questions For SOC 2 reports, vendor security assessments, or anything that requires a signed document, reach out to your account contact or `security@rentaltide.com`. We will route the request to the right place. For technical questions about a specific failure mode, reach out in your support channel — we are happy to walk through any of the above in more detail. --- # Reliability and continuity Source: https://docs.rentaltide.com/getting-started/reliability/ > How RentalTide stays available during cloud outages, internet drops, and physical disasters, and what your staff can do in each scenario # Reliability and continuity RentalTide is the system of record for your bookings, payments, and operations. We design it so a single bad day — at AWS, at your dock, or at our office — does not turn into a bad week for your business. This page covers the broad strokes of what we do to keep the platform running and what your team can do when something does go wrong. For deeper technical detail (regions, services, recovery time objectives), see the [technical appendix](/getting-started/reliability-technical/). --- ## What we protect against | Scenario | What it looks like | Who keeps you running | | ------------------------------------------------------- | --------------------------------------------------------------------------------- | ------------------------------------------------------ | | A single AWS data centre failing | Brief pause (seconds to a couple of minutes) while traffic reroutes | AWS multi-AZ infrastructure, automatic | | An entire AWS region going down (us-east-1) | Site may be slow or unreachable; we cut over to backups and update status page | RentalTide on-call, manual cutover | | Your local internet drops | Booking widget and admin are unreachable from your dock | You — offline procedures below | | Our servers crash or a deploy goes bad | Errors on specific pages, automatic restart and rollback in under 10 minutes | RentalTide on-call + automated health checks | | Fire, flood, or physical loss at your location | Your devices may be gone; your data and bookings are untouched | Cloud-hosted data, just sign in from any device | | Fire, flood, or physical loss at our office | No impact — we have no on-premise servers | Cloud-hosted everything | --- ## Where your data lives RentalTide runs entirely on Amazon Web Services. We do not store customer data on laptops, in our office, or on any device you cannot access from a browser. That means: - A staff laptop being lost, stolen, or destroyed has **no effect** on your bookings, customers, or payments. - A fire or flood at your location has **no effect** on your data. Sign in from a phone, a hotel laptop, or a tablet and you are back online. - We do not need to ship hardware to recover from any disaster. Your primary database runs in AWS's `us-east-1` region in Northern Virginia with synchronous replication across three independent data centres (called Availability Zones). Continuous backups are taken automatically, and we keep point-in-time recovery for the last seven days plus daily snapshots for thirty-five days. --- ## What happens if AWS has a bad day AWS designs each region to tolerate the loss of one data centre with no customer impact. We rely on that. In the rare cases where an entire region has degraded service: 1. **Detection** — automated monitors alert RentalTide on-call within minutes. 2. **Communication** — we update the status page at `status.rentaltide.com` and post in your support channel. 3. **Triage** — for partial regional outages (one service degraded, others fine), we wait for AWS to recover. AWS regional incidents are typically resolved in under two hours. 4. **Failover** — for a full sustained regional outage (very rare, last meaningful one was December 2021), we restore from cross-region backups into `us-west-2`. Your data is preserved; the site comes back up within the recovery window in the technical appendix. While we recover, your team can still do a lot — see the [offline procedures](#offline-procedures-for-staff) below. --- ## What happens if your internet drops This is the most common outage you will actually experience. RentalTide is a web app, and if the dock has no internet, neither does the booking widget or the admin panel. Here is what to do. ### Take walk-ups on paper Keep a printed walk-up sheet on the counter with these fields: - Customer first name, last name, phone, email - Asset type and quantity - Start time and intended return time - Signature line for liability waiver - Payment method (cash, card terminal direct, "bill me later") Photos of the driver's licence and signed waiver work fine on a phone. Enter them in RentalTide once internet is restored. ### Keep your card reader running Your Stripe terminal can complete payments without RentalTide as long as it has cellular or hotspot connectivity. The transaction will still settle correctly. Reconcile it against the paper sheets when you re-sync. ### Use a hotspot A phone with cellular service is enough to get the admin panel back up on one device. Use the [Today's Hub](/operations/journey-board/) view on that device as your single source of truth until the dock connection returns. ### Don't worry about the booking widget Customers trying to book online during your local outage just see a normal "site unreachable" message from their browser. They will retry. We do not lose their attempts — our analytics show the booking widget itself remains available globally even when individual locations are offline. --- ## What happens if our servers crash Servers fail. Bad deploys ship. We plan for both: - **Automatic restart.** If a server process crashes, our container orchestrator restarts it within seconds and shifts traffic to healthy instances. - **Health checks.** Every server reports a heartbeat every few seconds. Any instance that fails its health check is removed from the rotation automatically. - **Bad deploy rollback.** New code is deployed to a subset of servers first. If error rates spike, the deploy halts and the previous version takes back over. Total exposure on a bad deploy is usually under five minutes. - **Status page.** Major incidents are posted at `status.rentaltide.com` with regular updates until resolution. If you see errors that persist for more than a few minutes, reach out in your support channel. We will already be on it, but it helps us confirm scope. --- ## What happens if there's a fire, flood, or worse The honest answer: your data and bookings are unaffected. Everything that matters is in the cloud, replicated across three data centres. There is no scenario short of a regional AWS catastrophe where you lose customer records, payment history, or future bookings. ### If your location is unsafe to operate - Sign in to RentalTide from any device anywhere in the world. - Mark affected dates as closed under **Operations > Calendar > Block dates**. - Use the bulk messaging tools to email or text every customer with a booking in the affected window. - Use the [cart recovery](/marketing/cart-recovery/) tools to follow up once you reopen. ### If you lose physical hardware (terminals, printers, tablets) - Your data is fine. - A new tablet or laptop with a browser is all you need to be operational again. - Stripe will reissue terminals on request. Reach out and we will help you place the order. ### If we lose office access We have no on-premise servers, no local databases, and no critical infrastructure at our office. Engineering and support work from laptops that can be replaced overnight. The platform runs entirely on AWS and would not notice. --- ## Offline procedures for staff A quick reference your staff can use the moment internet drops, before they have a chance to read this whole page. | Activity | Offline alternative | | ------------------------- | ------------------------------------------------------------------------- | | New walk-up rental | Paper sheet + driver's licence photo. Enter when back online. | | Existing booking arrives | Mark on a printed daily list. Check them in on screen later. | | Take a payment | Use the Stripe terminal directly (cellular or hotspot). | | Look up a customer | Have a phone on a cellular hotspot for one device. | | Sign a waiver | Paper liability waiver, scan or photograph for upload later. | | Manage assets on the lake | Communicate by radio or phone; reconcile in the manifest when back up. | | Reservations on the phone | Take notes, promise a confirmation email once you re-sync. | Print this table and laminate it. We have a printable PDF version on request. --- ## How we communicate during incidents You will hear from us in three places during a real incident: 1. **Status page** — `status.rentaltide.com` is updated within minutes of detection. This is the source of truth for current status, what is affected, and ETA. 2. **Support channel** — your dedicated support channel (Slack or email) gets a message within the same window with anything specific to your location. 3. **Post-incident report** — for any incident with customer impact lasting more than fifteen minutes, we publish a written postmortem within five business days. These are stored under [Operations > Support channel](/core/support-channel/) and are also shared publicly when appropriate. If you ever cannot reach us through your usual channel during an outage, the support email at `support@rentaltide.com` is monitored from outside our normal infrastructure. --- ## Recovery time and recovery point at a glance These are the targets we hold ourselves to. They are described in detail in the [technical appendix](/getting-started/reliability-technical/). | Failure mode | Recovery time objective (RTO) | Recovery point objective (RPO) | | ----------------------------------------------- | ----------------------------- | ------------------------------ | | Single Availability Zone failure | Under 2 minutes | Zero data loss | | Application instance crash | Under 60 seconds | Zero data loss | | Bad deploy | Under 5 minutes | Zero data loss | | Full AWS region outage | Under 4 hours | Under 5 minutes | | Catastrophic data corruption (rare) | Under 6 hours | Under 5 minutes | --- ## Practising your own continuity plan Reliability on our side is half the picture. We recommend every location: - Keep paper walk-up sheets and waivers on hand for the season. - Keep one staff phone with a cellular plan dedicated to RentalTide access during dock-wifi outages. - Identify a backup person who can sign in and run the admin panel if the manager is unavailable. - Test your Stripe terminal on cellular at least once per season. - Know where to find your support channel and the status page. If you would like help drafting a continuity plan specific to your location, reach out in your support channel and we will work through it with you. --- # Initial Setup Source: https://docs.rentaltide.com/getting-started/setup/ > Configure your business information, connect Stripe, and invite your staff # Initial setup This guide walks you through the one-time configuration steps to get your RentalTide location fully operational. Complete these before your first day of business. --- ## Business information Navigate to **Admin > Settings** to fill in your business details. These values appear on receipts, invoices, and customer-facing pages. - **Business name** — your legal or DBA name - **Phone number** — shown on booking confirmations and the public site - **Logo** — uploaded as a square image, at least 256 x 256 px - **Support email** — where customer replies are routed --- ## Location setup Each location needs three things configured before it can accept bookings. ### Timezone Set the timezone that matches your physical location. All booking times, operating hours, and reports use this timezone. You can change it later, but existing bookings will not shift. ### Operating hours Define when your location is open for each day of the week. The public booking page only shows time slots within these hours. You can override individual dates from the calendar for holidays or weather closures. ### Tax rates and fees Under **Location > Taxes & Fees**, add each applicable tax rate (state, county, local) as a percentage. You can also define flat fees such as: - Fuel surcharge - Cleaning fee - Environmental fee - Credit card processing fee pass-through Taxes and fees are calculated automatically at checkout and reported separately in the ledger. --- ## Stripe Connect onboarding RentalTide processes payments through Stripe. Each location connects its own Stripe account so funds deposit directly into your bank. 1. Go to **Admin > Payments**. 2. Click **Connect with Stripe**. 3. Complete the Stripe onboarding flow — you will need your EIN or SSN, bank account details, and a government-issued ID. 4. Once approved, your location can accept credit cards, Apple Pay, and Google Pay. {% callout type="warning" title="Stripe approval" %} Stripe may take 1-2 business days to verify your identity and bank account. You can configure everything else in RentalTide while you wait, but payment collection will not work until Stripe approves your account. {% /callout %} If you already have a Stripe account, RentalTide uses **Stripe Connect** to link it. Your existing Stripe dashboard, payouts, and reporting remain unchanged. ### Terminal setup If you plan to accept in-person payments, register your Stripe terminal hardware under **POS > Terminals**. RentalTide supports Stripe Reader S700, M2, and BBPOS WisePOS E. --- ## Staff invitations Invite your team from **Admin > Staff Management**. Each staff member receives a role: | Role | Permissions | | ----------- | -------------------------------------------------------------------------------- | | **Admin** | Full access to all settings, reporting, and staff management | | **Manager** | Bookings, POS, operations, and reporting. Cannot manage billing or other admins. | | **Staff** | Day-to-day operations — check-in, walk-ups, POS register, journey board | 1. Click **Invite Staff**. 2. Enter their email address and select a role. 3. Assign them to one or more locations. 4. They will receive an email with a link to set their password. {% callout type="tip" title="Scheduling" %} After inviting staff, set up their weekly schedule under **Staffing > Schedule**. Shifts appear on the manifest and control who shows up on the journey board. {% /callout %} --- ## Waivers Most rental operations require customers to sign a liability waiver before departure. Configure your waiver under **Fleet > Waivers**. 1. Paste your waiver text or upload a PDF. 2. Choose when the waiver is presented — at checkout, on the next-steps page, or at check-in. 3. Enable the signature requirement. Customers sign on their phone or a shared tablet. Signed waivers are stored and linked to the booking. You can view or download them from the booking detail page. --- ## Next steps Your location is fully configured. Here are a few things to explore next: - [Embed the booking widget](/public/booking-widget/) on your website - [Create promo codes](/marketing/promo-codes/) for your launch - [Set up the POS register](/pos/register/) for walk-in retail sales - [Configure the manifest](/operations/manifest/) for daily departure tracking --- # Marina Management Source: https://docs.rentaltide.com/marina/ > Full-service marina operations including slips, reservations, waitlist, guest access, haul services, contracts, utility metering, and visual dock maps. RentalTide Marina is a complete marina management module that handles every aspect of running a marina -- from slip inventory and tenant reservations to utility billing and visual dock maps. It is designed for marinas of any size and integrates directly with your existing RentalTide billing, customer records, and accounting system. ## Module overview The Marina module is organized into the following functional areas: | Area | Purpose | | ----------------------------------------- | ---------------------------------------------------------------------- | | [Dashboard](/marina/dashboard/) | Unified operations overview with key metrics and quick links | | [Slips & Storage](/marina/slips/) | Manage physical slip inventory, unit types, amenities, and pricing | | [Reservations](/marina/reservations/) | Create and manage slip reservations with billing cycle support | | [Waitlist](/marina/waitlist/) | Queue customers waiting for slips with matching and offer workflows | | [Guest Access](/marina/guest-access/) | Issue and manage guest passes with access codes and ID verification | | [Haul Services](/marina/haul-services/) | Schedule haul-out, put-in, pressure wash, and relocation services | | [Contracts](/marina/contracts/) | Generate, send, and track lease/rental contracts with e-signatures | | [Meter Readings](/marina/meter-readings/) | Record electric and water meter readings and bill tenants for usage | | [Reports](/marina/reports/) | Occupancy, revenue, and utility usage reports with export capability | | [Marina Maps](/marina/marina-maps/) | Upload dock layouts and place interactive slip pins for visual booking | ## Subscription and pricing Marina management requires an active slip subscription. Slips are billed at **$10 per slip per month** on top of your base RentalTide subscription. When you add a slip that exceeds your current quota, the system will automatically bill for the additional capacity. {% callout type="note" %} You can manage your slip subscription from the **Subscription** page. The system tracks how many units you have active versus your quota and will alert you when you are approaching your limit. {% /callout %} ## Permissions Marina features are governed by the following permission groups: | Permission | Grants access to | | ------------------ | ------------------------------------------------------------------------ | | `inventory_access` | View slips, reservations, and all marina pages | | `inventory_add` | Create new slips, bulk create, upload maps | | `inventory_edit` | Edit slips, manage sections, update statuses, manage waitlist and guests | | `inventory_delete` | Delete slips, remove maps | ## Getting started 1. **Activate your slip subscription** from the Subscription page. 2. **Create your slip inventory** using the [Slips & Storage](/marina/slips/) page -- use Bulk Create for large marinas. 3. **Upload a marina map** from [Marina Maps](/marina/marina-maps/) and place pins on your slips. 4. **Set up contract templates** from [Contracts](/marina/contracts/) so you can send lease agreements. 5. **Start taking reservations** from the [Reservations](/marina/reservations/) page or through the public slip booking page. {% cardGroup cols=2 %} {% card title="Dashboard" href="/marina/dashboard/" /%} {% card title="Slips & Storage" href="/marina/slips/" /%} {% card title="Reservations" href="/marina/reservations/" /%} {% card title="Waitlist" href="/marina/waitlist/" /%} {% card title="Guest Access" href="/marina/guest-access/" /%} {% card title="Haul Services" href="/marina/haul-services/" /%} {% card title="Contracts" href="/marina/contracts/" /%} {% card title="Meter Readings" href="/marina/meter-readings/" /%} {% card title="Reports" href="/marina/reports/" /%} {% card title="Marina Maps" href="/marina/marina-maps/" /%} {% /cardGroup %} --- # Slip Contracts Source: https://docs.rentaltide.com/marina/contracts/ > Generate, send, track, and manage slip lease contracts with templates, e-signatures, PDF generation, and status tracking. The Contracts page lets you manage slip rental agreements with built-in contract generation, e-signature workflows, and PDF archiving. Every reservation can have an associated contract that moves through a defined lifecycle from draft to signed. ## Overview The contracts page shows four stats cards at the top: | Stat | Description | | ------------------- | ------------------------------------------------------------ | | Active Reservations | Total number of non-cancelled, non-completed reservations | | Contracts Signed | Number of reservations with signed contracts | | Pending Signature | Number of reservations with contracts awaiting signature | | Signed Rate | Percentage of active reservations that have signed contracts | ## Contract statuses | Status | Icon | Meaning | | ----------- | --------- | --------------------------------------------------- | | No Contract | Clock | No contract has been generated for this reservation | | Draft | Document | Contract generated but not yet sent to the tenant | | Sent | Email | Contract emailed to the tenant for signing | | Viewed | Open | Tenant has opened the signing link | | Signed | Checkmark | Contract fully executed | | Expired | Cancel | Signing deadline passed without execution | ## Tabs The page is organized into three tabs: 1. **Pending** -- Shows reservations without a signed contract (including Draft, Sent, Viewed, and No Contract statuses). 2. **Signed** -- Shows reservations with signed contracts. 3. **All** -- Shows all reservations regardless of contract status. ## Contract workflow ### Step 1: Generate a contract 1. Find the reservation in the table (on the Pending tab). 2. Click **Generate** in the Actions column. 3. Select a **contract template** from the dropdown. 4. Click **Generate**. The system creates a draft contract using the selected template, populating it with data from the reservation (customer name, slip details, dates, rates, etc.). ### Step 2: Send for signature 1. Find the reservation with a Draft contract. 2. Click **Send** in the Actions column (or use the context menu). 3. Enter the **signer name** and **signer email** (pre-filled from the reservation if available). 4. Click **Send**. The tenant receives an email with a signing link. ### Step 3: Track and follow up - **Resend** -- If the tenant has not responded, use the context menu to resend the signing email. - **Void** -- If you need to cancel an unsigned contract, use Void to invalidate it. You can then generate a new one. ### Step 4: View signed contracts Once signed, the contract appears in the Signed tab. From the context menu: - **View Signed PDF** -- Opens the signed contract PDF in a new tab (if a PDF URL is available). - **Generate PDF** -- If no PDF exists yet, generates one from the signed contract data and opens it. - **View Reservation** -- Navigates to the reservation detail page. ## Contract templates Click **Manage Templates** to open the Contract Template Editor. Templates are reusable contract formats that can include: - Standard lease terms and conditions - Placeholder variables that auto-fill from reservation data (customer name, slip number, dates, rates) - Location-specific provisions - Insurance requirements - Marina rules and regulations Templates are managed per location and can be created, edited, duplicated, and deleted. ## Table columns The contracts table shows: | Column | Description | | ----------------------- | -------------------------------------------------------------------- | | Reservation | Reservation number or ID | | Slip/Unit | Unit number or ID | | Renter | Tenant name | | Start Date | Reservation start date | | Contract Status | Current status with icon and color | | Last Sent / Signed Date | Date the contract was last sent (Pending tab) or signed (Signed tab) | | Actions | Generate, Send, or context menu | ## Context menu actions Right-click or click the three-dot menu on any row: ### For unsigned contracts - **Send for Signature** -- Email the signing link - **Resend** -- Send the email again - **Void Contract** -- Invalidate the current contract (allows generating a new one) ### For signed contracts - **View Signed PDF** -- Open the signed document - **Generate PDF** -- Create a PDF if one doesn't exist - **View Reservation** -- Navigate to the reservation detail {% callout type="tip" %} Create templates for each contract type you use -- annual lease, seasonal, transient, dry storage -- so generating new agreements takes just a few clicks. Monitor the "Signed Rate" stat to ensure all active tenants have executed agreements on file. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **"No Contract" showing for active reservations** -- This means no contract has been generated yet. Click Generate to create one from a template. **Tenant says they didn't receive the email** -- Use the Resend option from the context menu. Also check that the signer email address is correct. **Voided contract but need a new one** -- After voiding, the reservation returns to "No Contract" status and you can generate a fresh contract. {% /callout %} --- # Marina Dashboard Source: https://docs.rentaltide.com/marina/dashboard/ > Unified operations dashboard with occupancy metrics, quick links, recent activity, and attention alerts for marina staff. The Marina Dashboard is the central hub for day-to-day marina operations. It provides a real-time snapshot of your marina's status, surfaces items that need attention, and offers one-click navigation to every sub-module. ## Key metrics The dashboard displays six stat cards across the top of the page. Each card is clickable and navigates to the relevant management page. | Metric | Description | Navigates to | | ----------------- | ------------------------------------------------------------- | --------------- | | Occupancy Rate | Percentage of slips currently occupied out of total inventory | Slips & Storage | | Available | Number of slips with status "available" | Slips & Storage | | Waitlist | Number of active waitlist entries | Waitlist | | Scheduled Hauls | Number of haul services with status "scheduled" | Haul Services | | Pending Contracts | Number of contracts awaiting signature | Contracts | | Unbilled | Dollar amount and count of unbilled meter readings | Meter Readings | {% callout type="tip" %} The occupancy rate is calculated as `occupied / total slips`. Slips in maintenance or out-of-service status are included in the total but not counted as occupied. {% /callout %} ## Quick links Below the metrics, the dashboard shows six quick-link cards that provide fast access to each marina sub-module: - **Slips & Storage** -- Manage slip inventory and availability. Shows a badge if any slips are in maintenance. - **Waitlist** -- Manage slip waitlist entries. Shows a badge with the count of active entries. - **Guest Access** -- Manage visitor passes and access codes. Shows a badge with the count of active guest passes. - **Haul Services** -- Schedule haul-out and haul-in services. Shows a badge with the count of upcoming scheduled services. - **Contracts** -- Manage slip rental contracts. Shows a badge if any contracts are pending signature. - **Meter Readings** -- Record and bill utility usage. Shows a badge with the count of unbilled readings. ## Recent activity The left panel of the bottom section shows the most recent activity across your marina, combining: - Upcoming haul service requests (haul-out or haul-in with vessel name) - New waitlist entries Activity items are sorted by recency and show relative timestamps (e.g., "2 hours ago"). ## Attention required The right panel highlights items that need immediate action: - **Pending contracts** -- Contracts awaiting signature, with a link to follow up or send reminders. - **Unbilled meter readings** -- Readings that have not been invoiced yet, with the total pending dollar amount. - **Slips in maintenance** -- Units that are currently in maintenance status and may need status updates. When there are no items requiring attention, the panel shows an "all caught up" message. ## Location selection The dashboard requires a specific location to be selected. If you are viewing "All Locations," a modal will prompt you to choose one. All metrics, activity, and alerts are scoped to the selected location. {% callout type="note" %} Data on the dashboard updates automatically via SWR (stale-while-revalidate). You do not need to refresh the page to see new data, though there may be a brief delay as the cache refreshes. {% /callout %} --- # Guest Access Source: https://docs.rentaltide.com/marina/guest-access/ > Issue and manage guest passes with access codes, ID verification, vehicle tracking, granular permissions, and check-in logging. Guest Access lets you control who can enter your marina facility beyond your slip tenants. Issue digital guest passes with unique 8-character access codes, verify IDs, track vehicles, and set granular permissions for what each guest can access. ## Access types | Type | Description | | --------- | -------------------------------------------------------------------- | | Temporary | One-time or short-duration access with a fixed end date | | Recurring | Ongoing access for regular visitors (e.g., a captain or crew member) | | Permanent | Indefinite access until manually revoked | ## Guest pass details Each guest pass card displays: - **Status** -- Current pass status (Pending, Active, Expired, Revoked) - **Guest name** -- With a verified badge if ID has been checked - **Reservation link** -- Clickable link to the associated reservation - **Access code** -- Unique 8-character code (with copy-to-clipboard button) - **Access type** -- Temporary, Recurring, or Permanent - **Date range** -- Start and end dates - **Relationship** -- How the guest relates to the tenant (e.g., Friend, Family, Crew) - **Vehicle info** -- Make, model, color, and license plate (if provided) - **Visit count** -- Total number of check-ins and date of last visit - **Permissions** -- Labeled badges showing what the guest can access ### Permissions Each guest pass has four independent permission toggles: | Permission | Meaning | | ---------- | ------------------------------------------------------------------------ | | Slip | Guest can access the slip/dock area | | Vessel | Guest can board the vessel | | Facilities | Guest can use marina facilities (restrooms, showers, laundry) | | Operate | Guest is authorized to operate the vessel (highlighted in warning color) | ## Guest pass statuses | Status | Color | Meaning | | ------- | ------ | ---------------------------------- | | Pending | Orange | Pass created but not yet activated | | Active | Green | Pass is currently valid for entry | | Expired | Gray | End date has passed | | Revoked | Red | Pass manually deactivated by staff | ## Creating a guest pass 1. Click **Add Guest** in the header. 2. Enter the **Reservation ID** and **Unit ID** that the guest is visiting. 3. Fill in guest information: - **Guest Name** (required) - **Relationship** (e.g., Friend, Family, Crew) - **Email** and **Phone** (optional) 4. Set access details: - **Access Type** -- Temporary, Recurring, or Permanent - **Start Date** and **End Date** 5. Configure permissions: - Toggle on/off: Slip Access, Vessel Access, Facilities, Operate Vessel 6. Optionally add vehicle details: - Make, Model, Color, License Plate 7. Add **Notes** if needed. 8. Click **Create Guest Pass**. The system generates a unique 8-character access code automatically. ## Verifying an access code Use the **Verify Code** button in the header to check whether an access code is valid: 1. Click **Verify Code**. 2. Enter the 8-character code (auto-uppercased). 3. Click **Verify**. 4. The system returns whether the code is valid, and if so, shows the guest's name and pass details. This is useful for gate staff to quickly validate a visitor's credentials. ## Managing guest passes From the three-dot menu on each guest card: - **Check In** -- Record that the guest has arrived. Increments the visit count and updates the last check-in timestamp. Only available for Active passes. - **Verify ID** -- Mark that the guest's identification has been verified. Adds a verified badge to the card. Only available if not already verified. - **Revoke Access** -- Immediately deactivate the pass. The guest can no longer use the access code. Only available for Active passes. - **Delete** -- Permanently remove the guest pass record. ## Filtering and search - **Status filter** -- Click status chips to filter by Pending, Active, Expired, or Revoked. Each chip shows the count. - **Search** -- Search by guest name, access code, email, or phone number. - **Reservation filter** -- When navigating from a reservation detail page, the page automatically filters to show only guests for that specific reservation. ## Linking to reservations Guest passes are linked to specific reservations. Clicking a guest card navigates to the associated reservation detail page. You can also access the guest list for a specific reservation from the reservation detail page's "Guest Access" section. {% callout type="tip" %} Use the "Operate Vessel" permission carefully -- it indicates the guest is authorized to take the vessel out, which has liability implications. Keep this off by default and only enable it when the tenant explicitly authorizes it. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Access code not working** -- Check whether the pass has expired or been revoked. Use the Verify Code feature to see the current status. **Guest not appearing in the list** -- Make sure the correct location is selected. Guest passes are scoped to the location of the reservation they are linked to. {% /callout %} --- # Haul Services Source: https://docs.rentaltide.com/marina/haul-services/ > Schedule and manage haul-out, put-in, relocation, pressure wash, and other vessel handling services with status tracking and revenue reporting. Haul Services lets you schedule and track all vessel handling operations -- haul-outs, put-ins, round trips, and relocations. Each service request captures the vessel details, customer, scheduled date, pricing, and special instructions so your yard crew has everything they need. ## Service types | Type | Description | | ----------- | -------------------------------------------------------------- | | Haul Out | Lift the vessel out of the water onto land | | Put In | Return a stored vessel to the water (launch) | | Haul & Hold | Haul out and hold on land for a period (e.g., for maintenance) | | Round Trip | Haul out and put back in on the same day | | Relocation | Move a vessel from one location to another | {% callout type="note" %} Available service types can be configured per location from the Admin settings. The haul service settings (`haulServiceSettings`) on each location control which types are offered, pricing, and scheduling parameters. {% /callout %} ## Service statuses Each service progresses through a defined lifecycle: | Status | Color | Meaning | | ----------- | ------ | ----------------------------------------- | | Requested | Orange | Customer or staff submitted a request | | Scheduled | Blue | Date and time have been assigned | | Confirmed | Blue | Customer has confirmed the scheduled date | | In Progress | Orange | Service is currently underway | | Completed | Green | Service has been finished | | Cancelled | Gray | Service was cancelled | ### Status progression A progress bar on each service card visually indicates how far along the service is: | Status | Progress | | ----------- | -------- | | Requested | 16% | | Scheduled | 33% | | Confirmed | 50% | | In Progress | 75% | | Completed | 100% | | Cancelled | 0% | ## Creating a service request 1. Click **New Request** in the header. 2. Select the **service type** (Haul Out, Put In, Haul & Hold, Round Trip, or Relocation). 3. Enter **vessel information**: - Vessel name, LOA, beam, draft, weight - Registration number 4. Link to a **reservation** (optional) to associate the service with an existing slip reservation. 5. Set the **requested date** and **estimated duration** (30 minutes to 4 hours). 6. Add **customer notes** with any special instructions for the crew. 7. Enter optional **add-on services** (e.g., pressure wash, bottom paint checkboxes). 8. Click **Submit Request**. A unique service number is generated automatically (format: `HS[YY][MM]-[XXXX]`, e.g., HS2604-A3BF). ## Managing services ### From the service card Click any service card to open its detail dialog with full vessel info, dates, notes, and action buttons. ### Status actions Available actions depend on the current status: | Current Status | Available Actions | | -------------- | ------------------------ | | Requested | Schedule, Cancel, Delete | | Scheduled | Confirm, Cancel, Delete | | Confirmed | Start, Cancel, Delete | | In Progress | Complete, Cancel | | Completed | Delete (cleanup only) | | Cancelled | Delete | - **Schedule** -- Assign a specific date and time to a requested service. - **Confirm** -- Mark that the customer has acknowledged the schedule. - **Start** -- Begin the service (typically when the crane/forklift is in position). - **Complete** -- Mark the service as finished. - **Cancel** -- Cancel the service with a reason. - **Delete** -- Permanently remove the service record. ## Filtering and search - **Status filter** -- Click status chips to filter by any status. Each chip shows the count. - **Pending filter** -- Quick filter to show only Requested + Scheduled services. - **Search** -- Search by service number, vessel name, registration number, or customer notes. - **Revenue chip** -- The stats bar shows total revenue from completed services. ## Stats summary The stats bar at the top shows: - **Total** -- All services across all statuses - **Pending** -- Combined count of Requested + Scheduled services - **Per-status counts** -- Requested, Scheduled, Confirmed, In Progress, Completed, Cancelled - **Total Revenue** -- Sum of revenue from completed services ## Pricing Haul service pricing is configured at the location level in Admin settings. Pricing can be structured as: - **Flat rate** per service type - **Per-foot rate** based on vessel LOA - **Custom pricing** set on individual service requests The service detail shows the calculated price and any adjustments. {% callout type="tip" %} Use the "Pending" filter each morning to see what needs to be scheduled or confirmed for the day. Keep the service notes detailed -- your crew on the ground relies on them for special handling instructions like mast height, keel type, or blocking requirements. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Service stuck in "Requested" status** -- A staff member needs to manually schedule it by assigning a date and time. Requested services do not auto-schedule. **Cannot delete a completed service** -- Completed services can be deleted for cleanup, but consider whether you need the record for billing or reporting before removing it. {% /callout %} --- # Marina Maps Source: https://docs.rentaltide.com/marina/marina-maps/ > Upload marina dock layouts, place interactive slip pins, and provide visual slip booking for staff and customers. Marina Maps lets you upload images of your dock layouts and storage areas, then place interactive pins on each slip. The result is a visual, color-coded map that staff can use to manage slips and that customers can use to select slips when booking. ## Maps list The main page shows all uploaded maps for the selected location as image cards. Each card displays: - **Map image** -- A thumbnail preview (click to open the pin editor) - **Name** -- The map name (e.g., "Dock A", "Dry Storage Area") - **Description** -- Optional description text - **Active/Hidden status** -- Whether the map is visible to customers - **Display order** -- The order in which maps appear ## Uploading a new map 1. Click **Add Map** in the header. 2. Enter a **map name** (required) -- e.g., "Dock A", "North Basin", "Dry Storage Lot 2". 3. Add an optional **description**. 4. Click **Select Map Image** and choose a file: - Supported formats: JPEG, PNG, WebP, SVG - Maximum file size: 10MB 5. Preview the image in the dialog. 6. Click **Upload**. {% callout type="tip" %} Use aerial photos, architectural drawings, or schematic diagrams of your docks. Higher resolution images provide a better experience when zooming in. SVG format works well for schematic layouts because it scales without losing quality. {% /callout %} ## Editing map details From the three-dot menu on any map card, select **Edit Details** to change the name, description, or replace the image. ## Pin editor Click a map image or select **Edit Pins** from the context menu to open the interactive pin editor. The editor has two panels: ### Map canvas (main area) - **Zoom controls** -- Zoom in, zoom out, and fit-to-screen buttons - **Slip pins** -- Colored circles placed on the map, one for each assigned slip - **Drag to reposition** -- Click and drag any pin to move it to the correct location on the map ### Slip sidebar (left panel) - **Search** -- Filter slips by unit number - **Slip list** -- Shows all slips for the location with their current status and pin placement status - **Drag indicator** -- Drag a slip from the sidebar onto the map to place a new pin ### Pin colors | Color | Status | | ---------------- | ----------------------------- | | Green (#4CAF50) | Available | | Red (#F44336) | Occupied | | Orange (#FF9800) | Reserved | | Gray (#9E9E9E) | Maintenance or Out of Service | ### Saving pins Click **Save** in the editor toolbar to persist all pin positions. Pin positions are stored as X/Y coordinates relative to the map image dimensions. ## Visibility control Each map has an **Active/Hidden** toggle: - **Active** -- The map is visible to customers on the public booking page and in the customer portal. Staff can always see it. - **Hidden** -- The map is only visible to staff in the admin panel. Useful for maps that are under construction or seasonal. Toggle visibility from the three-dot menu: **Hide from Public** or **Show to Public**. ## Deleting a map From the three-dot menu, select **Delete**. A confirmation dialog warns that all slips will be unlinked from the map. The slips themselves are not deleted -- only the map image and pin positions are removed. ## Multiple maps per location You can upload multiple maps for a single location -- for example, one for each dock, a separate one for dry storage, and another for mooring fields. Each map operates independently with its own set of pins. ## Permissions | Action | Required Permission | | ------------------ | ------------------- | | View maps | `inventory_access` | | Upload new maps | `inventory_add` | | Edit maps and pins | `inventory_edit` | | Delete maps | `inventory_delete` | {% callout type="note" %} Maps are location-specific. You must select a specific location (not "All Locations") to view and manage maps. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Pins not saving** -- Make sure to click the Save button in the editor toolbar. Pin positions are not auto-saved. **Map image appears blurry** -- Try uploading a higher-resolution image. For best results, use images that are at least 2000px wide. **Slip not appearing in the sidebar** -- The sidebar shows slips for the current location. Verify that the slip is assigned to the same location as the map. {% /callout %} --- # Meter Readings Source: https://docs.rentaltide.com/marina/meter-readings/ > Record electric and water utility meter readings per slip, calculate usage and charges, and bill tenants through reservations or external invoices. Meter Readings lets you track electric (kWh) and water (gallon) consumption at each slip or storage unit. Enter the current reading, and the system calculates usage since the last entry and computes the charges based on your configured per-unit rate. ## Overview stats The page displays four stats cards: | Stat | Description | | ----------------- | ------------------------------------------------------------------ | | Total Readings | Total number of meter readings recorded | | Unbilled Readings | Readings that have not yet been invoiced | | Unbilled Amount | Total dollar amount of unbilled readings | | By Type | Split showing total electric usage (kWh) and water usage (gallons) | ## Recording a reading 1. Click **Record Reading** in the header. 2. **Select the slip** from the dropdown (shows unit number and name). 3. **Choose the reading type:** - Electric (kWh) - Water (gallons) 4. **Set the reading date** (defaults to today). 5. **Enter the current reading** -- The system will automatically calculate usage by subtracting the previous reading for this slip and type. 6. **Set the rate** (optional) -- Enter a per-unit rate ($/kWh or $/gallon). If left blank, the slip's default rate is used. 7. **Add notes** (optional) -- Any context about the reading. 8. Click **Record**. The system automatically: - Looks up the previous reading for that slip and type - Calculates usage (current - previous) - Computes the amount due (usage x rate) - Adds the reading to the unbilled queue {% callout type="note" %} Readings are ordered chronologically. The system uses the most recent prior reading for the same slip and type to calculate usage. If there is no prior reading, usage will equal the current reading value. {% /callout %} ## Tabs ### Unbilled tab Shows only readings that have not been billed. This is the primary working view. From here you can select readings and bill them. ### All Readings tab Shows every reading regardless of billing status. Useful for reviewing history and verifying data. ## Billing readings There are two ways to bill unbilled readings: ### Add to Reservation This is the primary billing method. It adds utility charges directly to a slip reservation. 1. Select one or more unbilled readings using the checkboxes. 2. Click **Add to Reservation**. 3. Select the **target reservation** from the dropdown. Only billable reservations (not completed, cancelled, or terminated) are shown. The dropdown displays reservation number, renter name, vessel name, and status. 4. Review the reservation details panel showing: - Current renter and vessel - Current reservation total - Current utility charges (Other Surcharges) - New charges being added - Updated total 5. Click **Add Charges to Reservation**. The selected readings are marked as billed and the charges are added to the reservation's "Other Surcharges" line item. ### Mark as Billed (External) Use this when you have invoiced the customer outside of RentalTide (e.g., through a separate accounting system). 1. Select one or more unbilled readings. 2. Click **Mark as Billed (External)**. 3. Enter the **external invoice or receipt number**. 4. Click **Mark as Billed**. The readings are marked as billed with a reference to the external invoice. ## Readings table The readings table shows the following columns: | Column | Description | | -------- | ------------------------------------------------------------------ | | Unit | Slip/storage unit identifier | | Type | Electric or Water (with icon and color coding) | | Date | Date the reading was taken | | Previous | Previous meter reading value | | Current | Current meter reading value | | Usage | Calculated usage (current - previous) with unit label (kWh or gal) | | Amount | Dollar amount due (usage x rate) | | Status | Billed (green) or Pending (orange) | | Actions | Delete button (only for unbilled readings) | ### Bulk selection On the Unbilled tab, you can: - Check individual readings - Use the header checkbox to select/deselect all unbilled readings - The selected count and total amount are displayed above the table ## Deleting readings Only unbilled readings can be deleted. Click the delete icon in the Actions column. Billed readings are locked and cannot be removed. {% callout type="tip" %} Record readings on a consistent schedule -- the first of every month works well for most marinas. This creates predictable billing cycles for your tenants. When multiple readings need to be billed to the same reservation, select them all at once to batch the operation. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Amount shows $0 or dash** -- The reading may not have a rate configured. Check the per-unit rate field when recording, or verify the slip's default rate in its settings. **Usage appears unexpectedly high** -- Verify the previous reading is correct. An incorrect prior entry will inflate the calculated usage. Check for potential equipment faults or unauthorized usage at the slip. **Cannot delete a reading** -- Only unbilled readings can be deleted. If you need to correct a billed reading, record a new adjustment reading. {% /callout %} --- # Marina Reports Source: https://docs.rentaltide.com/marina/reports/ > Occupancy, revenue, and utility usage reports with date range filtering, breakdown by unit type, and export capability. Marina Reports provides data-driven visibility into how your facility is performing. The page is organized into three report tabs -- Occupancy, Revenue, and Utilities -- with a configurable date range and export functionality. ## Date range selection All reports can be scoped to a specific time period using the date range selector in the header: | Option | Period | | ------------- | --------------------------------------- | | Current Month | First to last day of the current month | | Last Month | First to last day of the previous month | | Last 3 Months | Current month plus two prior months | | Last 6 Months | Current month plus five prior months | | Year to Date | January 1 through today | The selected date range is displayed as a banner below the header showing the exact start and end dates. ## Occupancy report The Occupancy tab provides insight into how full your marina is and which unit types have the most availability. ### Summary cards | Card | Description | | -------------- | --------------------------------------------------- | | Total Slips | Total number of slip/storage units across all types | | Occupied | Number of slips currently in "occupied" status | | Occupancy Rate | Overall percentage (occupied / total) | ### Occupancy by unit type A detailed table breaks down occupancy for each unit type: | Column | Description | | -------------- | ------------------------------------------------------------------------------------- | | Unit Type | Wet Slip, Dry Slip, Covered Slip, Dry Storage, Rack Storage, Trailer Storage, Mooring | | Total | Total units of this type | | Occupied | Number currently occupied | | Available | Number currently available | | Occupancy Rate | Percentage occupied (color-coded: green >= 90%, yellow >= 70%, red < 70%) | The occupancy rate for each type is displayed as a colored chip to quickly identify areas of high or low utilization. ## Revenue report The Revenue tab shows projected income based on currently occupied slips and their monthly rates. ### Summary cards | Card | Description | | --------------------------- | ------------------------------------------- | | Monthly Revenue (Projected) | Sum of monthly rates for all occupied slips | | Annual Revenue (Projected) | Monthly revenue multiplied by 12 | ### Revenue by unit type | Column | Description | | --------------- | --------------------------------------- | | Unit Type | The type of slip/storage unit | | Occupied Units | Number of occupied units of this type | | Monthly Revenue | Sum of monthly rates for occupied units | | Annual Revenue | Projected annual revenue (monthly x 12) | A totals row at the bottom sums all unit types. {% callout type="note" %} Revenue projections are based on the `monthlyRate` field of each occupied slip. If you use per-foot pricing or different billing cycles (seasonal, annual), the actual billed amounts may differ from the projections shown here. These figures represent the recurring rate capacity of your current occupancy. {% /callout %} ## Utilities report The Utilities tab shows electric and water usage data from your meter readings, displayed in a side-by-side layout. ### Electric usage | Metric | Description | | -------------- | ------------------------------------------ | | Total Readings | Number of electric meter readings recorded | | Total Usage | Sum of all electric usage in kWh | | Total Charges | Sum of all electric charges in dollars | | Billed | Count of readings that have been invoiced | | Unbilled | Count of readings not yet invoiced | ### Water usage | Metric | Description | | -------------- | ----------------------------------------- | | Total Readings | Number of water meter readings recorded | | Total Usage | Sum of all water usage in gallons | | Total Charges | Sum of all water charges in dollars | | Billed | Count of readings that have been invoiced | | Unbilled | Count of readings not yet invoiced | Billed and unbilled counts are displayed as colored chips (green for billed, orange for unbilled) for quick visual scanning. ## Exporting Click the **Export** button in the header to download the currently visible report data. This is useful for sharing with stakeholders, importing into accounting software, or offline analysis. {% callout type="tip" %} Run the occupancy report weekly to identify underutilized areas. If certain unit types consistently have low occupancy, consider adjusting pricing or marketing those spaces differently. Compare the utilities report against revenue to understand what percentage of income goes to utility costs. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Revenue shows $0 for occupied slips** -- Check that the monthly rate is set on those slips. Slips without a configured rate will contribute $0 to the projection. **Utility data appears incomplete** -- The report shows all readings in the system. If readings are missing, verify that meter readings are being recorded on schedule from the Meter Readings page. {% /callout %} --- # Slip Reservations Source: https://docs.rentaltide.com/marina/reservations/ > Full lifecycle management for slip reservations including creation, billing cycles, status transitions, payments, and detailed reservation views. Reservations track the full lifecycle of a marina tenant -- from initial booking through active occupancy and eventual departure. Each reservation ties a customer to a slip for a defined period with a configurable billing cycle. ## Reservations list The main reservations page displays all reservations for the selected location in a data grid with the following columns: | Column | Description | | ------------- | ---------------------------------------------------------------- | | Reservation # | Auto-generated identifier (click to open detail page) | | Slip | Unit number and section | | Customer | Renter's full name | | Vessel | Vessel name and LOA | | Start Date | When the reservation begins | | Billing | Billing cycle (Hourly, Daily, Weekly, Monthly, Seasonal, Annual) | | Amount | Total reservation amount | | Payment | Payment status indicator | | Status | Current reservation status | | Contract | Whether a contract has been signed | ## Creating a reservation There are two ways to create a reservation: ### From the admin panel 1. Click **Create Reservation** in the header. This opens the public slip booking page in a new tab, pre-filtered to your location. 2. Select a slip, set dates, enter customer and vessel information, and complete the booking. ### Add Client (quick create) 1. Click **Add Client** to open the quick-create modal. 2. Enter customer information, select a slip, set billing details. 3. The system creates both the customer record and reservation in one step. ## Reservation statuses | Status | Color | Meaning | | ---------- | ------ | ------------------------------------------ | | Pending | Orange | Created but not yet confirmed or paid | | Confirmed | Blue | Confirmed, awaiting start date or check-in | | Active | Green | Tenant is currently occupying the slip | | Completed | Gray | Reservation has ended (checked out) | | Cancelled | Red | Reservation was cancelled | | Terminated | Red | Reservation was terminated early by staff | ### Status transitions The status can be advanced through the status chip on each row. Available transitions depend on the current status: | Current Status | Available Actions | | -------------- | -------------------------- | | Pending | Confirm, Send Bill, Cancel | | Confirmed | Check In, Cancel | | Active | Check Out, Cancel | | Completed | (no further transitions) | | Cancelled | (no further transitions) | Click the status chip on any row to see and select available transitions. ## Payment statuses | Status | Color | Meaning | | -------- | ------ | ------------------------- | | Pending | Orange | No payment received yet | | Partial | Blue | Partial payment received | | Paid | Green | Fully paid | | Overdue | Red | Payment is past due | | Refunded | Gray | Payment has been refunded | ## Billing cycles Reservations support the following billing frequencies: - Hourly - Daily - Weekly - Monthly - Seasonal - Annual The billing cycle determines when recurring charges are generated and how the total is calculated. ## Filtering and search The filter bar provides multiple ways to narrow down reservations: - **Search** -- By reservation number or vessel name. - **Status** -- Select from Pending, Confirmed, Active, Completed, or Cancelled. - **Payment** -- Filter by payment status (Pending, Partial, Paid, Overdue, Refunded). - **Billing** -- Filter by billing cycle. - **Date range** -- Set a "Start From" and "Start To" date to filter by reservation start date. - **Clear Filters** -- Resets all filters at once. ### Stats cards Above the filters, clickable stats cards show the count of reservations by status (Pending, Confirmed, Active, Completed, Cancelled). Click a card to toggle that status filter on or off. ## Reservation detail page Click any reservation row to navigate to the full detail page. The detail page is a two-column layout with: ### Left column - **Hero card** -- Status, reservation number, slip/unit info, dates, and quick-action buttons - **Reservation details** -- Customer info, vessel details, billing cycle, and rates - **Billing** -- Itemized breakdown of charges, taxes, surcharges, and utility charges - **Payment summary** -- Amount due, amount paid, outstanding balance - **Payment history** -- Complete list of all payments and refunds - **Ledger** -- Full accounting ledger for the reservation ### Right column - **Timeline** -- Chronological status history with timestamps - **Contract** -- Contract status and signing details - **Notes** -- Internal staff notes - **Messages** -- Message thread with the customer - **Guest access** -- Guest passes associated with this reservation ### Available actions from the detail page - **Confirm / Check In / Check Out** -- Advance the reservation status - **Send Bill** -- Generate and email an invoice to the customer - **Cancel** -- Cancel with a reason (opens cancel dialog) - **Manage Billing** -- Adjust rates, surcharges, and billing details - **Process Payment** -- Record or process a payment - **Add Card** -- Save a payment method to the reservation - **Issue Refund** -- Process a full or partial refund - **Transfer** -- Move the reservation to a different slip - **Edit Customer** -- Update customer contact information - **Delete** -- Permanently remove the reservation (admin only) {% callout type="tip" %} Use the "Send Bill" action from the Pending status to email an invoice to the customer before confirming. This lets customers pay online before their start date. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Slip appears double-booked** -- The system warns before confirming overlapping reservations. Check whether an expired reservation was not properly checked out. **Billing not processing** -- Verify that the tenant has a valid payment method on file. Check the payment history for declined charges. {% /callout %} --- # Slips & Storage Source: https://docs.rentaltide.com/marina/slips/ > Manage physical slip and storage inventory with unit types, dimensions, amenities, pricing tiers, sections, and bulk operations. The Slips & Storage page is where you manage your marina's physical inventory -- every wet slip, dry storage bay, rack position, mooring, and trailer spot. Each unit has a type, dimensions, amenities, and a full pricing schedule that supports hourly through annual billing. ## Unit types RentalTide supports seven unit types that cover the full range of marina and storage operations: | Type | Description | | --------------- | ---------------------------------------------- | | Wet Slip | In-water berth alongside a dock or finger pier | | Dry Slip | Dry dock berth (not rack storage) | | Covered Slip | In-water berth with overhead cover | | Dry Storage | Indoor or outdoor on-land storage space | | Rack Storage | Stacked dry-rack position for smaller vessels | | Trailer Storage | On-land trailer parking spot | | Mooring | Offshore mooring ball or buoy | ## Adding a slip Click **Add Slip** in the top-right corner to open the slip form. The form is organized into tabs: ### Basic information | Field | Description | | ----------- | --------------------------------------------------------------------------------------------------- | | Unit Number | Required. A unique identifier (e.g., A-12, D3-07). Must be unique within the location. | | Unit Name | Optional friendly name (e.g., "Premium End-Tie") | | Unit Type | One of the seven types listed above | | Section | Organizational group (e.g., "Dock A", "North Basin"). Select an existing section or type a new one. | ### Dimensions | Field | Description | | ---------------- | -------------------------------------------------------------- | | Length (ft) | Physical length of the slip | | Width (ft) | Physical width of the slip | | Depth (ft) | Water depth at the slip | | Max Draft (ft) | Maximum vessel draft the slip can accommodate | | Max Beam (ft) | Maximum vessel beam allowed | | Max LOA (ft) | Maximum vessel length overall | | Max Weight (lbs) | Weight limit (relevant for rack and dry storage) | | Max Height (ft) | Height clearance (relevant for covered slips and rack storage) | ### Amenities | Amenity | Options | | --------------- | ---------------------------------------------------------------------------------------- | | Shore Power | Toggle on/off. If enabled, set amperage (30, 50, or 100 amp) and voltage (120V or 240V). | | Water | Toggle on/off | | WiFi | Toggle on/off. If enabled, optionally specify the network name. | | Bathroom Access | Toggle on/off | | Shower Access | Toggle on/off | ### Pricing Each slip supports flat-rate and per-foot pricing across multiple billing cycles: | Rate Type | Available Cycles | | ---------------- | ----------------------------------------------------------- | | Flat Rate | Hourly, Daily, Weekly, Monthly, Quarterly, Seasonal, Annual | | Per-Foot Rate | Hourly, Daily, Weekly, Monthly, Seasonal, Annual | | Security Deposit | One-time deposit amount | You can also configure quantity-based pricing discounts per cycle. ### Additional settings - **Show to Public** -- Whether this slip appears on the public booking page. - **Internal Notes** -- Staff-only notes not visible to customers. - **Tax Rates** -- Select which of your location's tax rates apply to this slip. ## Bulk create For large marinas, use **Bulk Create** to generate many slips at once: 1. Click **Bulk Create** in the header. 2. Set a **prefix** (e.g., "A-") and a **number range** (e.g., 1 to 50). 3. Optionally enable **zero-padding** (e.g., A-01 through A-50). 4. Set **defaults** for unit type, section, dimensions, amenities, and rates. 5. Click **Create** to generate all slips in a single transaction. {% callout type="note" %} Bulk create is limited to 500 slips per operation. If any unit number already exists, the entire batch is rolled back and no slips are created. The system will auto-bill your subscription if the new slips exceed your current quota. {% /callout %} ## Bulk edit 1. Click **Bulk Edit** in the header to enter selection mode. 2. Check individual slips or use the **Select All** checkbox. 3. Click **Edit** to open the bulk edit modal. 4. Change any combination of fields -- section, unit type, amenities, rates, etc. 5. Click **Apply** to update all selected slips at once. ## Sections Sections are organizational groupings (e.g., "Dock A", "South Basin", "Dry Storage Lot 2"). They help you filter and manage large inventories. - **Create a section** by typing a new name in the Section field when adding or editing a slip. - **Manage sections** by clicking the gear icon in the header. From there you can rename a section (all slips in that section are updated) or delete a section (clears the section assignment from those slips). - **Filter by section** using the Section dropdown in the filter bar. ## Viewing slips Toggle between **Grid view** (cards) and **List view** (compact rows) using the view toggle in the filter bar. ### Filtering - **Search** by unit number, name, or section. - **Status filter** -- Click a status chip (Available, Occupied, Reserved, Maintenance, Out of Service) to filter. Click again to clear. - **Unit Type filter** -- Select a specific type or view all. - **Section filter** -- Select a specific section or view all. ### Status indicators | Status | Color | Meaning | | -------------- | ------ | -------------------------------------------- | | Available | Green | Open and ready for a new reservation | | Occupied | Red | Currently assigned to an active tenant | | Reserved | Orange | Assigned to a confirmed upcoming reservation | | Maintenance | Blue | Temporarily out of service for repairs | | Out of Service | Gray | Permanently decommissioned or soft-deleted | You can change a slip's status directly from the slip card menu without opening the edit form. ## Deleting a slip When you delete a slip, two options are available: - **Soft delete** (default) -- Sets the status to "Out of Service." The slip is hidden from availability searches but its history and reporting data are preserved. - **Hard delete** -- Permanently removes the slip from the database. This is only allowed if the slip has no active reservations. Hard-deleting a slip also decrements your subscription count. {% callout type="warning" %} Hard-deleting a slip is irreversible. If the slip has any active reservations, the deletion will be blocked. Use soft delete to preserve audit trails. {% /callout %} ## Subscription Adding slips requires an active slip subscription. Each slip is billed at $10/month. When you add a slip that exceeds your current quota, the system automatically bills for the overage. The subscription banner at the top of the page shows your current usage and remaining capacity. --- # Slip Waitlist Source: https://docs.rentaltide.com/marina/waitlist/ > Manage a first-come-first-served queue for slip availability with customer preferences, offer workflow, and automatic position tracking. The marina waitlist manages demand when slips are full. Customers join a prioritized queue specifying their vessel requirements and slip preferences. When a matching slip opens up, staff can send offers directly to waitlisted customers. ## Waitlist entries Each waitlist entry is displayed as a card showing: - **Position number** -- Queue position (e.g., #1, #2, #3) - **Status** -- Current entry status - **Customer name** -- Linked from the customer database (clickable to navigate to customer profile) - **Vessel info** -- Vessel name and minimum LOA requirement - **Preferences** -- Preferred unit types and sections - **Start date** -- When the customer wants to move in (with flexible/fixed indicator) - **Budget** -- Maximum monthly rate the customer is willing to pay - **Notes** -- Free-text notes from the customer or staff - **Date added** -- When the entry was created ## Waitlist statuses | Status | Color | Meaning | | --------- | ------ | ------------------------------------------ | | Active | Blue | Customer is actively waiting for a slip | | Offered | Yellow | A slip offer has been sent to the customer | | Accepted | Green | Customer accepted an offer | | Declined | Red | Customer declined an offer | | Expired | Gray | Offer expired without response | | Cancelled | Gray | Entry was cancelled by staff or customer | ## Adding a customer to the waitlist 1. Click **Add to Waitlist** in the header. 2. **Select or create a customer:** - Search for an existing customer by name, email, or phone. - Or click "Create new customer" and enter first name, last name, email, and phone. 3. **Set preferences:** - **Preferred Unit Types** -- Multi-select from Wet Slip, Dry Slip, Covered Slip, Dry Storage, Rack Storage, Trailer Storage, or Mooring. - **Min Length (ft)** -- Minimum slip length required for the vessel. - **Max Monthly Rate** -- Budget cap for monthly rent. - **Desired Start Date** -- When the customer wants to begin. - **Flexible Start** -- Toggle on if the customer is flexible about timing. 4. **Set utility requirements:** - **Requires Water** -- Toggle on if water hookup is needed. - **Requires WiFi** -- Toggle on if WiFi is needed. 5. **Notes** -- Add any additional context. 6. Click **Add to Waitlist**. The customer is placed at the end of the queue. Position is automatically calculated based on the number of existing active entries. ## Making an offer When a slip becomes available, you can offer it to a waitlisted customer: 1. Click the three-dot menu on the waitlist card and select **Make Offer**. 2. **Select Available Slip** -- Choose from slips currently in "available" status. The dropdown shows unit number, type, length, and monthly rate. 3. **Set Offer Expiration** -- Choose how long the customer has to respond: 24 hours, 48 hours, 72 hours, or 1 week. 4. Click **Send Offer**. The entry status changes to "Offered" and an expiration countdown begins. ### Offer outcomes - **Accepted** -- The customer confirms, and the entry status changes to "Accepted." You can then create a reservation for the customer. - **Declined** -- The customer declines. A decline counter increments. After 3 declines (the default `maxDeclines` setting), the entry is automatically removed. - **Expired** -- If the offer expires without response, the entry reverts to "Active" status and can be offered a slip again. ## Matching engine The backend provides a matching endpoint that finds eligible waitlist entries for a specific slip. When a slip becomes available, you can use this to identify which customers match based on: - Unit type preference - Minimum length requirement - Power and water requirements - Section preference - Queue position (first-come-first-served priority) ## Managing entries From the three-dot menu on each card, you can: - **Make Offer** -- Send a slip offer (only available for Active entries) - **Cancel** -- Mark the entry as cancelled. Queue positions are automatically recalculated. - **Delete** -- Permanently remove the entry from the database. Queue positions are recalculated. ## Filtering and search - **Status filter** -- Click status chips (Active, Offered, Accepted, Declined, Expired, Cancelled) to filter. Chips show the count for each status. - **Search** -- Search by customer name, email, renter ID, vessel name, or notes. - **Results count** -- Shows "Showing X of Y entries" below the search bar. {% callout type="tip" %} Set offer expiration to 48 hours as a default balance between giving customers time to decide and keeping the queue moving. Review the waitlist weekly and reach out to customers who have been waiting longest to confirm they are still interested. {% /callout %} {% callout type="note" %} Position numbers are automatically recalculated when entries are cancelled or deleted. There is no way to manually reorder the queue -- it is strictly first-come-first-served. {% /callout %} --- # Marketing Source: https://docs.rentaltide.com/marketing/ > Promo codes, gift cards, affiliates, bundles, private links, cart recovery, templates, and website builder The marketing tools help you attract new customers, recover lost sales, and keep your brand consistent across every touchpoint. From discount codes and referral programs to automated email sequences and a drag-and-drop website builder, everything you need to grow your business lives here. {% cardGroup cols=3 %} {% card title="Promo codes" href="/marketing/promo-codes/" /%} {% card title="Gift cards" href="/marketing/gift-cards/" /%} {% card title="Affiliate program" href="/marketing/affiliate/" /%} {% card title="Bundles" href="/marketing/bundles/" /%} {% card title="Private links" href="/marketing/private-links/" /%} {% card title="Cart recovery" href="/marketing/cart-recovery/" /%} {% card title="Email templates" href="/marketing/email-templates/" /%} {% card title="Text templates" href="/marketing/text-templates/" /%} {% card title="Website builder" href="/marketing/website-builder/" /%} {% /cardGroup %} --- # Affiliate program Source: https://docs.rentaltide.com/marketing/affiliate/ > Referral tracking with unique URLs, commission rates, QR codes, and payout management The affiliate program lets you set up referral partnerships where affiliates earn a commission on bookings they send your way. Each affiliate gets a unique tracking URL, and the system automatically attributes bookings and calculates earnings. --- ## Dashboard overview The top of the affiliates page shows summary stat cards: | Card | What it shows | | ---------------- | ------------------------------------------ | | Total Affiliates | Number of registered affiliates | | Total Earned | Lifetime commissions across all affiliates | | Total Paid | Amount already paid out | | Pending | Commissions earned but not yet paid | --- ## Adding an affiliate 1. Click **+ New Affiliate**. 2. Enter the affiliate's **name** and **email**. 3. Set the **commission percentage** (applied to the base booking amount, before taxes and fees). 4. Optionally enable **pass cost to customer** -- adds the commission as a surcharge on the booking rather than coming out of your revenue. 5. Save. The system generates a **unique tracking URL** with a `?ref=` parameter: ``` https://app.rentaltide.com/booking/customerId/{yourId}?ref={affiliateId} ``` Share this URL with the affiliate. Any booking made through that link is automatically attributed to them. --- ## Affiliate table Each row in the affiliate table shows: | Column | Description | | ------------ | ----------------------------------- | | Name | Affiliate name and email | | Commission | Percentage earned per booking | | Total Earned | Lifetime commissions | | Paid Out | Amount already disbursed | | Pending | Commissions earned but not yet paid | | Actions | Menu with available operations | --- ## Managing affiliates ### Edit Update the affiliate's name, email, or commission rate. Changes apply to future bookings only -- existing commissions are not recalculated. ### Record payout Log a payment to the affiliate to move pending earnings to the paid column: 1. Click the **Record Payout** action. 2. Enter the payout amount. 3. The system deducts the amount from pending and adds it to paid. Payouts are tracked for audit purposes but the actual payment is made outside the system (via check, bank transfer, etc.). ### Location restrictions Click **Manage Locations** to restrict which of your business locations the affiliate can refer bookings to. By default, affiliates can refer to all locations. ### Staff assignments Click **Manage Staff** to assign staff members to an affiliate. Staff members linked to an affiliate can view the affiliate's performance data and manage their account. ### Generate QR code Create a QR code for the affiliate's tracking URL. The QR code opens the booking page with the affiliate's referral parameter pre-filled. Use the **Download** button to save the QR code image. ### Marketing flyer Generate a printable marketing flyer that includes the affiliate's QR code and booking URL. Affiliates can distribute the flyer at hotels, tourism offices, or events. ### Copy URL Copy the affiliate's tracking URL to the clipboard for sharing via email, text, or social media. ### Delete Remove an affiliate from the system. Historical commission data is preserved for reporting purposes. --- ## Linking affiliates to promo codes Affiliates can be linked to promo codes so their referrals receive a discount while you track the source: 1. Go to **Marketing > Promo Codes**. 2. Create or edit a promo code. 3. In the **Affiliate** targeting field, select the affiliate. 4. When a customer uses the promo code, the booking is attributed to the affiliate. This gives affiliates two attribution paths: the tracking URL and the linked promo code. --- ## Commission calculation - Commission is calculated on the **base booking amount** before taxes, fees, and add-ons. - When **pass cost to customer** is enabled, the commission percentage is added as a surcharge on the booking total, so the affiliate's commission comes from the customer rather than your margin. - Commission is accrued at the time of booking and moves to "pending" status. It stays pending until you record a payout. {% callout type="tip" %} Each affiliate gets a unique ID so there is no overlap in attribution. Use QR codes for physical distribution at hotels, concierge desks, and tourism offices. Link affiliates to promo codes to offer referral discounts while tracking the source. Pay affiliates on your own schedule -- the system tracks pending amounts until you record a payout. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Affiliate not getting credit for bookings** -- The customer must use the affiliate's tracking URL or linked promo code to book. Direct bookings or bookings through a different link will not be attributed. **Commission amount seems off** -- Commission is calculated on the base booking amount, not including taxes, fees, or add-ons. Verify the commission percentage on the affiliate's profile. **QR code not generating** -- The QR code is generated using an external service. Ensure your internet connection is active and try again. **Cannot delete an affiliate** -- You must have admin permissions to delete affiliates. The delete action is permanent for the affiliate record, though historical commission data is preserved. {% /callout %} --- # Bundles Source: https://docs.rentaltide.com/marketing/bundles/ > Multi-item discount packages with inventory, gift cards, and memberships Bundles let you package multiple items together at a discounted rate. Customers see the bundle as a single option in the booking widget, select it, and all included items are added to the cart with the discount applied automatically. This page covers creating and managing bundles from the marketing perspective. For fleet-level bundle configuration, see the [Fleet > Bundles](/fleet/bundles) page. --- ## Creating a bundle 1. Click **+ New Bundle**. 2. Enter a **name** and **description**. 3. Choose a **discount type**: | Discount type | How it works | | -------------- | --------------------------------------------------------------------------- | | Percentage off | Reduces the combined price of all items by a percentage | | Fixed price | Sets a flat price for the entire bundle regardless of individual item rates | | Free item | Makes one or more items in the bundle free -- customer pays for the rest | 4. Set the **discount value** (percentage or dollar amount). 5. **Add items** -- select from three item types: | Item type | Description | | ---------- | ------------------------------------------ | | Inventory | A rentable asset from your fleet | | Gift card | A prepaid gift card with a specified value | | Membership | A membership tier enrollment | 6. For each item, set the **quantity** and optionally mark it as a **free item** or set a **per-item discount percentage**. 7. Optionally configure: - **Location** -- restrict the bundle to a specific location - **Start date / End date** -- availability window - **Max redemptions** -- cap on total purchases - **Active** toggle -- enable or disable the bundle 8. Save the bundle. --- ## Bundle cards Each bundle appears as a card on the management page showing: - **Name and description** - **Discount type and value** (with an icon indicator: percentage, dollar, or gift card) - **Included items** with their type icons (boat for inventory, gift card, or membership badge) - **Redemption count** -- how many times the bundle has been purchased - **Status chip** -- Active or Inactive - **Actions menu** -- Edit or Delete --- ## Customer experience 1. Customer opens your booking widget. 2. They see a **Bundle** option alongside individual items. 3. Selecting the bundle adds all included items to the cart with the discount pre-applied. 4. They complete checkout as a single transaction. Each bundled item is managed individually after booking -- separate check-in, separate asset assignment, separate tracking on the manifest and journey board -- but they share a **bundle group ID** that ties them together as a single order. --- ## Scheduling bundles Use the start date, end date, and max redemptions fields to create time-limited promotional bundles: - **Flash sales** -- set a short validity window (e.g., this weekend only) - **Seasonal packages** -- match your bundle dates to your pricing seasons - **Limited availability** -- set max redemptions to create scarcity (e.g., "Only 20 available") When a bundle expires or reaches its redemption cap, it automatically stops appearing on the booking widget. {% callout type="tip" %} Create family packages (e.g., two kayaks + one paddleboard), adventure bundles (e.g., jet ski + snorkel gear), or gift combos (e.g., rental + gift card). Individual items within a bundle are managed separately for operations -- each gets its own booking entry for asset tracking and check-in. The bundle group ID lets you see which bookings belong together. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Bundle not showing in the widget** -- All inventory items included in the bundle must be available for the selected date and time. If even one item is unavailable, the bundle will not appear. Also check that the bundle is active and within its date range. **Discount not applying correctly** -- Double-check the discount type and value in the bundle configuration. For percentage discounts, verify the percentage is set on the bundle, not on individual items (unless using per-item discount mode). **Cannot add a membership or gift card** -- Ensure you have membership tiers or gift card support configured before adding those item types to a bundle. {% /callout %} --- # Cart recovery Source: https://docs.rentaltide.com/marketing/cart-recovery/ > Capture abandoned checkouts and follow up with AI-generated emails, SMS, or recovery links Cart recovery captures booking sessions where a customer entered their personal information but did not complete checkout. Follow up via email, SMS, or a direct recovery link to help them finish their booking. --- ## Viewing abandoned carts The cart recovery table shows all abandoned sessions for the selected location, sorted by most recent first. Each row displays: | Column | Description | | --------- | ------------------------------------------------------------------- | | Customer | First name, last name, and email address | | Phone | Phone number (if provided during checkout) | | Item | The inventory item left in the cart (name from BookingInfo) | | Date | The selected booking start date | | Amount | Total price and deposit due now | | Abandoned | Relative time since the session was abandoned (e.g., "2 hours ago") | | Status | Whether the customer has been contacted | | Actions | Menu with follow-up options | ### Status indicators - **Not contacted** -- the customer has not been reached out to yet. These rows are highlighted for attention. - **Contacted** -- a follow-up has been sent. The timestamp of the last contact is recorded. --- ## Follow-up actions Click the actions menu on any row to access follow-up options: | Action | What it does | | ------------------ | ---------------------------------------------------------------------------------------------------------------------- | | Copy Recovery Link | Copies a URL that restores the customer's cart exactly as they left it -- same dates, quantities, add-ons, and pricing | | Send Email | Opens a dialog to send an AI-generated recovery email personalized with the customer's name and cart contents | | Send SMS | Sends an AI-generated text message with a recovery link (requires phone number and Twilio integration) | | Delete | Removes the abandoned cart from the list | ### AI-generated messages When you choose **Send Email** or **Send SMS**, the system generates a personalized message using AI. The message includes: - The customer's name - The specific item they were booking - The selected dates and times - A direct recovery link You can preview and edit the message before sending. The AI adapts tone and content based on how long ago the cart was abandoned. ### Recovery links Recovery links restore the full cart state, including: - Selected inventory item - Chosen dates and times - Quantity - Add-ons (both inventory-specific and global) - Billing address (if entered) - Deposit amount and pricing The recovery URL format is: `{your-domain}/checkout/recover/{cartId}` --- ## Capture requirements Cart recovery only captures sessions where the customer has entered **personal information** during checkout: - Name (first or last name) - Email address - Phone number Anonymous browsing sessions where the customer only viewed inventory without entering any identifying information are not captured. --- ## Timing Abandoned carts have a **TTL (time to live)** -- they are automatically cleaned up after a set period. The most effective recovery happens quickly, so prioritize carts that were abandoned most recently. --- ## Email template Cart recovery emails use the **Cart Abandoned** (`cart_abandoned`) template in your email templates configuration. Customize the template content, subject line, and styling from **Marketing > Email Templates**. You can also configure scheduling to automatically send cart recovery emails after a set delay (e.g., 30 minutes after abandonment). {% callout type="tip" %} Follow up quickly -- recovery rates drop sharply after the first few hours. The AI-generated messages are personalized with the customer's name and specific items, so they feel natural rather than templated. Recovery links restore the full cart including selected dates, quantities, and add-ons. Set up automated cart recovery emails using the scheduling configuration on your Cart Abandoned email template. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **No abandoned carts showing up** -- Cart recovery requires the customer to have entered at least their name or email during checkout. Sessions where the customer only browsed inventory without entering personal details are not captured. **Recovery link expired** -- If the original availability has changed or the cart TTL has passed, the recovery link may no longer work. Create a private link with the same items and pricing to send instead. **SMS not sending** -- Verify that Twilio is configured in your location settings and that the customer's phone number is valid. The phone number must include a country code. **Customer received the email but the link shows an error** -- The item may no longer be available for the originally selected date. The customer will need to select new dates or contact your team for assistance. {% /callout %} --- # Email templates Source: https://docs.rentaltide.com/marketing/email-templates/ > Automated email templates with trigger-based sending, merge tags, scheduling, and visual editing Email templates let you automate customer communication at every stage of the booking lifecycle. Each template is tied to a trigger event, supports merge tags for personalization, and can be edited with a basic HTML editor or a visual drag-and-drop builder. --- ## Template list The templates page shows a table of all configured email templates for the selected location. Each row displays: | Column | Description | | ---------- | ------------------------------------------------------------ | | Template | Name and trigger type | | Subject | Email subject line | | Status | Enabled or disabled | | Scheduling | Trigger event and timing (e.g., "Immediately after booking") | | Actions | Preview, edit, schedule, style, copy, or delete | Switch between the **Templates** tab and the **Domain Auth** tab using the tab bar at the top. --- ## Available triggers Each template is linked to a trigger event that determines when the email fires: | Trigger | When it sends | | -------------------------------- | ------------------------------------------------------ | | Booking Confirmation | Booking is confirmed | | Booking Approval | Booking requires and receives approval | | Booking Denial | Booking approval is denied | | Booking Cancellation | Booking is cancelled | | Booking Reschedule | Booking is rescheduled | | Booking Weather Reschedule | Booking is rescheduled due to weather | | Booking Reminder | Configurable time before the booking start | | Booking Refund | Refund is issued | | Collect Booking Deposit | Deposit payment is processed | | Release Booking Deposit | Security deposit is released | | Cart Abandoned | Customer abandons checkout | | Request Review | Post-booking review request | | Waitlist Confirmation | Customer is added to the waitlist | | Waitlist Booking Available | Waitlisted date becomes available | | Yearly Reminder | Annual re-engagement email | | Gift Card | Gift card is purchased and delivered | | Tip Confirmation | Tip is received after completion | | Tour Pending Minimum | Tour has not yet met the minimum participant threshold | | Tour Confirmed | Tour reaches minimum and is confirmed | | Tour Cancelled | Tour is cancelled | | Tour Completed (Review Request) | Tour completes and review is requested | | Bundle / Cart Order Confirmation | Bundle order is confirmed | | Booking Link | Private link is sent to a customer | | Slip: Bill Sent | Marina slip bill is issued | | Slip: Hold Expired | Marina slip hold has expired | | Save My Spot Confirmation | Save My Spot reservation is confirmed | | Save My Spot Reminder | Reminder for a Save My Spot reservation | | Payment Plan: Upcoming Payment | Payment plan installment is approaching | | Payment Plan: Payment Charged | Payment plan installment is charged | | Payment Plan: Payment Failed | Payment plan charge fails | | Payment Plan: Plan Cancelled | Payment plan is cancelled | | Post-Trip Summary | Summary sent after trip completion | | Payment Captured | Remaining balance payment is captured | | Invoice: Balance Due | Invoice with outstanding balance is sent | | Manual | Sent manually by staff from the booking detail page | --- ## Editing a template ### Basic HTML editor Open a template to edit the **subject line** and **body** using a rich text editor (ReactQuill). Insert merge tags using the placeholder button, which shows a dropdown of all available variables. ### Visual editor (Unlayer) Click the **Visual Editor** button to open the Unlayer drag-and-drop email builder. Design emails visually with: - Pre-built content blocks (text, images, buttons, dividers, social links) - Drag-and-drop layout with columns and rows - Responsive design that adapts to mobile - Custom merge tag insertion - Design templates and style presets ### Conditional blocks Insert conditional blocks that show or hide content based on booking data. For example, show a damage deposit section only when a deposit is held, or show tour-specific information only for tour bookings. --- ## Merge tags Insert merge tags to personalize each email with real booking data. Tags are replaced at send time. ### Common merge tags | Tag | Description | | ------------------------------------ | -------------------------------------- | | `{{CustomerInfo.FirstName}}` | Customer's first name | | `{{CustomerInfo.LastName}}` | Customer's last name | | `{{CustomerInfo.Email}}` | Customer's email | | `{{BookingInfo.StartDate}}` | Booking start date | | `{{BookingInfo.EndDate}}` | Booking end date | | `{{BookingInfo.CompanyName}}` | Your company name | | `{{BookingInfo.CompanyPhoneNumber}}` | Your company phone | | `{{BookingInfo.Address}}` | Location address | | `{{InventoryInfo.inventoryName}}` | Name of the booked item | | `{{RentalPricing.Total}}` | Total booking price | | `{{RentalPricing.Currency}}` | Currency code | | `{{PaymentInfo.DepositDueNow}}` | Deposit amount due | | `{{PaymentInfo.RemainingBalance}}` | Remaining balance after deposit | | `{{OrderUrl}}` | Link to the customer's Next Steps page | | `{{GiftCard.code}}` | Gift card code (for gift card emails) | | `{{GiftCard.amount}}` | Gift card amount with currency | The full list of available variables is accessible through the placeholder button in both the basic and visual editors. --- ## Scheduling Configure when the email sends relative to the trigger event: | Timing | Description | | ---------------- | --------------------------------------------------------------------------------------- | | Immediately | Sends as soon as the trigger fires | | X minutes before | Sends a set number of minutes before the event (e.g., 120 minutes before booking start) | | X minutes after | Sends a set number of minutes after the event | The scheduling configuration dialog lets you set the delay in minutes and choose the direction (before or after). Each template can be independently enabled or disabled. --- ## Style presets Apply visual themes to your emails from the style presets library. Presets control colors, fonts, button styles, and overall layout. You can also create custom style presets with your brand colors and save them for reuse. --- ## Domain authentication The **Domain Auth** tab provides instructions for configuring SendGrid DNS records to send emails from your own domain. This improves deliverability and prevents emails from landing in spam. Required DNS records: - **SPF** -- Sender Policy Framework - **DKIM** -- DomainKeys Identified Mail - **DMARC** -- Domain-based Message Authentication --- ## Copying templates ### Copy to location Duplicate a single template to one or more other locations. The copy includes the template content, subject, body, scheduling configuration, and style settings. ### Copy all templates Duplicate all templates from the current location to another location in one operation. An overwrite confirmation dialog appears if the destination location already has templates for the same triggers. {% callout type="tip" %} Always send a test email to yourself before activating a template. Use the preview feature to see exactly what customers will receive with real booking data. Keep email content concise and action-oriented -- customers scan, they do not read paragraphs. Check the mobile preview since most customers read email on their phone. Set up per-location branding if your locations have different logos or color schemes. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Emails not sending** -- Verify the template is enabled, the trigger is set correctly, and your domain authentication (SendGrid DNS) is properly configured. **Merge tags showing as raw text** -- Check the tag syntax. Tags must be wrapped in double curly braces with the correct path: `{{CustomerInfo.FirstName}}` not `{{ CustomerInfo.FirstName }}`. **Emails going to spam** -- Complete your domain authentication setup with SPF, DKIM, and DMARC records. Sending from an unauthenticated domain significantly increases spam filtering. **Email looks different in some clients** -- Email rendering varies across clients (Gmail, Outlook, Apple Mail). Use the visual editor's built-in compatibility mode and test across multiple clients. **Template copy failed** -- Ensure you have admin permissions at the destination location. The copy operation may show an overwrite confirmation if templates already exist for the same trigger at the destination. {% /callout %} --- # Gift cards Source: https://docs.rentaltide.com/marketing/gift-cards/ > Create, sell, and redeem digital gift cards with balance tracking, analytics, and promotions Gift cards let you sell prepaid balances that customers can apply toward future bookings. Create and send gift cards directly from the dashboard, let customers purchase them through your booking widget, and run gift card promotions to boost sales. --- ## Dashboard overview The top of the gift cards page shows analytics cards summarizing your gift card program: | Card | What it shows | | ------------------- | ------------------------------------------------------ | | Total Sold | Total dollar amount of all gift cards sold | | Outstanding Balance | Sum of all unredeemed gift card balances | | Redemption Rate | Percentage of sold value that has been redeemed | | Expired Unredeemed | Value of expired gift cards that were never fully used | Additional stats include: - **Fully used** -- count of gift cards with zero remaining balance - **Partially used** -- count of cards with some balance remaining - **Unused** -- count of cards that have never been redeemed A **trends chart** shows monthly gift card sales and redemption activity. --- ## Creating a gift card 1. Click **+ New Gift Card**. 2. Enter the **amount** (dollar value of the card). 3. Enter the **recipient's email** address. 4. Optionally enter the **recipient's name**. 5. Optionally include a **personal message**. 6. Optionally set an **expiry date**. 7. Click **Create** -- the recipient receives an email with their gift card code. The gift card is assigned a unique alphanumeric code and tracked in the system immediately. --- ## Customer-purchased gift cards Customers can buy gift cards directly from your booking widget. They select an amount, enter the recipient's details, and pay at checkout. The gift card is delivered automatically via email with the unique code and any personal message. --- ## Redeeming a gift card During checkout, the customer enters their gift card code in the **Gift Card** field. The balance is applied to the order total. If the order is less than the gift card balance, the remaining amount stays on the card for future use. A single gift card can be used across multiple bookings until the balance reaches zero. --- ## Tracking balances The gift card table shows every issued card with: | Column | Description | | ----------------- | ------------------------------------------------ | | Code | The unique gift card code | | Original Amount | Initial value when the card was created | | Remaining Balance | Current available balance | | Recipient | Recipient's name and email | | Payment Status | Whether the card was paid for or issued manually | | Used Count | Number of times the card has been redeemed | | Last Used | Date of the most recent redemption | | Created | Date the card was issued | ### Aging buckets The analytics section includes aging buckets that group outstanding gift card balances by how long they have been unredeemed (e.g., 0-30 days, 31-60 days, 61-90 days, 90+ days). This helps identify cards that may be at risk of expiring unused. --- ## Gift card promotions The promotions panel lets you create special offers to drive gift card sales. Click the **Promotions** section to manage active promotions. ### Promotion types | Type | Description | | ---------------------- | ------------------------------------------------------------------- | | Buy One Get One (BOGO) | Customer buys a gift card and receives a second one free | | Bonus Value | Customer pays full price but receives extra value added to the card | ### Bonus value modes | Mode | Description | | ------------ | ----------------------------------------------------------------- | | Fixed Amount | A fixed dollar bonus is added (e.g., "Buy $100, get $20 bonus") | | Percentage | A percentage bonus is added (e.g., "Buy any card, get 20% extra") | ### Promotion settings | Field | Description | | ------------------------- | ------------------------------------------------------------------- | | Name | Internal name for the promotion | | Description | Explanation shown to staff | | Promotion type | BOGO or Bonus Value | | Bonus type | Fixed amount or percentage (for Bonus Value promotions) | | Bonus amount / percentage | The bonus value or percentage | | Min purchase amount | Minimum gift card value to qualify for the promotion | | Max purchase amount | Maximum gift card value that qualifies | | Max bonus amount | Cap on the bonus value (for percentage-based bonuses) | | Start / End date | Validity window for the promotion | | Max redemptions | Total number of times the promotion can be used | | Badge text | Custom label shown on the promotion badge (e.g., "Holiday Special") | | Banner color | Color of the promotional banner | | Active | Toggle the promotion on or off | ### Promotion statuses | Status | Meaning | | --------- | --------------------------------- | | Active | Promotion is live and available | | Scheduled | Start date is in the future | | Ended | End date has passed | | Sold Out | Max redemptions have been reached | | Paused | Manually deactivated | {% callout type="tip" %} Gift cards are a great option for holidays and special occasions -- promote them on your website and social media. Partial redemption is fully supported, so a $100 gift card can be used across multiple bookings. Run BOGO promotions during the off-season to generate advance revenue. The aging buckets in analytics help you track breakage (unredeemed balances) for accounting purposes. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Gift card code not working** -- Verify the code exists in the system, has a remaining balance, and has not expired. Codes are case-sensitive. **Promotion not applying** -- Check that the promotion is active, the current date is within the validity window, and the gift card amount meets the minimum purchase requirement. **Balance showing as wrong** -- Gift card balances update in real time as redemptions occur. Check the redemption history on the card detail to see all transactions that reduced the balance. {% /callout %} --- # Private links Source: https://docs.rentaltide.com/marketing/private-links/ > Unique booking URLs with pre-configured inventory, dates, pricing, and customer details Private links are unique booking URLs with pre-set inventory, dates, and custom pricing baked in. When a customer opens the link, everything is pre-filled -- they just confirm and pay. Use them for quotes, VIP pricing, group events, or any scenario where you want to control exactly what the customer sees. --- ## Creating a private link The creation flow is a two-step process: ### Step 1: Select inventory A visual card grid shows all available inventory items for the selected location, with photos, capacity information, and category labels. Click the item you want to include in the private link. ### Step 2: Configure details After selecting an item, fill in the booking details: | Field | Description | | ------------------ | ------------------------------------------------------------------------------------------------------------------- | | Start date | The booking start date | | End date | The booking end date | | Start time | The departure time (with time picker) | | Duration | Rental duration in hours. A dropdown shows available hourly slots from the item's pricing configuration with prices | | Quantity | Number of units to book | | Price override ($) | Custom price that overrides the standard rate. Leave blank to use the item's regular pricing | | Staff note | Internal note visible to staff only (not shown to the customer) | ### Customer pre-fill (optional) Pre-fill the customer's information so it appears when they open the link: | Field | Description | | ---------- | ------------------------ | | First name | Customer's first name | | Last name | Customer's last name | | Email | Customer's email address | | Phone | Customer's phone number | After saving, the system generates a unique URL and displays it for copying. --- ## Managing private links The private links table shows all links for the selected location: | Column | Description | | ---------- | ----------------------------------------------------------- | | Inventory | The item name (and asset type if applicable) | | Customer | Pre-filled customer name (or "No customer info" if not set) | | Dates | Start and end dates of the booking | | Price | Custom price if set, or "Standard pricing" | | Staff Note | Internal note from the link creator | | Status | Pending (unused), Redeemed (booked), or Expired | | Created | Date the link was created and by whom | | Last Sent | Date the link was last emailed to a customer | | Actions | Copy, Send, or Delete | --- ## Actions ### Copy link Click the **Copy** button to copy the private link URL to your clipboard. A confirmation appears when the copy is successful. Share the link via any channel -- email, text, chat, or social media. ### Send via email 1. Click the **Send** action. 2. The recipient's email is pre-filled if customer info was provided. 3. Optionally add a **custom message** that appears in the email body. 4. Click **Send**. The system sends a branded email with the booking link. The "Last Sent" column updates with the timestamp. ### Delete Click **Delete** to remove the private link. A confirmation dialog appears. Deleted links can no longer be accessed by customers. --- ## Link lifecycle Private links have a built-in expiration mechanism: - Links expire based on the **booking start date** or **30 days from creation**, whichever is later. - Once a customer completes a booking through the link, the status changes to **Redeemed**. - Expired and redeemed links return an error page when accessed. --- ## Email template Private link emails use the **Booking Link** (`private_link`) template in your email templates configuration. Customize the email content, subject line, and styling from the **Marketing > Email Templates** page. {% callout type="tip" %} Private links are ideal for sending quotes -- the customer clicks the link and books at the exact price you agreed on. Set the start date close to create urgency. Pre-fill customer information to reduce friction at checkout. Use the staff note field to record context about why the link was created (e.g., "Phone inquiry, quoted $200 for 2-hour rental"). {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Link not working** -- Check whether the link has expired or has already been redeemed. Expired and used links return an error page. **Customer seeing the wrong price** -- Verify the custom price set on the private link. The link price overrides your standard rates entirely. If no custom price is set, the item's regular pricing applies. **Email not sending** -- Verify that the recipient email is valid and that your email templates are configured. Check the **Booking Link** template in Marketing > Email Templates. **Link expired too soon** -- Links expire based on the booking start date or 30 days from creation, whichever is later. For quotes that may take time, set the start date further in the future. {% /callout %} --- # Promo codes Source: https://docs.rentaltide.com/marketing/promo-codes/ > Create discount codes with targeting rules, usage limits, and AI-powered suggestions Promo codes let customers apply discounts at checkout. Each code can be configured with a discount type, validity window, usage limits, and advanced targeting rules to control exactly when and where it applies. The page also includes analytics cards and an AI-powered suggestion engine. --- ## Dashboard overview The top of the promo codes page shows four stat cards: | Card | What it shows | | ----------------- | -------------------------------------------- | | Total Codes | Number of active promo codes | | Total Redemptions | Combined usage count across all codes | | Active Codes | Codes currently within their validity window | | Expiring Soon | Codes approaching their expiry date | A bar chart below the stats shows redemption trends over time. --- ## Creating a promo code 1. Click **+ New Promo Code**. 2. Enter the **code** (e.g., SUMMER25). Click the auto-generate button to create a random code. 3. Add a **description** for internal reference. 4. Choose the **discount type**: | Discount type | How it works | | ------------- | --------------------------------------------------------- | | % Discount | Percentage off the booking total (e.g., 25% off) | | $ Discount | Fixed dollar amount off the booking total (e.g., $50 off) | 5. Set the **discount value** (the percentage or dollar amount). 6. Set the **usage limit** -- maximum total redemptions for this code. 7. Set the **expiry date** -- the code stops working after this date. --- ## Advanced targeting Fine-tune which bookings qualify for the discount using optional targeting fields: | Targeting rule | Description | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- | | Location | Restrict the code to a specific location. Leave empty for all locations | | Inventory | Apply only to certain inventory items. Select "All Inventory" or pick specific items | | Day of week | Limit to specific days (e.g., Monday-Thursday for weekday-only discounts) | | Exclude add-ons | When enabled, the discount applies only to the base rental price, not add-on items | | Affiliate | Tie the code to a specific affiliate's tracking URL for attribution | | ID.me verification | Require ID.me identity verification to use the code. Restrict to specific groups: Veteran, Active Duty, Reservist, Military Family, or Gold Star Family | ### Affiliate-linked codes When you select an affiliate from the dropdown, the code is automatically linked to their tracking URL. Bookings made with the code are attributed to the affiliate for commission purposes. Use the **Generate Affiliate Code** button to auto-create a code using the affiliate's name. --- ## Managing promo codes The promo code table shows all codes with their key details: | Column | Description | | ----------- | --------------------------------------------- | | Code | The promo code string | | Description | Internal description | | Discount | Type and value (e.g., "25% off" or "$50 off") | | Usage | Current redemptions vs. usage limit | | Expiry | Expiration date | | Status | Active, expired, or usage limit reached | | Actions | Edit or delete the code | Click **Edit** to modify any field on an existing code. Click **Delete** to permanently remove a code (requires the `promo_delete` permission). --- ## AI suggestions Click the **AI Suggestions** button to activate the AI recommendation engine. It analyzes your booking patterns -- slow days, seasonal dips, underperforming inventory -- and generates promo code suggestions that target those gaps. Each suggestion includes: - A recommended code name - Discount type and value - Targeting rules (days, inventory, dates) - Rationale explaining why the suggestion was made Review the suggestions and click **Activate** to create the code with one click. --- ## Permissions | Permission | Required for | | -------------- | -------------------------------- | | `promo_create` | Creating and editing promo codes | | `promo_delete` | Deleting promo codes | --- ## Code limits Your plan includes a maximum number of active promo codes, controlled by the `maxDiscountCodes` setting. The current limit is shown when you approach it. Deactivate or delete expired codes to free up slots. {% callout type="tip" %} Promo codes are case-insensitive, so SUMMER25 and summer25 both work. Track each code's redemption count and revenue impact from the table. Set codes to auto-expire so you do not have to remember to deactivate them. Combine promo codes with affiliate tracking for full attribution visibility. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Code not working at checkout** -- Check that the current date falls within the valid window, the usage limit has not been reached, and the booking meets the targeting restrictions (location, inventory, day of week). If ID.me is required, the customer must complete verification first. **Hit the promo code limit** -- Your plan has a maximum number of active codes. Deactivate or delete expired codes to free up slots, or contact support to increase the cap. **Discount not applying to add-ons** -- If the "Exclude add-ons" flag is enabled on the code, add-on items are intentionally excluded from the discount. **Affiliate not getting credit** -- Verify the affiliate is linked to the promo code in the targeting settings. The customer can either use the affiliate's tracking URL or enter the linked promo code -- both attribute the booking. {% /callout %} --- # Text templates Source: https://docs.rentaltide.com/marketing/text-templates/ > Automated SMS templates with trigger-based sending, merge tags, and scheduling Text templates work like email templates but deliver messages via SMS. Each template is tied to a trigger event, supports the same merge tags for personalization, and can be scheduled relative to the trigger. Since SMS is text-only, there is no subject line or HTML formatting -- just the message body. --- ## Template list The text templates page shows a table of all configured SMS templates for the selected location: | Column | Description | | ---------- | ---------------------------------------- | | Template | Name and trigger type | | Message | Preview of the SMS body text | | Status | Enabled or disabled | | Scheduling | Trigger event and timing | | Actions | Preview, edit, schedule, copy, or delete | --- ## Creating a template 1. Click **+ New Template**. 2. Select the **trigger** from the dropdown (same trigger list as email templates -- see [Email Templates](/marketing/email-templates) for the full list). 3. Write the **message body** using plain text and merge tags. 4. Click **Save**. ### Editing Open an existing template to modify the message body. The editor is a plain text area with a **placeholder button** that inserts merge tags from a dropdown menu. --- ## Merge tags The same merge tags available in email templates work in text templates: | Tag | Description | | --------------------------------- | -------------------------------------- | | `{{CustomerInfo.FirstName}}` | Customer's first name | | `{{CustomerInfo.LastName}}` | Customer's last name | | `{{BookingInfo.StartDate}}` | Booking start date | | `{{BookingInfo.EndDate}}` | Booking end date | | `{{BookingInfo.CompanyName}}` | Your company name | | `{{InventoryInfo.inventoryName}}` | Name of the booked item | | `{{RentalPricing.Total}}` | Total booking price | | `{{OrderUrl}}` | Link to the customer's Next Steps page | The full list of available variables is accessible through the placeholder button in the editor. See the [Email Templates](/marketing/email-templates) page for the complete variable reference. --- ## Scheduling Configure when the text sends relative to the trigger event, using the same scheduling system as email templates: | Timing | Description | | ---------------- | --------------------------------------------------------------- | | Immediately | Sends as soon as the trigger fires | | X minutes before | Sends before the event (e.g., 120 minutes before booking start) | | X minutes after | Sends after the event | Click the **Schedule** button on any template to open the scheduling configuration dialog. --- ## Preview Click the **Preview** button to see how the rendered SMS will look with sample booking data filled in. The preview replaces all merge tags with realistic test values so you can verify the message reads naturally. --- ## Copying templates ### Copy to location Duplicate a text template to one or more other locations. The copy includes the message body, trigger configuration, and scheduling settings. An overwrite confirmation dialog appears if the destination already has a template for the same trigger. --- ## SMS character limits SMS messages are limited by carrier standards: | Length | Behavior | | ---------------------- | ----------------------------- | | 160 characters or less | Sent as a single SMS segment | | 161-306 characters | Split into 2 segments | | 307+ characters | Split into 3 or more segments | Multi-segment messages may arrive out of order on some carriers. The character count is displayed in the editor to help you stay within the single-segment limit when possible. --- ## Twilio integration Text templates require Twilio to be configured in your location settings. Without Twilio, SMS messages will not be sent. Configure your Twilio credentials in **Admin > Settings > Integrations**. {% callout type="tip" %} Keep messages under 160 characters when possible to avoid splitting into multiple SMS segments, which can arrive out of order. Include the Next Steps link (`{{OrderUrl}}`) so customers can access their booking details, waiver, and directions from the text. Use the same scheduling options as email -- for example, send a reminder 2 hours before the booking start time. Pair SMS reminders with email reminders for maximum reach. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Texts not sending** -- Verify that Twilio is configured in your location settings and that the customer has a valid phone number on file. The phone number must include a country code. **Messages arriving as multiple texts** -- SMS messages over 160 characters are split into segments. Shorten the message or accept that longer messages may arrive in pieces. **Merge tags showing as raw text** -- Check the tag syntax and ensure the merge tag path matches the available variables exactly. **Template copy failed** -- Ensure you have admin permissions at the destination location. Check whether a template for the same trigger already exists and handle the overwrite prompt. {% /callout %} --- # Website builder Source: https://docs.rentaltide.com/marketing/website-builder/ > Drag-and-drop website builder with booking widget integration, custom domains, and automatic publishing The website builder lets you create a public-facing website for your rental business without writing any code. Assemble pages from pre-built blocks, customize styling, embed your live booking widget, and publish to a RentalTide subdomain or your own custom domain. --- ## Layout The builder uses a three-panel layout: - **Left panel** -- Block library. Drag blocks onto the page from categorized sections. - **Center panel** -- Live preview. See your site exactly as customers will. Click any block to select it. - **Right panel** -- Property editor. Edit the selected block's content, images, colors, links, and layout. --- ## Block types Blocks are organized into three categories: section blocks, custom blocks, and system blocks. ### Section blocks | Block | What it does | | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | | Hero Banner | Large banner section with headline, subtitle, call-to-action button, background image, and overlay color. Toggle whether your company name appears | | Booking Widget | Embeds your live booking page directly on the site. Optionally filter to a specific location or inventory item | | Locations | Card grid displaying your locations with names, descriptions, images, and links (either RentalTide booking links or external URLs) | | About | Text and image section for your company story | | FAQ | Expandable question-and-answer accordion with configurable heading | ### Custom blocks | Block | What it does | | ---------------- | ----------------------------------------------------------------------------------- | | Text Block | Rich text content block with heading, body, and alignment options | | Image Block | Full-width or constrained image with alt text, caption, and configurable max width | | Image + Text | Side-by-side image and text layout with configurable image position (left or right) | | Spacer / Divider | Adds vertical spacing with configurable height and optional divider line | ### System blocks | Block | What it does | | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Navigation Bar | Top navigation with logo and configurable links. Links can be anchors (same-page), external URLs, or RentalTide booking links filtered to a specific location or item | | Contact | Contact section with email, phone, address, and optional boat license link | | Footer | Bottom section with social media links (Instagram, Facebook, X), terms of service, and country setting | --- ## Editing blocks 1. Click any block on the preview to select it. A blue highlight indicates the selected block. 2. The right panel shows all editable properties for that block. 3. Modify text content, swap images, update colors, change links, adjust padding and alignment. 4. Changes appear immediately in the live preview. ### Block operations | Operation | How to do it | | --------- | ------------------------------------------------------------------------------------------------ | | Add | Drag a block from the left panel onto the preview | | Remove | Select the block and click the delete button | | Reorder | Drag blocks up or down in the preview to change their position | | Duplicate | Select a block and click the duplicate button to create a copy with the same content and styling | --- ## Navigation links The navbar block supports three link types: | Link type | Description | | ---------- | ------------------------------------------------------------------------------- | | Anchor | Same-page navigation to a section (e.g., `#book` scrolls to the booking widget) | | External | Opens any external URL in a new tab | | RentalTide | Auto-generated booking link filtered to a specific location or inventory item | Configure links by adding entries with a label, type, and URL or location/inventory selection. --- ## Global styles Set site-wide defaults from the global styles panel: | Setting | Description | | ---------------- | ----------------------------------------------------- | | Primary color | Main brand color used for buttons, links, and accents | | Secondary color | Secondary accent color | | Font family | Typography used across the entire site | | Background color | Page background color | Individual blocks can override these global settings with their own color and style values. --- ## Publishing Click **Publish** to make your site live. The site is hosted at your RentalTide subdomain: ``` yourslug.rentaltide.com ``` The system automatically generates a sitemap for search engine indexing. Drafts are saved continuously as you work, so you never lose progress. ### Custom domains Custom domains (e.g., `www.yourcompany.com`) require DNS configuration: - Set up a CNAME record pointing to your RentalTide CloudFront distribution - The domain, CloudFront domain, and DNS settings are stored in the website configuration - Contact support for initial setup assistance ### Infrastructure details Each published website includes: - **S3 bucket** for static file hosting - **CloudFront CDN** for global delivery and caching - **Automatic SSL** for HTTPS - **Favicon and logo** support --- ## Booking widget integration The **Booking Widget** block embeds your real booking page directly on the website. Customers can browse inventory, select dates, and complete checkout without leaving your site. Optionally filter the widget to show only a specific location or inventory item. --- ## SEO The website builder supports basic SEO configuration: | Field | Description | | -------------------- | ---------------------------------------------------------------------- | | Website title | Sets the page `` tag (shown in browser tabs and search results) | | Custom location name | Override the location name for branding | | Favicon | Custom favicon uploaded for browser tab display | The automatically generated sitemap helps search engines discover and index your pages. {% callout type="tip" %} The Booking Widget block embeds your real booking page, so customers can browse inventory and book without leaving your site. Use high-quality hero images -- they set the first impression. Check the mobile preview to make sure everything looks good on phones and tablets. All changes are saved as drafts until you explicitly publish. The FAQ accordion is great for answering common questions about policies, what to bring, and cancellation rules. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Site not showing updates after publishing** -- CDN caching can delay updates by a few minutes. Wait 5-10 minutes and hard-refresh the page (Ctrl+Shift+R / Cmd+Shift+R). **Images not loading or slow** -- Ensure images are optimized for web (JPEG or WebP, under 2 MB). Very large files slow page load times. **Booking widget not showing** -- The booking widget requires at least one published inventory item at the selected location. If you have no published inventory, the widget appears empty. **Custom domain not resolving** -- Verify the CNAME DNS record points to the correct CloudFront distribution domain. DNS propagation can take up to 48 hours. **Navigation links not working** -- For anchor links, ensure the target section exists on the page and uses the correct anchor ID (e.g., `#book`). For RentalTide links, verify the location and inventory IDs are valid. {% /callout %} --- # Operations Source: https://docs.rentaltide.com/operations/ > Day-of tools for managing departures, returns, walk-ups, maintenance, and more The operational tools your team uses on the water and at the dock to manage daily activity. {% cardGroup cols=2 %} {% card title="Journey board" href="/operations/journey-board/" /%} {% card title="Rundown board" href="/operations/rundown-board/" /%} {% card title="Return board" href="/operations/return-board/" /%} {% card title="Manifest" href="/operations/manifest/" /%} {% card title="Walk-ups" href="/operations/walk-ups/" /%} {% card title="Weather" href="/operations/weather/" /%} {% card title="Maintenance" href="/operations/maintenance/" /%} {% card title="Asset tracking" href="/operations/asset-tracking/" /%} {% card title="Orders" href="/operations/orders/" /%} {% /cardGroup %} --- # Asset tracking Source: https://docs.rentaltide.com/operations/asset-tracking/ > Real-time GPS tracking of your fleet on an interactive map Asset tracking provides a real-time map view of your fleet, powered by GPS integrations from the RentalTide App Store. See where every asset is, monitor staff positions, and review live status -- all on an interactive map. --- ## Tracking providers The asset tracking page supports multiple GPS data sources, prioritized in this order: | Provider | Description | | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | **Zello Work GPS** | Staff location tracking via the Zello Work radio app. Shows staff positions on a map in real time. | | **Partner app (e.g. Vectra GPS)** | Third-party GPS tracking apps installed from the RentalTide App Store. The partner's tracking interface is embedded directly in the page. | | **Fallback tracking URL** | A custom tracking URL configured in your location settings, displayed as an embedded iframe. | The page automatically selects the best available provider. Zello takes priority when connected, followed by partner apps, then the fallback URL. --- ## Zello Work GPS When the Zello Work app is installed and connected: - Staff locations appear as pins on an interactive map. - The map shows the last known position and timestamp for each staff member. - A refresh button lets you manually request updated positions. - Connection status is displayed in the header ("Live" chip when connected). Zello integration requires the `rentaltide_zello_work` app to be installed from the App Store. --- ## Partner app tracking When a tracking partner app (such as Vectra GPS) is installed from the App Store: 1. The page fetches the partner's embed configuration via their API. 2. The partner's tracking map is rendered as an embedded iframe. 3. An "Open" button in the header links to the partner's full dashboard for advanced features. If the partner app needs initial setup (e.g., linking GPS devices), a setup prompt appears with a button to open the partner's configuration portal. --- ## Fallback tracking If no App Store tracking app is installed but your location has an `assetTrackingUrl` configured in location settings, that URL is displayed as a full-page embedded iframe. --- ## No tracking configured When no tracking provider is available, the page displays an empty state with: - An explanation of the asset tracking feature. - A **"Browse Tracking Apps"** button that navigates to the App Store, filtered to the "Operations & Logistics" category. - Instructions for configuring a custom tracking URL in location settings. --- ## Header The header section shows: | Element | Description | | ------------------- | -------------------------------------------------------------------------------------------------- | | **Title** | "Asset Tracking" | | **Powered by** | Name of the active tracking provider (e.g. "Powered by Vectra GPS" or "Powered by Zello Work GPS") | | **Live chip** | Green "Live" indicator when a tracking connection is active | | **Settings button** | Opens the App Store to manage tracking app configuration | | **External link** | Opens the partner app's external dashboard (when applicable) | --- ## Permissions Access to the asset tracking page requires the `matrix_access` permission. {% callout type="tip" %} Install a GPS tracking app from the App Store to get the most out of this page. Zello Work GPS is a good choice if your staff already use Zello for communication -- it adds location tracking on top of the radio functionality. For hardware-based boat tracking, partner apps like Vectra GPS provide device-level positioning. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **"Setup Required" message** -- Your tracking app is installed but hasn't been configured with your GPS devices yet. Click the button to open the partner's setup page. **Map is blank** -- Check that the tracking app is properly installed and your subscription is active. For Zello, verify that staff have the Zello Work app running on their devices. **Fallback URL not loading** -- Ensure the `assetTrackingUrl` in your location settings is a valid, publicly accessible URL that allows iframe embedding. {% /callout %} --- # Journey board Source: https://docs.rentaltide.com/operations/journey-board/ > Kanban board tracking today's bookings from arrival through return in real time The journey board is a drag-and-drop Kanban view of your daily rental operations. Bookings move through customizable pipeline stages -- from "Booked" all the way to "Complete" -- giving your entire team a live picture of what is happening at every step. --- ## Pipeline stages Stages are driven by your location's **pipeline configuration** (set in Admin > Location Settings). The board reads the enabled stages and renders one column per stage. Common default stages include: | Stage | Typical meaning | | ----------------------- | ------------------------------------------------------ | | **Booked** | Reservation confirmed, customer has not yet arrived | | **Check In** | Customer has arrived and is being processed | | **Rundown Ready** | Pre-departure walkthrough is ready to begin | | **Rundown In Progress** | Staff are performing the departure walkthrough | | **On Lake** | Customer has departed and is actively on the water | | **Returned** | Customer has come back and the asset is being received | | **Complete** | Rental is fully closed out | | **Cancelled** | Booking was cancelled | | **No Show** | Customer did not arrive | | **Pre-auth Held** | Payment pre-authorization is being held | The terminal statuses (Complete, Cancelled, No Show, Pre-auth Held) are always present even if not explicitly configured in the pipeline. --- ## Booking cards Each card in a column displays: | Element | Details | | ------------------- | -------------------------------------------------------------------------------------------------------------------------- | | **Customer avatar** | Initials of the customer; VIP customers show a crown icon instead | | **Customer name** | First and last name | | **Price chip** | Total rental price displayed as a green chip (e.g. "$150") | | **Inventory name** | Asset type or inventory name with a boat icon; shows quantity prefix (e.g. "2x Jet Ski") when more than one unit is booked | | **Assigned staff** | Staff member name, shown to the right of the inventory line when assigned | | **Time range** | Start and end time displayed in the booking's location timezone (e.g. "9:00 AM - 11:00 AM") | | **Status chip** | Current pipeline stage label with color-coded background | Cards are grouped when multiple line items share the same booking ID. Grouped bookings appear as a single expandable card showing all line items underneath. --- ## Moving bookings between stages Drag a card (or a grouped card) from one column and drop it into another to change its status. When you drop: 1. The board validates stage requirements (configured per-stage in location settings). 2. If validation warnings exist, an override dialog appears asking you to confirm. 3. On confirmation, the status is updated via the API and the card moves to the new column. Touch devices are fully supported -- the board uses a combined HTML5 and touch drag-and-drop backend for seamless operation on iPads and tablets. --- ## View modes Toggle between views using the icons in the header toolbar: | View | Description | | ------------------- | ----------------------------------------------------------- | | **Board** (default) | Kanban columns with drag-and-drop | | **Timeline** | A chronological timeline view using MUI Timeline components | --- ## Filtering and date navigation - **Date picker**: Select a start and end date. By default the board shows today only. - **Date arrows**: Step forward or back one day at a time using the arrow buttons, or jump to today with the "Today" button. - **Status filter**: Filter to show only specific pipeline stages. - **Location selector**: Switch between locations or view "All Locations" combined. Filter selections are persisted to local storage so they survive page reloads. --- ## Header bar The header includes: - **Live clock** showing the current time in the selected location's timezone. - **Filter toggle** to expand or collapse the filter panel. - **Refresh** happens automatically -- the board uses SWR with a 200-booking page size and re-fetches when filters change. --- ## Clicking a card Clicking (or tapping) any booking card navigates to the full booking detail page at `/bookings/{rentalId}`. Clicking a column header navigates to that stage's configured route. {% callout type="tip" %} The board auto-refreshes whenever you change filters. Color indicators on each column header show the stage color from your pipeline configuration, and a count chip displays the number of bookings in that stage. Use the location filter if you manage multiple sites. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Board appears empty** -- Verify the correct date and location are selected. The default view shows today only. **Can't drag a card** -- Check that your account has the `boatBrigade_access` permission. Cards in some terminal statuses may also have drag disabled. **Validation override dialog appears** -- Your pipeline has stage requirements configured. Review the warnings and confirm to proceed, or cancel to keep the booking in its current stage. {% /callout %} --- # Maintenance Source: https://docs.rentaltide.com/operations/maintenance/ > Fleet maintenance tracking with service history, scheduling, and AI condition estimates The maintenance page tracks every service task across your fleet. Log repairs, schedule preventive maintenance, run inspections, and monitor fleet condition -- all tied to individual inventory items and assets with full service history. --- ## Getting started Before you can log maintenance records, you need to select an inventory item: 1. Use the **Inventory selector** at the top of the page to pick the fleet item (e.g. "Pontoon Boats"). 2. Optionally narrow down to a specific **asset** within that inventory (e.g. "Asset #12"). Records and charts update to reflect the selected inventory item and asset. --- ## Maintenance records The main table shows all maintenance records for the selected inventory, sorted by date: | Column | Description | | ------------------ | ---------------------------------------------- | | **Date** | When the maintenance was performed | | **Type** | Category of work (see maintenance types below) | | **Performed by** | Name of the technician or staff member | | **Description** | Free-text description of the work done | | **Cost** | Total cost including parts and labor | | **Hours** | Engine or usage hours at the time of service | | **Next scheduled** | Engine hours at which the next service is due | | **Status** | Overdue, upcoming, or completed | ### Maintenance types The system tracks these standard maintenance categories: - Engine Oil Change - Filter Replacement - Hull Inspection - Propeller Check - Battery Maintenance - Anode Replacement - Fuel System Check - Electrical System Inspection - Bilge Pump Maintenance - Steering System Inspection - Transmission Fluid Change - Coolant System Maintenance - Winterizing / De-Winterizing - Damage Repair - Other --- ## Creating a record 1. Click the **+** button in the header. 2. Fill in the maintenance details: type, date, description, performed by, cost breakdown, and engine hours. 3. Optionally select the specific asset the maintenance was performed on. 4. Upload photos or documents. 5. Set the next scheduled service interval (in engine hours). 6. Click **Save**. Records can also be edited after creation or deleted (with confirmation). --- ## Upcoming maintenance A dedicated table shows maintenance items approaching their service interval. The system compares each record's "next scheduled" hours against the current maximum hours recorded for that asset, and flags items due within 20 hours. --- ## Inspections A separate inspection system runs alongside maintenance records: 1. Click the **inspection icon** in the header to open the inspection dialog. 2. Fill in the inspection checklist -- each inspection record captures condition details, hours, and findings. 3. Inspection records are displayed in their own table, filterable by asset. --- ## Filters The filter panel lets you narrow records by multiple criteria: | Filter | Options | | -------------------- | ------------------------------------------------- | | **Search** | Free text across type, performer, and description | | **Maintenance type** | Select a specific category | | **Performed by** | Filter by technician name | | **Date range** | Start and end date | | **Cost range** | Minimum and maximum cost | | **Status** | All, overdue, upcoming, or completed | --- ## Charts and analytics Toggle between visualization modes using the chart view selector: | View | Description | | --------------- | ------------------------------------------------ | | **Cost chart** | Bar chart showing maintenance costs by month | | **Types chart** | Pie chart breaking down maintenance by category | | **Calendar** | Calendar view showing maintenance events by date | --- ## KPI cards Summary cards at the top of the page display key metrics: - Total maintenance records - Total cost across all records - Number of overdue items - Number of upcoming items --- ## Work orders The work order system provides a structured workflow for larger maintenance tasks: - Create work orders with priority, assignee, and deadline. - Track work orders through open, in-progress, and completed statuses. - Work orders are stored locally and persist across sessions. --- ## Maintenance templates Save common maintenance procedures as templates to speed up record creation. Templates store the type, description, and default cost, and can be loaded when creating a new record. --- ## Rental blocking (Dry Dock) The maintenance rental blocker prevents bookings on assets that are under maintenance. When an asset is marked for dry dock: - The asset is unavailable for new bookings during the maintenance period. - Conflicting existing bookings trigger a conflict dialog. - The blocker supports multiple asset IDs simultaneously. --- ## Predictive maintenance widget The predictive maintenance widget uses usage data to estimate when service will be needed, helping you schedule maintenance before issues arise. {% callout type="tip" %} Completing a maintenance record with a "next scheduled" value automatically creates an upcoming maintenance alert. Keep engine hours updated on your assets so the predictive system can provide accurate forecasts. The maintenance calendar view is useful for planning seasonal preparation work. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Can't create a record** -- Verify that your account has the `maintenance_add_record` permission. **Can't delete a record** -- Deletion requires the `maintenance_delete_record` permission. **Asset not showing in the selector** -- The asset must be associated with the selected inventory item. Check that the asset exists in fleet management. **Charts showing no data** -- Select an inventory item first. Charts populate from the maintenance records for the selected item. {% /callout %} --- # Manifest Source: https://docs.rentaltide.com/operations/manifest/ > Tour and group departure management with participant lists and check-in tracking The manifest page is the control center for tour and group departures. It shows every scheduled session as a departure card, with participant lists, check-in progress, staff assignments, and group capacity at a glance. --- ## Departure cards Each departure card represents a tour session (or group of sessions sharing the same product and time). The card header displays: | Element | Details | | ------------------------- | ---------------------------------------------------------------------------------------------- | | **Tour name** | The tour product name (editable inline by clicking the edit icon) | | **Time range** | Start and end time displayed in the session's configured timezone (e.g. "9:00 AM -- 11:00 AM") | | **Participant count** | Current participants out of maximum capacity (e.g. "8 / 12") | | **Check-in progress bar** | A linear progress bar showing what percentage of tickets have been checked in | | **Tags** | Any tags applied to the group, shown as colored chips | Click the expand arrow to open a departure card and view its groups, bookings, and participant details. --- ## Groups within a departure When a tour session has multiple groups (e.g., the session split because the first group reached capacity), each group appears as a separate section inside the departure card. Each group shows: | Field | Description | | ------------------------------ | ------------------------------------------ | | **Group number** | Sequential group number within the session | | **Status** | Confirmed, pending, or cancelled | | **Assigned staff** | Staff members assigned to guide this group | | **Current / Max participants** | Capacity tracking for this specific group | --- ## Participant management Inside each group, every booking is listed with its participants: | Column | Description | | --------------------- | ---------------------------------------------------------------------------- | | **Customer name** | First and last name of the booking holder | | **Ticket count** | Number of tickets on this booking (e.g. 3 adults) | | **Check-in status** | Individual ticket check-in checkboxes -- tick each participant as they board | | **Equipment choices** | Tour equipment selections made during booking | | **Waiver status** | Whether waivers have been signed for each participant | ### Check-in actions - **Individual check-in**: Click the checkbox next to each participant name to mark them as checked in. - **Bulk check-in**: Click the "Check all" button to check in all participants on a booking at once. - **Undo check-in**: Uncheck a previously checked-in participant if needed. --- ## Staff assignment Click the staff assignment button on any group to open the staff assignment dialog. You can: - Search for staff members by name. - Assign one or multiple staff members to guide a specific group. - Staff assignments are saved immediately and visible to the rest of your team. --- ## Actions menu Each departure card has a three-dot menu with additional actions: | Action | Description | | --------------------- | ------------------------------------------------------- | | **Confirm group** | Mark the group as confirmed | | **Cancel group** | Cancel a specific group within the departure | | **Cancel departure** | Cancel all groups in this departure | | **Send review links** | Send post-tour review request links to all participants | | **Assign staff** | Open the staff assignment dialog | | **Print** | Print the manifest for this departure | --- ## Date filters Filter departures by time period using the toggle buttons in the header: | Filter | Shows | | ------------ | --------------------------------- | | **Today** | Sessions scheduled for today only | | **Upcoming** | Today through 14 days ahead | | **Past** | The last 7 days | | **All** | Past 7 days through 90 days ahead | --- ## Search and filtering - **Search bar**: Type a customer name, tour name, or booking ID to filter the departure list. - **Product filter**: Select a specific tour product to show only its departures. - **Check-in filter**: Filter to show only bookings that are not yet checked in, already checked in, or all. - **Show cancelled**: Toggle to include or hide cancelled bookings and sessions. --- ## QR scanner Open the QR scanner from the header to scan a customer's booking QR code. The scanner locates the matching booking across all visible departures and highlights it. --- ## Waiver management Click the waiver icon next to any participant to: 1. Send an SMS with a waiver signing link to the participant's phone number. 2. Browse recent waiver signatures and link an existing signed waiver to the participant. 3. View the current waiver status (completed, pending, or not sent). --- ## Data sources The manifest pulls from two data sources: - **Tour sessions** -- Sessions created through the tour product system, loaded via the tour sessions API. - **Inventory tour bookings** -- Bookings flagged as tours (`isTour=true`) that are not linked to a tour session, fetched separately and merged into the manifest view. Bookings for each session are loaded on-demand when you expand a departure card, avoiding unnecessary API calls for sessions you are not viewing. {% callout type="tip" %} Expand only the departures you need -- bookings are loaded lazily when you open a card, keeping the page fast even when you have dozens of sessions scheduled. The manifest respects your location's timezone for all time displays. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Departure card shows 0 participants but bookings exist** -- Expand the card to trigger the booking fetch. Participant counts update after bookings are loaded. **Times look wrong** -- The manifest uses the session's configured timezone. If sessions were created without a timezone, it falls back to the browser's local timezone. **Staff assignment not saving** -- Ensure you have the required permissions. Staff changes are saved immediately via the tour sessions API. {% /callout %} --- # Orders Source: https://docs.rentaltide.com/operations/orders/ > Multi-item orders combining bookings into a single transaction with shared customer info The order details page is the primary view for managing a customer's complete rental transaction. An order groups one or more line items (individual bookings) under a single customer, with shared payment, waivers, messages, and activity history. --- ## Order structure An order consists of: | Component | Description | | ---------------- | ----------------------------------------------------------------------------------------------- | | **Customer** | One customer per order, with name, email, phone, and billing information | | **Line items** | One or more individual rental bookings, each with its own inventory, assets, timing, and status | | **Payment** | A unified financial summary across all line items | | **Waivers** | Shared waiver participants that can be assigned to specific line items | | **Messages** | Conversation thread attached to the order | | **Activity log** | Audit trail of all changes made to the order | --- ## Order hero The top of the page displays the order header with: | Element | Description | | ------------------ | ------------------------------------------------------------------------ | | **Customer name** | Full name of the booking holder | | **Order ID** | Shortened booking ID for reference | | **Status color** | Color-coded indicator based on the majority status across all line items | | **Booking source** | How the order was created (online, walk-up, internal, etc.) | --- ## Pipeline stepper A horizontal stepper shows the order's progress through your location's pipeline stages. The stepper: - Highlights the current majority status across all active line items. - Uses your location's configured pipeline colors and stage names. - Terminal statuses (complete, cancelled, no show) use fixed colors: green for complete, red for cancelled/no show, amber for pre-auth held. ### Changing status You can move the entire order (all active line items) to a new pipeline stage by: - Clicking a stage in the stepper to advance or move backward. - Using the batch status update to change all active line items at once. Individual line items can also be moved independently from their own card. --- ## Line item cards Each line item in the order is displayed as a card showing: | Field | Description | | ------------------- | ----------------------------------------------- | | **Inventory name** | The asset type or product name | | **Quantity** | Number of units booked | | **Assigned assets** | Specific asset IDs assigned to this line item | | **Status** | Current pipeline stage for this individual item | | **Time** | Start and end date/time | | **Assigned staff** | Staff members assigned to this item | | **Addons** | Any add-on products attached to this line item | ### Line item actions Each line item card has its own set of actions: | Action | Description | | ----------------- | ------------------------------------------------------- | | **Assign assets** | Select or change the physical assets for this item | | **Assign staff** | Assign staff members with skill-based filtering | | **Manage addons** | Add or remove add-on products | | **Edit pricing** | Adjust the pricing for this specific item | | **Edit timing** | Change departure and return times | | **Change status** | Move this individual item to a different pipeline stage | --- ## Payment summary The payment section provides a consolidated financial view: | Field | Description | | ------------------ | ----------------------------------------- | | **Subtotal** | Combined base price across all line items | | **Taxes and fees** | Itemized tax and fee breakdown | | **Addons** | Total add-on charges | | **Discounts** | Applied discount amounts | | **Tips** | Total tip amount | | **Total** | Grand total for the order | | **Amount paid** | Total payments received | | **Balance due** | Outstanding amount (total minus paid) | ### Taking payment Click the payment button to open the payment dialog, where you can: - Charge a card on file. - Process a cash payment. - Use a connected terminal for in-person card payments. --- ## Waiver management The waivers section shows all participants associated with the order. Waiver participants can be: - **Dragged and dropped** onto specific line items to assign them. Drag a participant from the waiver list and drop them onto a line item card. - **Checked for status**: signed, pending, or not yet sent. - **Sent waiver links** via SMS or email. --- ## Order ledger The ledger tab shows all financial transactions associated with the order: - Payments received (card, cash, terminal) - Refunds issued - Gift card applications - Fee adjustments - Accounting entries with GL codes --- ## Messages A threaded conversation view for communicating with the customer. Messages can be sent via email and are logged in the order's activity history. --- ## Email history View all emails sent to the customer related to this order, including confirmations, reminders, reschedule notices, and cancellation notifications. --- ## Order actions The order-level action menu includes: | Action | Description | | ---------------------- | -------------------------------------------------------- | | **Send email** | Send a custom or template-based email to the customer | | **Cancel order** | Cancel all line items with optional refund | | **Reschedule** | Change the date/time for the booking | | **Assign membership** | Link a membership to this customer for discount pricing | | **Add item** | Add a new line item (inventory) to the existing order | | **Convert to walk-up** | Convert a pre-booked order into an active walk-up rental | | **Delete order** | Permanently remove the order (deletes all line items) | --- ## Activity log The activity log records every change to the order with timestamps and actor names: - Status changes - Payment events - Asset assignments - Staff assignments - Pricing edits - Email sends - Notes added --- ## Auto-refresh For active walk-up orders (those in check-in, on-lake, or rundown statuses), the page auto-refreshes every **60 seconds** and also refreshes when you return to the browser tab after switching away. {% callout type="tip" %} Orders are the recommended way to view and manage bookings. Even single-item bookings are displayed as orders with one line item. Use the waiver drag-and-drop feature to quickly assign signed waivers to the correct line items when a group has multiple rentals. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Order shows "Loading" indefinitely** -- Check the URL for a valid booking ID. The order page requires a `bookingId` parameter in the URL path. **Cannot delete order** -- All line items must be in a cancelled status before deletion is allowed. Cancel the order first, then delete. **Payment dialog not opening** -- Ensure your Stripe integration is configured and the connected account ID is valid for this location. {% /callout %} --- # Return board Source: https://docs.rentaltide.com/operations/return-board/ > Manage active rentals on the water and process returns with condition tracking The return board tracks every rental that is currently on the water or has just come back. It is split into two sections -- "On Lake" for active rentals and "Returned" for those that have docked but still need processing. --- ## Board layout | Column | Status | Description | | ------------ | ---------- | -------------------------------------------------------------------------------- | | **On Lake** | `on_lake` | Rentals that have departed and are currently active on the water | | **Returned** | `returned` | Rentals where the asset has come back but the return process is not yet complete | On mobile the two columns become swipeable tabs. --- ## Booking cards Each card shows: | Element | Details | | --------------------- | ----------------------------------------------------- | | **Customer name** | Full name from the booking record | | **Inventory** | Asset type or inventory name | | **Asset IDs** | Assigned asset identifiers | | **Departure time** | When the customer left the dock | | **Due back time** | Expected return time | | **Overdue indicator** | Red "OVERDUE" badge with a warning icon when past due | | **Remaining balance** | Outstanding balance on the booking, if any | Cards are color-coded by urgency: overdue bookings have a red border, due-soon bookings have an amber tint, and normal bookings have no special highlighting. --- ## Return flow When you tap a booking card in the "On Lake" column, a return dialog opens. The return process involves: 1. **Damage check** -- Indicate whether there is any damage. If yes, a damage dialog opens where you enter the employee name and open the full Check In/Out inspection modal. 2. **No damage path** -- If no damage, the booking moves directly to the "Returned" status. 3. **Gas recording** -- If gas tracking is enabled for the location, a gas modal opens for each assigned asset. You enter fuel quantity, select the POS fuel product, and optionally upload a receipt photo for AI validation. 4. **Overage calculation** -- If the location has booking overages enabled, the system automatically calculates late fees based on the grace period, overage threshold, and overage amount configured in location settings. 5. **Complete return** -- The booking status updates to `returned`, the timing record is finalized with back time and timestamp, and the gas total is added to the remaining balance. --- ## Gas tracking When the location flag `AllowGas` is enabled, the return flow includes per-asset fuel recording: | Field | Description | | ----------------- | -------------------------------------------- | | **Fuel quantity** | Number of liters or gallons used | | **Product** | The POS fuel product to debit from inventory | | **Total cost** | Calculated from quantity and product price | | **Receipt photo** | Optional upload for AI receipt validation | Gas entries update the POS inventory automatically, deducting the fuel quantity from stock. --- ## Overage fees If the location has `allowBookingOverages` enabled, late return fees are calculated automatically: | Condition | Fee applied | | --------------------------------------------- | ------------------ | | Return within grace period | No fee | | Return past grace period but within threshold | One overage fee | | Return past grace period and threshold | Double overage fee | The grace period, threshold, and overage amount are configured per-location in Admin settings. --- ## Auto-refresh The board refreshes every **15 seconds**. Updates from other staff members (such as a colleague completing a return) appear automatically without needing to reload. --- ## Date filtering Use the filter panel in the header to narrow the date range. By default, the board shows bookings from 14 days ago to 14 days ahead. Filters are persisted in local storage. --- ## Damage inspection When you select "Yes" on the damage check, the system opens a full Check In/Out modal where you can: - Record engine hours and fuel level - Write inspection notes - Upload photos and videos of the damage - Capture the employee signature The inspection record is saved as a boat record linked to the specific rental and inventory. {% callout type="tip" %} The return board is designed for dock staff. Keep it open on a tablet at the dock so you can see at a glance which rentals are approaching their return time. Overdue rentals sort to the top automatically with red highlighting. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Gas modal does not appear** -- Verify that the `AllowGas` flag is enabled in your location settings. **Overage fee seems wrong** -- Check the grace period, overage threshold, and overage amount in your location configuration. The calculation uses the difference between the scheduled end time and the actual return time. **Transfer to AR option missing** -- The "Transfer to AR" feature requires the `AllowTranferToAr` flag to be enabled in location settings. {% /callout %} --- # Rundown board Source: https://docs.rentaltide.com/operations/rundown-board/ > Multi-step checkout workflow for processing departures efficiently The rundown board is a two-column operations view that tracks bookings through the pre-departure checkout process. Bookings arrive in the "Ready" column when they are waiting to be processed, and move to "In Progress" while staff complete the departure walkthrough. --- ## Board layout The board splits bookings into two columns: | Column | Status | Description | | --------------- | --------------------- | ------------------------------------------------------------------------------------ | | **Ready** | `rundown_ready` | Bookings waiting for a staff member to begin the departure checkout | | **In Progress** | `rundown_in_progress` | A staff member has opened the checkout flow and is actively processing the departure | Each column shows a count badge and booking cards. On mobile, the two columns become tabs that you swipe between. --- ## Booking cards Each card displays: | Element | Details | | ------------------- | ---------------------------------------------------------------- | | **Customer name** | Full name from CustomerInfo | | **Inventory** | Asset type name or inventory name | | **Asset IDs** | Assigned assets, if any | | **Time** | Departure and return times | | **Waiver status** | Green "Waiver" chip when signed, orange "No waiver" when pending | | **Group indicator** | Shows the number of members when this is a group booking | Cards in the "In Progress" column display a flashing animation to indicate that a staff member is actively working on them. --- ## Checkout flow When you tap a booking card, a checkout modal opens with the **Check In/Out** dialog. The flow varies depending on your asset configuration: 1. **Select the asset** -- If the booking has multiple assets, select which one you are checking out. 2. **Record condition** -- Log engine hours, fuel level, current condition, and any notes. 3. **Capture photos** -- Take or upload photos of the asset before departure. 4. **Sign off** -- Employee signature confirms the pre-departure inspection. When all assets on a booking have been checked out, the booking automatically moves to `rundown_in_progress`. When the checkout is finalized, the booking transitions to `on_lake` with departure time, return time, and timestamps recorded. --- ## QR scanner Tap the camera icon in the header to open the built-in QR scanner. Customers receive a QR code in their booking confirmation email -- scanning it instantly locates the booking in either the Ready or In Progress column and opens the checkout modal. You can switch which column the scanner searches (Ready or In Progress) before scanning. --- ## Auto-refresh The board refreshes every **15 seconds** to keep the display current. Bookings that change status (e.g., moved to `on_lake` by another staff member) automatically disappear from the rundown board. A manual refresh button is also available in the header. --- ## Date filtering By default the board loads bookings from 14 days ago through 14 days ahead. You can customize the date range: 1. Tap the **filter icon** in the header to expand the filter panel. 2. Set a start date and end date. 3. Tap **Apply** to activate the filter, or **Reset** to return to the default range. Filter settings are saved to local storage. --- ## Optimistic updates When you begin processing a booking, the board immediately marks it as "In Progress" locally before the server confirms. If the server update fails, the card reverts to its previous state. This ensures the UI feels fast even on slower connections. {% callout type="tip" %} During peak periods, use QR scanning to process departures quickly without scrolling through the board. The 15-second auto-refresh means multiple staff members can work the board simultaneously without stepping on each other. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **QR scanner not working** -- Check that your browser has camera permissions enabled. On iOS, you may need to grant camera access in Settings > Safari. **No assets available during checkout** -- All inventory of that type is currently in use. Wait for a return or check the return board. **Card stuck in "In Progress"** -- If a staff member opened and then abandoned a checkout, the card stays in "In Progress." Tap it to resume, or close the modal to return it to "Ready." {% /callout %} --- # Walk-ups Source: https://docs.rentaltide.com/operations/walk-ups/ > Process walk-in rentals and monitor active on-the-water activity in real time The walk-ups page (also called the Nav Board) is a combined operations hub for starting same-day walk-in rentals and monitoring every active rental currently on the water. It is designed for dockside use on tablets and desktops. --- ## Nav board (active rentals) The main section of the page is the nav board -- a real-time table of all rentals currently on the water at your location. It refreshes every **15 seconds** with silent background updates. ### Nav board columns | Column | Description | | --------------------- | ----------------------------------------------------------------------------------------------------------------- | | **Inventory** | The asset type or inventory name (always visible, cannot be hidden) | | **Asset ID** | The specific assigned asset identifier | | **Customer** | Customer first and last name (always visible, cannot be hidden) | | **Departed** | The time the customer left the dock, shown in AM/PM format | | **Due Back** | The expected return time | | **Time Out / Status** | Live timer showing how long the rental has been active, plus urgency countdown (always visible, cannot be hidden) | Column visibility is configurable per-user per-location via the settings icon in the header. ### Color-coded urgency Rows are color-coded based on how close a rental is to its return time: | Urgency | Condition | Visual | | ------------- | ---------------------------------------- | ------------------------------------------ | | **Overdue** | Past the due-back time | Red background and border, "OVERDUE" badge | | **Due now** | 10 minutes or less until due back | Amber/warning background | | **Due soon** | 30 minutes or less until due back | Light amber tint | | **Normal** | More than 30 minutes remaining | No special highlighting | | **Departing** | Pre-departure countdown (check-in stage) | Light blue tint | ### Row details Each row also displays: - **Waiver chip** -- Green "Waiver" or orange "No waiver" indicator based on participant waiver status. - **Nav board tags** -- Custom colored tags applied during walk-up start (e.g. "Birthday", "VIP"). - **Dependent indicator** -- Warning icon with tooltip when the group includes minors or dependents. - **Notes icon** -- Visible when the booking has notes attached. --- ## Row actions Each active rental row has action buttons: | Action | Description | | ---------------------- | ---------------------------------------------------------------------------------------------------- | | **Stop** | Immediately stops the rental, transitioning it to the checkout flow | | **Extend** | Adds additional time (in configurable minute increments) to the rental | | **Swap asset** | Opens the asset swap dialog to change which physical asset is assigned without restarting the rental | | **Pause / Resume** | Pauses the rental timer (the row shows a pause icon when paused) | | **Convert to walk-up** | Converts a regular pre-booked rental into a walk-up for immediate processing | | **Open order** | Navigate to the full order details page | --- ## Starting a walk-up rental Tap the **"+ Walk-Up"** button to launch the walk-up wizard. The wizard is a multi-step dialog: ### Step 1: Select inventory Browse available inventory at your location. Each item shows: - Inventory name and image - Total assets vs. available assets - Seating capacity - Individual asset availability (available or in use) Select one or more inventory items and set the quantity for each. ### Step 2: Customer and group - Enter the primary customer's last name, or search for an existing renter in the system. - Add group members with their name, phone number, and email. - Group members can be marked as having an existing waiver on file. - Add custom nav board tags for visual identification on the board. - Optionally add notes that will appear on the booking. ### Step 3: Waiver - If your location requires waivers, participants are prompted to sign before departure. - The force-waiver option prevents proceeding until a waiver is completed. - Waivers can be signed on-device or sent via SMS for remote signing. ### Step 4: Asset assignment - Assign specific physical assets to each inventory item. - The system shows only available assets, preventing conflicts. - You can set block pricing categories and second-seat passenger categories if configured. ### Step 5: Launch - Review all selections and confirm. - The walk-up creates a booking, assigns assets, records the departure time, and the rental immediately appears on the nav board. --- ## Walk-up checkout When a walk-up rental is stopped, the checkout flow calculates the final price: 1. **Calculate price** -- The system computes pricing based on the actual time on the water. Hourly pricing uses overtime increments if configured. 2. **Review pricing** -- Each line item shows the inventory, actual minutes, billed hours, and calculated price. 3. **Collect payment** -- Accept payment via card, cash, or terminal. Tips can be added. 4. **Complete** -- The rental is finalized, the ledger is updated, and the booking moves to a completed status. --- ## Marine safety status The header displays current weather conditions fetched from OpenWeatherMap: | Condition | Status | | ------------------------------------------- | ---------------------------------------- | | Wind below threshold | **Good** -- safe conditions | | Wind above advisory threshold | **Caution** -- high wind advisory | | Wind above danger threshold or thunderstorm | **Dangerous** -- operations should pause | | Low visibility (below 5,000m) | **Caution** | The thresholds adjust automatically based on whether your location uses metric or imperial units. --- ## View modes Toggle between two layout modes using the header controls: | Mode | Description | | --------------- | ------------------------------------- | | **List view** | Traditional table rows (default) | | **Kanban view** | Board-style columns grouped by status | --- ## Upcoming departures Toggle **"Show Upcoming"** in the settings to display pre-departure bookings (check-in status) alongside active on-water rentals. These rows show a departure countdown (e.g. "Departs in 15m") instead of time-on-water. {% callout type="tip" %} The walk-up flow is optimized for speed. During busy periods, you can start a rental in under 30 seconds: select inventory, enter a last name, skip the waiver step if allowed, and launch. The nav board immediately shows the new rental with a live timer. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **No inventory shown in walk-up wizard** -- Check that your location has active inventory with available assets. All assets may be currently in use. **Pricing shows $0 or an error** -- Verify that the inventory has hourly pricing configured. The walk-up pricing engine requires valid pricing brackets. **Timer seems frozen** -- The timer display updates every 30 seconds. Wait a moment or manually refresh the board. {% /callout %} --- # Weather Source: https://docs.rentaltide.com/operations/weather/ > Current conditions, forecasts, and weather-related cancellation tools The weather page provides real-time weather data for your rental location, a 5-day forecast, and a one-click tool for cancelling all bookings on a weather-affected day. --- ## Current conditions The top section displays live weather data pulled from OpenWeatherMap, refreshing every **30 seconds**: | Metric | Description | | ----------------------- | ----------------------------------------------------------------------------------------------------- | | **Temperature** | Current temperature with feels-like reading, in your location's configured units (metric or imperial) | | **Weather description** | Conditions such as "Partly Cloudy", "Rain", or "Thunderstorm" with an icon | | **Humidity** | Current relative humidity percentage | | **Wind speed** | Wind speed and direction | | **Visibility** | Visibility distance | | **Pressure** | Atmospheric pressure | The weather location is automatically set based on your selected location's address. The system geocodes the address to find coordinates for the weather lookup. --- ## 5-day forecast Below the current conditions, a row of forecast cards shows daily projections for the next five days. Each forecast day includes: | Field | Description | | -------------- | ----------------------------------- | | **Date** | Day of the week and date | | **High / Low** | Temperature range for the day | | **Conditions** | Primary weather condition with icon | | **Humidity** | Average humidity for the day | | **Wind** | Expected wind speed and gusts | --- ## Weather cancellation Each forecast day card includes a **"Cancel All Bookings"** button. This tool is designed for weather emergencies -- storms, high winds, or unsafe conditions that force you to shut down operations for the day. ### How it works 1. Select the day you want to cancel (or use the "Cancel Today" option). 2. A confirmation dialog appears, warning that this will cancel all active bookings for that date at the selected location. 3. On confirmation, the system: - Cancels all active bookings for the selected date. - Issues gift card credits to affected customers (if configured). - Sends the configured weather cancellation email template (`booking_reschedule_weather`) to each customer. 4. A results dialog shows a summary: number of bookings cancelled, gift cards issued (with codes and amounts), and any errors. ### Requirements - You must have a specific location selected (not "All Locations"). - Your location must have a `booking_reschedule_weather` email template configured. - The button is disabled when either requirement is not met, with a tooltip explaining why. --- ## Location selection If "All Locations" is selected, the page shows an info alert prompting you to pick a specific location. Weather data is fetched based on the selected location's physical address, so a specific location must be chosen. --- ## Units Temperature and wind speed units follow your location's `units` setting: | Setting | Temperature | Wind | | ------------ | ----------- | ---- | | **metric** | Celsius | m/s | | **imperial** | Fahrenheit | mph | {% callout type="tip" %} The weather page auto-refreshes every 30 seconds. The "Last updated" timestamp below the refresh button shows exactly when the data was last fetched. Use this page as a dashboard on a screen at your front desk to monitor conditions throughout the day. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Weather data not loading** -- Ensure your location has a valid physical address set in Admin > Location Settings. The system geocodes this address to find weather data. **Cancel button disabled** -- Either select a specific location (not "All Locations") or set up the `booking_reschedule_weather` email template in your location's template settings. **Gift cards not issuing on cancellation** -- Gift card issuance depends on your cancellation policy configuration. Check that gift card settings are enabled for weather cancellations. {% /callout %} --- # Point of Sale Source: https://docs.rentaltide.com/pos/ > Ring up transactions, manage terminals, close tills, and run POS reports The RentalTide point of sale handles everything from retail and snack bar sales to rental payment collection. Process card, cash, and split payments through integrated Stripe terminals, then close out each shift with a full reconciliation report. {% cardGroup cols=3 %} {% card title="Register" href="/pos/register/" /%} {% card title="Till closing" href="/pos/cashout/" /%} {% card title="Transactions" href="/pos/transactions/" /%} {% card title="Invoices" href="/pos/invoices/" /%} {% card title="Terminals" href="/pos/terminals/" /%} {% card title="Inventory audit" href="/pos/inventory-audit/" /%} {% card title="Transfers" href="/pos/transfers/" /%} {% card title="Accounts receivable" href="/pos/accounts-receivable/" /%} {% card title="POS reporting" href="/pos/reporting/" /%} {% /cardGroup %} --- # Accounts receivable Source: https://docs.rentaltide.com/pos/accounts-receivable/ > Track outstanding customer balances and collect payments Accounts receivable (AR) gives you a clear view of every customer who owes money, organized by aging bucket. See outstanding balances, drill into individual ledger histories, and export the data for your accounting team. --- ## Accessing AR Navigate to **POS > Accounts Receivable**. The page requires the `pos_accounts_receivable_access` permission. Data is pulled from the accounting ledger and includes all unpaid charges across POS transactions, bookings, and account settlements. --- ## Summary cards Five clickable cards appear at the top of the page, showing totals by aging bucket: | Card | What it shows | | --------------------- | -------------------------------------------------------- | | **Total Outstanding** | The sum of all unpaid customer balances (always visible) | | **Current** | Balances from charges made in the last 30 days | | **30 Days** | Balances from charges 30-60 days old | | **60 Days** | Balances from charges 60-90 days old | | **90+ Days** | Balances from charges older than 90 days | Click a card to filter the customer list to only show customers with balances in that aging bucket. Click the same card again (or click "Total Outstanding") to clear the filter. --- ## Filtering and sorting ### Search Type in the search field to filter customers by first name, last name, email address, or phone number. ### Sort options Sort the customer list by: - **Balance (high to low)** -- default sort, prioritizes largest balances - **Balance (low to high)** -- smallest balances first - **Name (A-Z)** -- alphabetical by customer name - **Oldest debt** -- customers with the oldest unpaid charges appear first ### Reset Click **Reset** to clear the search, aging filter, and sort back to defaults. --- ## Customer list Each customer row displays: - **Name** -- first and last name - **Email** -- contact email address - **Phone** -- phone number (if available) - **Balance** -- total outstanding amount - **Aging breakdown** -- individual amounts in each aging bucket (Current, 30, 60, 90+) - **Entry count** -- number of outstanding ledger entries Only customers with balances of $1.00 or more are shown. ### Expanding a customer Click a customer row to expand it and load their detailed ledger history. The expanded view shows: - Individual ledger entries with dates, descriptions, and amounts - Debit and credit entries - Running balance - Related booking or transaction references --- ## Exporting Click the **Export CSV** button to download the AR aging report. The export includes: | Column | Description | | -------- | ----------------------------- | | Name | Customer full name | | Email | Customer email address | | Phone | Phone number | | Balance | Total outstanding | | Current | Amount in the current bucket | | 30 Days | Amount in the 30-day bucket | | 60 Days | Amount in the 60-day bucket | | 90+ Days | Amount in the 90+ day bucket | | Entries | Number of outstanding entries | The export respects all active filters, so you can generate a report for a specific aging bucket or search result. --- ## Collecting payment Outstanding balances can be collected through several methods: - **From the POS register** -- select the customer account, then use **Settle Balance** or **Custom Amount** to charge the outstanding amount via card, cash, or terminal - **Send an invoice** -- create a Stripe invoice from the register and email it to the customer for online payment - **Card on file** -- charge a saved payment method directly from the register All payments are recorded in the accounting ledger and reduce the customer's outstanding balance. --- ## Saved payment methods Customers with cards on file can be viewed in the AR detail panel. The saved payment methods section shows card brand, last four digits, and expiration date. --- ## Troubleshooting {% callout type="tip" %} Review the AR aging report weekly to stay on top of collections. Customers in the 90+ day bucket are the hardest to collect from -- prioritize outreach to the 30- and 60-day buckets before balances age further. The AR list respects your location filter, so multi-location operators can review each site independently. {% /callout %} {% callout type="warning" title="Common issues" %} **Balance looks wrong** -- Check for partial payments, credits, or refunds that may have been applied. Expand the customer row to see the full ledger history with individual debits and credits. **Customer not showing** -- Only customers with balances of $1.00 or more appear. Balances below that threshold are excluded. Also check that you are viewing the correct location. **Cannot charge saved card** -- The card on file may be expired or the customer may not have a saved payment method. Send an invoice or payment link instead. {% /callout %} --- # Till closing Source: https://docs.rentaltide.com/pos/cashout/ > Count cash, reconcile transactions, and close out each shift Till closing (cashout) is the end-of-shift reconciliation process. Review all unsettled transactions for the day, count the physical cash in each drawer, record any discrepancies, and settle the batch. When accounting integrations are active, the daily summary is automatically synced to Xero, QuickBooks, or Wave. --- ## Accessing till closing Navigate to **POS > Till Closing**. The page requires the `pos_cashout_access` permission. A specific location must be selected -- the "All Locations" view prompts you to choose one before proceeding. --- ## Current tab The **Current** tab shows all unsettled transactions for the selected date range along with summary cards and payment breakdowns. ### Summary cards Three cards appear at the top of the page: | Card | What it shows | | -------------------------- | -------------------------------------------------------- | | **Date Range** | The start and end dates currently selected | | **Location** | The name of the active location | | **Unsettled Transactions** | The count of transactions that have not yet been settled | ### Payment summary Below the summary cards, the page breaks down unsettled transactions by payment method (cash, credit, debit, account, gift card, etc.). For credit card transactions, the breakdown is further split by card brand (Visa, Mastercard, Amex, etc.), showing the total amount and count for each. ### Till breakdown If the location has registered tills, transactions are automatically grouped by till. Each till shows: - Till name - Total amount and transaction count - Payment type breakdown within that till - Transactions with no matching till are grouped under "Unknown/No Till" ### Cash drawer breakdown Locations with configured cash drawers see a more detailed view. Each drawer shows: - Drawer name and the tills assigned to it - Expected float and current float - Cash amount vs. card amount vs. other payment types - Individual payment method breakdown Drawers without any tills assigned collect "card/digital only" transactions. --- ## Closing the till 1. Review the payment summary and verify the transaction counts look correct. 2. Click **Cash Out** (or the cash-out button for a specific drawer). 3. In the **Cash Out Dialog**, enter the **counted cash** -- the physical amount in the drawer. 4. The system displays the **expected cash** calculated from all cash transactions in the period. 5. The **difference** (over or short) is calculated automatically. 6. Optionally enter a breakdown by denomination ($100, $50, $20, etc.). 7. Click **Confirm** to settle all transactions in the range. ### What happens on cashout When you confirm the cash out: 1. All unsettled transactions in the date range are marked as **settled** via the `settle-range` API endpoint. 2. The counted cash, expected cash, and difference are recorded. 3. If **Xero** integration is active, a daily summary journal entry is synced automatically. 4. If **QuickBooks** integration is active, a daily summary is synced to QuickBooks. 5. If **Wave** integration is active, a daily summary is synced to Wave. 6. The transaction list refreshes to reflect the settled status. If any accounting sync fails, the cashout itself still completes -- you receive a warning with the sync error details. --- ## History tab The **History** tab shows previous cashout records for the selected date range. Each entry includes: - Date and time of the cashout - Counted cash and expected cash - Over/short amount - Staff member who performed the cashout - Drawer name (if applicable) Use the history to track trends in cash discrepancies over time and identify potential issues. --- ## Date filtering Use the date picker at the top of the page to set the period you want to reconcile. The dates default to today. When you change the date range, transactions are re-fetched from the accounting ledger to ensure accuracy. --- ## Troubleshooting {% callout type="tip" %} Set a consistent **opening float** so each shift starts with the same cash amount. Close the till at the end of every shift -- not just at the end of the day -- to keep accountability tight. You can run multiple cashouts per day if shifts overlap. {% /callout %} {% callout type="warning" title="Common issues" %} **Large discrepancy** -- Review all transactions for the period. Look for voided or refunded cash transactions that may explain the difference. Check whether any no-sale events were recorded. **Cannot close the till** -- Till closing requires the `pos_cashout_access` permission. Ask an admin to grant this permission to your staff role. **Accounting sync failed** -- The cashout still completes even if Xero/QuickBooks/Wave sync fails. Check your integration credentials under **Admin > Integrations** and retry the sync manually. **No transactions showing** -- Verify the date range is correct and that you have selected the right location. Transactions from "All Locations" view are not available for cashout. {% /callout %} --- # Inventory audit Source: https://docs.rentaltide.com/pos/inventory-audit/ > Count physical inventory, identify discrepancies, and maintain accurate stock levels Inventory audits reconcile your physical stock with the quantities recorded in the system. The audit page provides both a grid view (card-based counting) and a list view (table-based counting), with support for till-level and location-level inventory tracking. --- ## Accessing the audit Navigate to **POS > Inventory Audit**. The page has two tabs: - **Inventory** -- view current stock levels without entering counts - **Audit** -- enter physical counts and identify discrepancies Switch to the **Audit** tab to start counting. --- ## Filtering inventory Before counting, use the filter bar to narrow down which items to audit: | Filter | Options | | ------------------ | ----------------------------------------------------------------------- | | **Search** | Filter by product name, SKU, or category | | **Category** | Show only items in a specific category | | **Stock level** | All, In Stock, Low Stock (10 or fewer), or Out of Stock | | **Inventory type** | All, Location-level, or Till-level | | **Till** | When a till is selected, shows only items tracked at that specific till | --- ## Counting methods ### Grid view (card-based) Each product appears as a card showing: - Product image, name, SKU, category, and price - **System Stock** -- the quantity the system expects, color-coded: - Green for normal stock levels - Orange for low stock (10 or fewer) - Red for out of stock (0) - **Count** -- use the **+** and **-** buttons or type a number directly - **Counted** chip -- appears after you enter a count - **Discrepancy indicator** -- shows the difference between counted and expected: - Green with up arrow for overages - Red with down arrow for shortages ### List view (table-based) A traditional table with columns for inventory type icon, SKU, name, category, variant, price, system stock, and a count input field. When no till is selected and tills exist, additional columns show per-till inventory levels. Toggle between views using the grid/list icons in the toolbar. --- ## Running an audit 1. Select the **Audit** tab. 2. Choose the **till** or **location** level to audit. 3. Filter by category or stock level if you want to count a subset of items. 4. For each item, enter the **actual count** on hand using the counter controls. 5. Review discrepancies -- the system highlights items where the counted quantity differs from the expected quantity. 6. Click **Complete Audit** to finalize. ### Discrepancy details When a discrepancy is detected, the card shows: - The difference (e.g., +3 Overage or -2 Shortage) - The **shrinkage value** -- the cost impact of the discrepancy, calculated as the difference multiplied by the item's cost price --- ## Syncing inventory The audit page includes a **Sync** button that refreshes inventory data from the server. Use this after receiving new stock or if you suspect the displayed quantities are stale. For locations with Xero integration, a sync-from-Xero option pulls the latest stock levels from your Xero inventory items. --- ## Printing Click the **Print** icon to generate a printable inventory report. The report includes all currently filtered items with their stock levels, costs, and category assignments. --- ## Exporting Click **Download** to export the current inventory view as a CSV file. The export includes: - Product name, SKU, category - Current quantity, price, cost - GL code - Per-till inventory levels (if applicable) --- ## Troubleshooting {% callout type="tip" %} Schedule regular audits -- weekly for high-volume items, monthly for slower categories -- to catch shrinkage early. Use the grid view on tablets for fast counting in the stockroom, and the list view on desktop for detailed review. Filter by "Out of Stock" to quickly identify items that need reordering. {% /callout %} {% callout type="warning" title="Common issues" %} **Counts not saving** -- Make sure you click **Complete Audit** after entering all counts. Simply entering numbers does not update system quantities until the audit is finalized. **Wrong stock level showing** -- Click **Sync** to refresh from the server. If the issue persists, check whether a recent transfer or sale was not recorded properly. **Till inventory not matching location inventory** -- Items with `inventoryType: till` are tracked separately at each till. A product's location-level quantity may differ from the sum of its till-level quantities if transfers have not been completed. {% /callout %} --- # Invoices Source: https://docs.rentaltide.com/pos/invoices/ > Send, track, and manage Stripe-powered invoices Invoices let you bill customers for products, services, or custom charges and collect payment via email. RentalTide invoices are powered by Stripe Invoicing -- customers receive a professional hosted payment page, and payments are automatically reconciled. --- ## Sending an invoice Invoices are created from the POS register during checkout: 1. Add items to the cart on the register. 2. Optionally attach a customer account. 3. Select **Invoice** as the payment method (under **More** options). 4. In the **Send Invoice** dialog: - Enter the customer's **email address** and **name** (pre-filled if a customer account is attached). - Choose a **due date**: 7, 14, 30, 60, or 90 days from today. - Add an optional **memo** for context. 5. Click **Send**. The invoice is created in Stripe and emailed to the customer. They receive a link to a Stripe-hosted payment page where they can pay by card. ### Settlement invoices You can also invoice a custom amount without cart items. When in **Custom Amount** mode on the register, the invoice sends a single line item with the entered amount and note -- useful for billing outstanding balances or services not in the catalog. --- ## Viewing invoices Navigate to **POS > Invoices** to see all invoices sent from your locations. The page shows a searchable, filterable list of invoices with key details visible at a glance. ### Search and filter - **Search** by customer name or email address. - **Status filter** -- click a status chip to show only invoices in that state. Available filters: All, Open, Paid, Void, Uncollectible. - The total count of matching invoices is displayed next to the filters. ### Invoice row Each invoice row displays: - Customer name and email - Total amount - Status chip (color-coded) - Created date - Due date (for open invoices) - Paid date (for paid invoices) Click a row to expand it and see full details. --- ## Invoice statuses | Status | Description | Color | | ----------------- | ------------------------------------------------ | ----- | | **Draft** | Created but not yet sent. Can be edited freely. | Gray | | **Open** | Sent to the customer and awaiting payment. | Blue | | **Paid** | Customer has completed payment. | Green | | **Void** | Cancelled before payment. No longer collectible. | Gray | | **Uncollectible** | Marked as unlikely to be collected. | Red | --- ## Managing invoices Expand an invoice row to see line items with quantities and prices, subtotal, tax, and total. Available actions depend on the invoice status: ### Open invoices - **Resend** -- re-sends the payment email to the customer (envelope icon) - **Void** -- cancels the invoice so it can no longer be paid (block icon). A confirmation dialog appears before voiding. This action cannot be undone. - **View** -- opens the Stripe-hosted invoice page in a new browser tab (external link icon) ### Paid, void, or uncollectible invoices - **View** -- opens the invoice in Stripe (if a hosted URL is available) --- ## Invoice details The expanded view shows: - **Memo** -- any notes attached when the invoice was sent - **Line items** -- each product or service with name, quantity, and line total - **Subtotal** -- sum of all line items before tax - **Tax** -- tax amount (if applicable) - **Total** -- final amount due --- ## Permissions The invoices page requires the `pos_access` permission. Creating and sending invoices is done through the register, which requires `pos_add_transaction`. --- ## Troubleshooting {% callout type="tip" %} Invoices are ideal for deposit collection, balance-due billing, or sending charges to customers who are not on-site. All invoice payments appear in your Stripe dashboard alongside other transactions for easy reconciliation. {% /callout %} {% callout type="warning" title="Common issues" %} **Customer did not receive the invoice** -- Verify the email address is correct and ask the customer to check their spam folder. Use the **Resend** action to re-send. **Wrong amount on a sent invoice** -- If the invoice is still open, void it and create a new one with the correct amount from the register. **No invoices showing** -- Invoices are filtered by location. Make sure you have the correct location selected, or switch to "All Locations" to see invoices across all sites. {% /callout %} --- # Register Source: https://docs.rentaltide.com/pos/register/ > Browse products, build a cart, and process payments at the point of sale The POS register is a full-featured checkout interface for ringing up retail items, snack bar orders, walk-up rentals, and custom charges. Products display as a tile grid inspired by Square POS, with a persistent cart sidebar for reviewing items and selecting a payment method. --- ## Product catalog Products appear as tiles organized into folders and categories. Each tile shows the product name, price, and an image (if configured). Tiles are color-coded by folder and display a badge when items are already in the cart. ### Browsing - **Folders** -- tap a folder tile to open it and see the products inside. Favorite folders appear first on the home screen. Use the breadcrumb at the top to navigate back. - **Categories** -- use the category filter bar to narrow the grid to a single category such as Drinks, Merchandise, or Gasoline. - **Search** -- type into the search bar to filter by product name or SKU. Results update as you type. - **Featured products** -- drag and drop products into the featured section to pin them to the register home screen for fast access. ### Product tiles Tap a tile to add one unit to the cart. If the product has multiple variants (e.g., sizes or colors), a variant selection dialog opens so you can choose the correct option and set a quantity before adding. Products with per-till inventory tracking show the stock level for the currently selected till. Out-of-stock items are dimmed but can still be added if the product allows negative quantities. --- ## Building the cart The cart sidebar occupies the right side of the screen on desktop and slides up as a drawer on mobile. Each cart item displays the product name, unit price, quantity, and line total. | Cart feature | How it works | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- | | Adjust quantity | Type a new number in the quantity field or use the increment/decrement controls | | Remove item | Click the trash icon that appears on hover | | Miscellaneous item | Click **Misc Item** to add a one-off line item with a custom name, price, quantity, GL code, and tax toggle | | Walk-up rentals | When navigating to the register from the Nav Board, rental line items are pre-populated in the cart with pricing from the hourly calculator | | Gasoline | Gasoline products accept decimal quantities (e.g., 12.345 gallons) | ### Discounts and promo codes - Enter a **promo code** in the discount field to apply a percentage or fixed-amount discount. - Customers linked to a **customer group** receive automatic group pricing on eligible products. - **Loyalty points** can be redeemed at checkout if the customer has earned points through the loyalty program. - Managers can manually set a discount percentage from the account summary section. --- ## Selecting a customer Tap **Account** in the payment method row to search for and attach a customer to the transaction. Once a customer is selected, the cart sidebar shows: - Customer name and email - Outstanding balance (if any) - Active membership status - Loyalty points balance - Store credit available - Linked bookings (select one to attach the transaction to a specific rental) Attaching a customer enables additional payment methods such as **Account (tab)**, **Card on File**, and **Settle Balance**. --- ## Payment methods Select a payment method from the row of buttons below the cart summary. The primary options are always visible; tap **More** to reveal additional methods. | Payment method | Description | | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Cash** | Opens the cash payment dialog with denomination buttons ($100, $50, $20, $10, $5, $2, $1, quarters, dimes, nickels, pennies). The register calculates change automatically. | | **Card** | Sends the charge to the connected Stripe terminal. The customer taps, inserts, or swipes on the reader. Tipping is presented on the reader if enabled. | | **Tap to Pay** | Uses Tap to Pay on iPhone to accept contactless payments directly on your device -- no hardware reader required. Only appears when the device supports it. | | **Account** | Charges the amount to the customer's tab (accounts receivable). Requires a customer to be selected. | | **Card on File** | Charges a card already saved to the customer's account. Requires a customer with a saved payment method. | | **Check** | Records a check payment with the check number for reference. Can be disabled per location. | | **Pre-Auth** | Captures a previously authorized hold (e.g., a damage deposit from a rental booking). Shows the available pre-auth amount. | | **Custom Amount** | Prompts for a specific dollar amount and optional note. Useful for settling partial balances or charging for services not in the catalog. | | **Gift Card** | Enter the gift card code to check the balance and apply it toward the total. If the gift card does not cover the full amount, the remainder can be paid with another method. | | **Invoice** | Creates a Stripe invoice and emails it to the customer. Set a due date (7, 14, 30, 60, or 90 days) and add a memo. | | **No Sale** | Opens the cash drawer without processing a transaction. Records a no-sale event for audit purposes. | ### Split payments Toggle **Split Payment** to divide the total across multiple transactions. Choose between even splits (e.g., 3 ways) or custom amounts per split. Each split can use a different payment method. --- ## Processing fees Card transactions may include processing fees depending on your location settings: - **Interchange fee** -- the card network fee (percentage + flat rate per transaction) - **Application fee** -- the platform processing fee These fees can be passed through to the customer or absorbed by the business. The fee breakdown appears in the cart summary before checkout. Cash, check, and account payments do not incur processing fees. --- ## Receipts After a successful transaction, a receipt modal appears with options to: - **Print** -- sends the receipt to a connected receipt printer - **Email** -- sends a digital receipt to the customer's email address - **Skip** -- closes the receipt without printing Receipts show the location logo, custom header text, line items with quantities and prices, tax breakdown, payment method, card details (last four digits, card brand, auth code), and custom footer text. Receipt customizations are configured in your location settings. --- ## Tabs (save for later) Save an in-progress cart as a named **tab** to come back to it later. Tabs persist across sessions and can be loaded from the cart sidebar. This is useful for bar tabs, layaway, or multi-visit transactions. - **Save Tab** -- saves the current cart with a name - **Load Tab** -- restores a previously saved tab into the cart - **Abandon Tab** -- deletes a saved tab without processing it --- ## Keyboard shortcuts | Shortcut | Action | | ----------------- | ----------------------------------------------------------------------------------------- | | **Ctrl+R** | Open the terminal refund dialog (requires terminal connection and transaction permission) | | **Type anywhere** | Jumps to product search | --- ## Troubleshooting {% callout type="warning" title="Common issues" %} **Products not showing** -- Verify that items are added to your POS inventory and assigned to the correct location. Products must have at least one variant with a price. **Reader not connecting** -- Check that the terminal is powered on and connected to the same Wi-Fi network. See [Terminals](/pos/terminals) for pairing instructions. **Tax amount is wrong** -- Tax rates are set at the location level under **Admin > Location Settings**. Each product variant can also have specific tax rates assigned. **Cannot process a refund** -- Refunds require the `pos_add_transaction` permission. Kiosk-restricted users cannot process refunds without a manager PIN. **Walk-up cart not loading** -- Ensure you navigated to the register from the Nav Board stop button. The walk-up checkout data is passed via browser navigation state and is cleared on page refresh. {% /callout %} --- # POS reporting Source: https://docs.rentaltide.com/pos/reporting/ > Generate and export financial, tax, and transaction reports POS reporting provides structured exports of your transaction, booking, and financial data. Select a report type, configure filters, and download the results as CSV or JSON for accounting, tax filing, or internal review. --- ## Accessing reports Navigate to **POS > Reporting**. The page requires staff-level permissions and shows all available report types as cards. Each card describes what the report includes and provides a download button. --- ## Available reports | Report | Description | Key filters | | --------------------- | ---------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | | **Bookings Export** | All bookings with dates, amounts, statuses, and customer details | Date range, booking status, format | | **Journal Entries** | Double-entry ledger entries with GL codes, debits, and credits | Date range, account code, booking ID, format | | **POS Transactions** | Every register transaction with line items, payment methods, and settlement status | Date range, payment type, settled/unsettled, format | | **Financial Summary** | Revenue, refunds, discounts, and net totals aggregated by period | Date range, group by (daily/weekly/monthly), format | | **Tax Report** | Tax collected broken down by rate and category | Date range, tax type, refund/zero-tax/exempt toggles, group by, format | | **Tips Report** | Daily breakdown of tips from POS and booking payments | Date range, format | --- ## Running a report 1. Set the **date range** using the start and end date pickers. Defaults to the last 30 days. 2. Apply **filters** specific to the report type (see below). 3. Choose the **format**: CSV (spreadsheet) or JSON (raw data). 4. Click **Download** on the report card. The file downloads immediately. The filename includes the report type and a timestamp (e.g., `pos_transactions_2026-04-07_14-30-00.csv`). --- ## Filter reference ### Booking status filter Available for the Bookings Export. Options: All Statuses, Pending, Confirmed, In Progress, Completed, Cancelled, No Show. ### Payment type filter Available for the POS Transactions report. Options: All Payment Types, Card, Cash, Refund, Refund (Cash), Refund (Account), Gift Card, Terminal, Additional Charge, Remaining Balance. ### Account code filter Available for the Journal Entries report. Filter by specific GL accounts: | Code | Account | | ---- | ------------------- | | 1010 | Cash | | 1120 | Accounts Receivable | | 3053 | PST Payable | | 3055 | GST Payable | | 3056 | HST Payable | | 3057 | QST Payable | | 4010 | Revenue | | 4020 | Refunds | | 5010 | Merchant Fees | ### Settlement filter Available for the POS Transactions report. Options: All Transactions, Settled Only, Unsettled Only. ### Group by Available for the Financial Summary and Tax Report. Options: Daily, Weekly, Monthly. ### Tax report toggles The tax report includes additional boolean filters: - **Include refunds** -- factor refunded amounts into the tax totals (default: on) - **Include zero-tax items** -- show line items that were not taxed (default: off) - **Include tax-exempt items** -- show items with tax-exempt status (default: on) - **Include voided** -- include voided transactions (default: off) ### Tax type filter Filter tax data by specific tax type: All, GST Only, PST Only, HST Only, QST Only. --- ## Location filtering Reports respect the active location selection in the header. When a specific location is selected, the report includes only data from that location. When "All Locations" is selected, the location filter is omitted and data from all sites is included. --- ## Keyboard shortcut Press **Ctrl+L** (or **Cmd+L** on Mac) from the reporting page to open the general ledger management page in a new tab for a real-time view of all account balances. --- ## Troubleshooting {% callout type="tip" %} Schedule regular report exports to keep your accountant or bookkeeper in sync. The journal entries export is the most detailed option for reconciliation -- each entry includes balanced debits and credits with GL codes that map to your chart of accounts. {% /callout %} {% callout type="warning" title="Common issues" %} **Report is empty** -- Expand the date range. Reports only include data that falls within the selected dates and matches all active filters. Check that the correct location is selected. **Numbers do not match Stripe** -- Pending transactions may not yet be settled. Compare against the same date range in the Stripe dashboard and check for processing delays. Interchange and application fees may also cause differences. **CSV not opening correctly in Excel** -- Import the file as a CSV rather than double-clicking it. In Excel, use **File > Import** or **Data > From Text/CSV** and select comma-delimited format to ensure columns parse correctly. **JSON export is too large** -- For very large date ranges, the JSON file may be several megabytes. Consider using CSV format or narrowing the date range to reduce file size. {% /callout %} --- # Terminals Source: https://docs.rentaltide.com/pos/terminals/ > Pair, configure, and manage Stripe card readers for in-person payments Terminals are the physical Stripe card readers connected to your RentalTide register. Pair a reader once, and it is available for every POS transaction at that location. RentalTide supports the Stripe S700, S710, WisePOS E, Verifone P400, and Tap to Pay on iPhone. --- ## Pairing a reader 1. Navigate to **POS > Terminals**. 2. Click **Pair Reader**. 3. Select the **location** to assign the reader to. 4. Enter the **registration code** displayed on the reader screen. 5. Click **Register**. The system creates a Stripe location (if one does not already exist for the selected location) and registers the reader. Both the reader and your device must be on the same Wi-Fi network for the initial pairing. --- ## Managing readers The terminal page displays a table of all paired readers with the following columns: | Column | Description | | ----------------- | ----------------------------------------------------- | | **Name** | The label assigned to the reader | | **Device Type** | Hardware model (S700, S710, WisePOS E, Verifone P400) | | **Serial Number** | The reader's hardware serial number | | **Status** | Current connection state (online/offline) | | **Location** | Which business location the reader is assigned to | ### Editing a reader Click **Edit** to change the reader's label or reassign it to a different location. The label appears on the reader selection screen during checkout. ### Deleting a reader Click **Delete** to unpair the reader from your account. A confirmation dialog appears before the reader is removed. Deleted readers can be re-paired using the registration code process. ### Configuring a reader Click the settings icon to open the per-reader configuration dialog. Each reader can override location-level defaults or inherit them. --- ## Reader configuration The configuration dialog provides settings organized by section: ### Splash screen - **Default** -- uses the location-level background image - **Custom** -- upload a reader-specific background image. Resolution requirements: - S700: 1080 x 1920 - S710: 1080 x 2400 - **Overlay name** -- toggle to display the reader's label on the splash screen ### Tipping - **Default** -- inherits the location's tipping configuration - **Custom** -- set reader-specific tipping preferences: - Enable or disable the tip screen - Set up to three suggested tip percentages (e.g., 15%, 18%, 20%) ### Cart display - **Default** -- inherits the location setting - **Custom** -- enable or disable showing the cart on the reader screen during checkout, and set how long (in seconds) the cart is displayed ### Cellular connectivity Enable cellular data for readers that support it (S710). When enabled, the reader maintains connectivity even when Wi-Fi is unavailable. Cellular service costs approximately $10-15/month depending on currency (USD $10, CAD $14, AUD $15). --- ## Location-level defaults Below the reader list, the terminal page provides location-wide settings that apply to all readers unless overridden per-reader: ### Default tipping 1. Toggle **Tipping** on or off for the location. 2. Set three **suggested tip percentages** (e.g., 15%, 18%, 20%). 3. Click **Save**. ### Default splash screen Upload a background image that displays on all readers at the location. Two image slots are available: - **S700 background** (1080 x 1920 resolution) - **S710 background** (1080 x 2400 resolution) Images are uploaded to S3 and cropped with the image cropper tool before saving. ### Terminal admin PIN Set the PIN code required to access the terminal's admin settings menu. Default is `07139`. ### Reboot window Configure the time window during which readers may automatically reboot for maintenance. Set the start hour and end hour (24-hour format). Default is 12:00 AM to 2:00 AM. ### Cart display Toggle whether the customer-facing screen on the reader shows the cart items during checkout, and set the display duration in seconds. --- ## Ordering hardware Click **Order Terminal** to request new reader hardware. The order dialog includes: - Device selection with quantities (S700, S710) - Payment options: purchase, finance (6 months at 9.99% APR), or lease ($35/month for 24 months) - Shipping address - Cost breakdown with subtotal, shipping, recycling fee, and tax Terminal orders are tracked on the page with status updates, tracking numbers, and invoice generation for your records. SuperAdmin users can link Stripe hardware order IDs and update tracking information. --- ## Troubleshooting {% callout type="tip" %} Firmware updates are applied automatically when the reader is idle and connected to Wi-Fi. The S700 is portable and battery-powered, making it ideal for dock-side payments. Tap to Pay on iPhone turns any supported iPhone into a contactless reader with no additional hardware -- it appears as a payment option on the register when the device supports it. {% /callout %} {% callout type="warning" title="Common issues" %} **Reader not connecting** -- Confirm the reader is powered on and connected to the same Wi-Fi network as your register device. Restart the reader if it has been idle for an extended period. **Reader shows offline** -- The reader lost its Wi-Fi connection. Reconnect it to the network and it will come back online automatically. Readers with cellular enabled maintain connectivity even without Wi-Fi. **Tip screen not appearing** -- Verify that tipping is enabled in either the reader-specific settings or the location default settings. Older firmware versions may not support the tip screen. **Splash screen not updating** -- After uploading a new background image, save the configuration and allow a few minutes for the reader to download the update. The reader must be connected and idle. **Pairing fails** -- Ensure the registration code on the reader screen has not expired. Codes are time-limited. Generate a new code on the reader by navigating to its settings menu. {% /callout %} --- # Transactions Source: https://docs.rentaltide.com/pos/transactions/ > Search, filter, and manage all POS transaction records The transactions page is a searchable ledger of every POS transaction processed at your locations. Find any sale, refund, or settlement by ID, customer name, or item name -- then drill into details, reprint a receipt, issue a refund, or sync to your accounting platform. --- ## Searching and filtering Use the filter bar at the top of the page to narrow results: | Filter | What it does | | -------------- | ----------------------------------------------------------------------------------------------------------- | | **Search** | Find transactions by transaction ID, user ID, item name, or SKU | | **Date range** | Filter to a specific start and end date. Defaults to yesterday through tomorrow to capture the current day. | | **Sort order** | Toggle between newest-first and oldest-first | | **Till** | Filter by a specific registered till, or show all tills | The search and date range can be combined. Click **Reset** to clear all filters back to defaults. --- ## Transaction list Each transaction row displays: - **Transaction ID** -- the unique identifier - **Date and time** -- when the transaction was processed - **Items** -- the products included with quantities and prices - **Amounts** -- subtotal, tax (with per-rate breakdown if available), discounts, tip, and total - **Payment method** -- cash, credit, debit, account, gift card, settlement, etc. - **Card details** -- brand, last four digits, and authorization code (for card payments) - **Staff** -- the user who processed the transaction - **Till** -- which till/register processed the sale ### Settlement transactions Account settlements (paying off a tab) are displayed with additional fields: - Account holder name - Balance before and after the settlement - Settlement amount ### Ledger entries When a date range is selected, transactions are fetched from the accounting ledger endpoint, which returns both the transaction records and their corresponding double-entry journal entries. The ledger data powers the export options and provides GL code-level detail. --- ## Transaction actions From each transaction row, the following actions are available: ### Reprint receipt Click the receipt icon to reopen the receipt modal for any past transaction. The receipt uses the receipt customization settings (logo, header, footer) from the location where the transaction was originally processed -- not the currently selected location. ### Process a refund 1. Click the **Refund** button on the transaction row. 2. Choose **Full refund** or **Partial refund**. 3. For partial refunds, enter the amount to refund. 4. If the transaction included a gift card payment, choose how to split the refund between the card and gift card portions. 5. Click **Confirm**. The refund is processed back to the original payment method. A refund receipt is generated automatically. The transaction record is updated with the refund amount, and partially refunded transactions show the remaining refundable balance. ### Sync to Xero If your business has an active Xero integration, a sync button appears on each transaction. Click it to push the transaction to Xero as a journal entry. The sync status is displayed on each row: - **Pending** -- sync has been initiated - **Synced** -- successfully synced to Xero - **Failed** -- sync failed (hover for error details) --- ## Exporting Click the **Export** button to download transaction data. Three export formats are available: | Export type | What it includes | | ---------------------- | ------------------------------------------------------------------------------------- | | **Transactions CSV** | All filtered transactions with amounts, payment methods, items, and timestamps | | **Ledger Entries CSV** | Double-entry journal entries with GL codes, debits, and credits (requires date range) | | **Detailed Export** | Combined transaction and ledger data in a single file | Exports respect all active filters, so you can generate targeted reports for specific date ranges, payment methods, or tills. --- ## Permissions The transactions page requires the `pos_transactions_access` permission. Users in kiosk-restricted mode have limited functionality -- certain actions like refunds may require a manager override. --- ## Troubleshooting {% callout type="tip" %} Booking payments collected through the register also appear here, giving you a unified view of all revenue. Transaction IDs link to the corresponding Stripe payment for quick reconciliation. Use the till filter to review transactions from a specific register during shift changes. {% /callout %} {% callout type="warning" title="Common issues" %} **Missing transaction** -- Check that your date filter includes the correct range. The default range is yesterday through tomorrow -- expand it if looking for older transactions. **Export is empty** -- The ledger export requires a date range to be selected. Set start and end dates before exporting. **Refund not available** -- The refund button is hidden for transactions that have already been fully refunded. Check the refund amount on the transaction detail to verify. **Xero sync button not showing** -- Verify that your Xero integration is active under **Admin > Integrations**. The sync button only appears when `customer.integrations.xero.isActive` is true. {% /callout %} --- # Transfers Source: https://docs.rentaltide.com/pos/transfers/ > Move inventory between locations and tills Transfers track the movement of inventory between locations, tills, and external suppliers. Create a transfer to receive new stock, move products between locations, or restock a specific till from your main inventory. --- ## Accessing transfers Navigate to **POS > Transfers**. The page shows all transfers for the selected location, organized into tabs by status. --- ## Transfer statuses | Status | Description | | ------------- | -------------------------------------------------------------------------------------------------------- | | **Pending** | Transfer has been created but not yet completed. Items have not been moved in the system. | | **Completed** | Transfer has been finalized. Inventory quantities have been adjusted at both the source and destination. | | **Cancelled** | Transfer was cancelled before completion. No inventory changes were made. | Use the tabs at the top of the page to filter by status. --- ## Creating a transfer 1. Click **New Transfer**. 2. Configure the transfer: | Field | Description | | -------------------- | ---------------------------------------------------------------------------------------- | | **Source type** | Where inventory is coming from: Location, Till, or External (supplier/vendor) | | **Source** | The specific location or till to pull inventory from (not required for external sources) | | **Destination type** | Where inventory is going: Location or Till | | **Destination** | The specific location or till to receive inventory | | **Transfer date** | The date of the transfer | | **Reference number** | Optional reference for tracking (e.g., purchase order number) | | **Notes** | Optional notes about the transfer | 3. **Add items** to the transfer: - Select an inventory item from the dropdown - Choose a variant (if the item has variants) - Set the quantity to transfer - Click **Add** to include the item 4. Review the items list and click **Create Transfer**. ### Source and destination combinations - **External to Location** -- receiving new stock from a supplier - **External to Till** -- receiving stock directly to a specific till - **Location to Location** -- moving products between business sites - **Location to Till** -- restocking a till from the main location inventory - **Till to Location** -- returning items from a till back to the main inventory - **Till to Till** -- moving stock between tills at the same location --- ## Completing a transfer Pending transfers must be completed to update inventory quantities: 1. Find the pending transfer in the list. 2. Click **Complete**. 3. The system adjusts inventory at both the source (decrease) and destination (increase). If any errors occur during completion (e.g., insufficient source stock), the transfer still completes but a warning is displayed with error details. --- ## Cancelling a transfer Click **Cancel** on a pending transfer to cancel it. Cancelled transfers remain in the history for reference but do not affect inventory quantities. --- ## Transfer details Click the **View** icon on any transfer to open the details dialog, which shows: - Source and destination with type indicators (location icon or till icon) - Transfer date and status - Reference number and notes - Complete item list with names, SKUs, variants, and quantities --- ## Xero and QuickBooks integration For businesses using Xero or QuickBooks, the transfers page includes a section to import purchase orders and bills: - **Purchase Orders** -- view open purchase orders from Xero or QuickBooks and convert them into inventory transfers - **Bills** -- view supplier bills and create transfers based on received items - **Manual mapping** -- when imported items do not match existing inventory by code, a mapping dialog lets you manually link each line item to the correct product and variant This integration streamlines the receiving process: instead of manually entering every item from a purchase order, import the PO and the transfer is pre-populated. --- ## Troubleshooting {% callout type="tip" %} Use reference numbers consistently (e.g., the purchase order number from your supplier) to make it easy to trace transfers back to their source documents. External-to-location transfers are the standard way to record receiving new stock -- they increase your inventory without decreasing any source. {% /callout %} {% callout type="warning" title="Common issues" %} **Transfer completed with errors** -- Some items may not have been transferred if the source did not have sufficient stock. Review the error messages and create a follow-up transfer for any items that were not moved. **Cannot find the item to transfer** -- Items must exist in your POS inventory before they can be transferred. Add the product first under **POS > Register** using the add product dialog. **Till inventory not updating** -- Only items with `inventoryType: till` track inventory at the till level. Location-level items have a single stock count shared across all tills. {% /callout %} --- # Customer-facing Source: https://docs.rentaltide.com/public/ > Booking widget, checkout, next steps, check-in, member portal, staff portal, waivers, and reviews The pages and flows your customers and staff interact with directly -- from booking through post-rental review. {% cardGroup cols=2 %} {% card title="Booking widget" href="/public/booking-widget/" /%} {% card title="Checkout" href="/public/checkout/" /%} {% card title="Next steps" href="/public/next-steps/" /%} {% card title="Check-in" href="/public/check-in/" /%} {% card title="Member portal" href="/public/member-portal/" /%} {% card title="Staff portal" href="/public/staff-portal/" /%} {% card title="Waivers" href="/public/waivers/" /%} {% card title="Reviews" href="/public/reviews/" /%} {% /cardGroup %} --- # Booking widget Source: https://docs.rentaltide.com/public/booking-widget/ > Embeddable customer booking page with inventory browsing, date selection, add-ons, tours, and cart The booking widget is the public-facing page where customers browse your inventory, select dates and times, configure add-ons, and add items to their cart. It can be hosted on your RentalTide subdomain, embedded as an iframe on your own website, or integrated via the WordPress plugin. ## Booking flow 1. **Location select** -- if you have multiple locations, the customer picks one first. 2. **Browse inventory** -- a grid of available items with photos, descriptions, capacity, and pricing. Items are organized by category. 3. **Item details** -- expanded view with photo gallery, pricing breakdown, specifications, and real-time availability. 4. **Date and time** -- select the rental date and start time. The calendar respects operating hours, blocked dates, seasonal availability, and last-call cutoffs. 5. **Duration and quantity** -- choose the rental duration (hourly slider or multi-day date range) and number of units. For tours, select a departure time and choose price tiers (Adult, Child, etc.). 6. **Add-ons** -- optional extras such as protection plans, equipment add-ons, and fuel packages. 7. **Cart** -- review all selections before proceeding to checkout. Supports multiple items from the same or different inventory types. ## URLs The booking widget is accessible at: - `/booking/{customerId}` -- direct customer ID URL - `/booking/{slug}/{locationSlug}` -- human-readable slug URL ## Booking types | Type | Description | | ----------------- | -------------------------------------------------------------------------------------------- | | Hourly rentals | Select a date and start time, then adjust a duration slider to set the rental length | | Multi-day rentals | Select a date range using a start and end date picker | | Tours | Select a departure session from a grid of available times, choose price tiers and quantities | | Moorage/Slips | Slip booking with date range selection | | Bundles | Pre-configured packages that combine multiple inventory items with bundled pricing | ## Tour bookings For tour products, the booking widget displays a **departure grid** showing available sessions with: - Departure time and end time - Available spots remaining - Price tiers (Adult, Child, etc.) with per-tier pricing - Private vs. open booking modes (dual cards shown for dual-mode products) - Availability status indicators (available, call to book, waitlist) ## Configuration ### Branding Customize the look and feel to match your brand: - **Colors** -- primary and accent colors applied throughout the widget - **Logo** -- displayed in the widget header - **Custom CSS** -- inject additional styles via the Custom Code Block integration - **Custom JS** -- add tracking scripts or behavioral customizations via the Custom Code Block integration ### Analytics Connect your analytics and advertising platforms via the App Store: - **Google Tag Manager / GA4** -- per-location GTM container ID or GA4 measurement ID - **Meta Conversion API** -- server-side Facebook/Instagram conversion tracking - **TikTok Pixel** -- TikTok conversion tracking ### Features Enable or disable capabilities: - **Multi-location** -- location picker for businesses with multiple sites - **Gift cards** -- allow gift card purchases through the widget - **Memberships** -- display membership options and apply member pricing - **Custom HTML** -- inject custom content blocks into the booking flow - **Reviews display** -- show Google and TripAdvisor review ratings and counts ### Embedding Embed the widget on your website using an iframe: ```html <iframe src="https://app.rentaltide.com/booking/{your-slug}" width="100%" height="800" frameborder="0" ></iframe> ``` Alternatively, install the **WordPress Plugin** from the App Store for native WordPress integration with shortcode support. ## Cart and cart recovery The cart persists items as customers browse. When a customer adds items but does not complete checkout: - The cart is automatically saved for recovery - A recovery URL is generated that can be included in follow-up emails - Staff can send private booking links that pre-populate the cart {% callout type="tip" %} Test your booking widget regularly by going through the full flow as a customer. Use high-quality photos -- they are the first thing customers see. Availability in the widget respects all overrides, blocked dates, and operating hours. Brand colors are configured in your Location Settings. Set up Google Tags to track your booking funnel and conversion rates. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **No availability showing** -- Check that your inventory has published availability, operating hours are set, and no date blocks are preventing bookings. Verify your operating season dates. **Page looks broken** -- Custom CSS can cause layout issues. Disable custom CSS temporarily via the Custom Code Block integration to isolate the problem. Clear your browser cache. **Wrong prices displayed** -- Verify your pricing settings and check for active promotions, seasonal pricing, or membership discounts that may be modifying the displayed rate. **Cannot select certain dates** -- The date may be blocked, fully booked, or outside your operating season. Check your availability settings and any date overrides. **Widget not loading in iframe** -- Make sure your website's Content Security Policy (CSP) allows framing from the RentalTide domain. Check the browser console for CSP errors. **Tour departures not showing** -- Verify that tour sessions have been generated for the selected date and that the sessions are not marked as call-to-book or unavailable. {% /callout %} --- # Check-in Source: https://docs.rentaltide.com/public/check-in/ > Kiosk-style arrival check-in with configurable steps for booking lookup, ID verification, payment, waiver, and safety briefing The check-in page is a kiosk-optimized flow that walks customers through arrival steps -- from finding their booking to completing any outstanding requirements. It is designed for use on a dedicated iPad or tablet at your dock, with a dark navy theme optimized for outdoor visibility. ## Access modes | Mode | URL | Description | | ----------- | ---------------------------------------------- | --------------------------------------------------------------------------------------------------------- | | Direct link | `/check-in?id={rentalId}` | Opens check-in for a specific booking. Used when sending a check-in link to a customer via email or text. | | Kiosk | `/check-in?locationId={id}&kioskToken={token}` | Unattended kiosk mode. Starts with a booking lookup screen and auto-resets after inactivity. | ## Kiosk mode In kiosk mode, the page starts with a **Booking Lookup** screen where the customer can find their reservation by: - **Scanning a QR code** from their confirmation email - **Searching by name** -- type their first or last name - **Searching by email** -- enter their email address - **Searching by phone** -- enter their phone number Once a booking is found, a **Booking Summary Card** displays the booking details (date, time, inventory, status) and the customer proceeds to the check-in steps. ## Check-in steps Each step is configurable and can be enabled or disabled in your location settings. The flow uses a stepper component showing progress through the enabled steps. ### Step 1: ID Verification Identity verification using one of two methods: - **Stripe Identity** (automated) -- the customer scans a government-issued ID using their device camera. Stripe verifies the document authenticity and extracts the customer's information. - **Manual verification** -- staff visually confirms the customer's identity. A confirmation button marks this step as complete. ### Step 2: Payment Collect any outstanding balance on the booking: - Displays the amount due - Accepts payment via Stripe (card entry or connected Stripe Terminal reader) - Shows payment confirmation on success If the booking is fully paid, this step is automatically skipped or marked as complete. ### Step 3: Waiver Digital waiver signing if not already completed: - Displays the waiver content - Collects acknowledgment checkboxes - Signature pad for signing - Multi-participant support for group bookings If the waiver was already signed (e.g., via the next steps page), this step is marked as complete. ### Step 4: Safety Briefing Customer watches or acknowledges a safety briefing: - Supports video content (uploaded safety video) - Supports document content (safety rules and guidelines) - Acknowledgment checkbox to confirm completion ### Step 5: Confirmation Check-in complete. The confirmation screen displays: - Success message - Departure information (time, dock assignment, asset details) - A custom "proceed to" message configured in your settings - In kiosk mode, a button to start a new check-in (auto-resets after the configured timeout) ## Configuration Configure check-in behavior in your location settings: | Setting | Description | | ---------------------- | ------------------------------------------------------------------------------- | | Active steps | Choose which check-in steps are required (ID, payment, waiver, safety briefing) | | ID verification method | Stripe Identity (automated) or manual (staff confirms visually) | | Safety content | Upload a video or document for the safety briefing step | | Kiosk timeout | Duration of inactivity before the kiosk auto-resets (for unattended use) | | Kiosk token | Secure token that authorizes the kiosk to operate without staff login | | Proceed-to message | Custom message shown on the confirmation screen (e.g., "Proceed to Dock B") | ## Check-in availability Check-in is available within a configurable window before the booking start time (default: 24 hours). If a customer tries to check in outside this window, they are shown a message indicating when check-in opens. ## Completing check-in When the customer completes all enabled steps, the system marks the booking as checked in. The confirmation step calls the check-in API, which: - Updates the booking status - Records the check-in timestamp - Returns any custom departure instructions {% callout type="tip" %} Set up a dedicated iPad at your dock for walk-in check-ins. The dark navy interface with gold accents is designed for outdoor visibility in bright conditions. Connect a Stripe Terminal reader for payment collection during check-in. Test the full check-in flow before your season starts. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Check-in not available yet** -- The check-in window opens 24 hours before the booking start time. The customer is too early. **QR code not scanning** -- Check lighting conditions. Ensure the camera has permission in the browser. The customer can use the manual search option instead. **ID verification failing** -- If Stripe Identity cannot verify the ID (blurry photo, unsupported document type), use the manual verification fallback where staff confirms the customer's identity visually. **Payment failing at kiosk** -- Check the Stripe Terminal reader connection. Ensure it is paired and online. The customer can also enter a card manually. **Kiosk not resetting** -- Verify the kiosk timeout is configured in your location settings. The page automatically reloads after the timeout period. **Booking not found in lookup** -- Verify the customer is searching with the correct name or email. Check that the booking exists and is within the check-in window. {% /callout %} --- # Checkout Source: https://docs.rentaltide.com/public/checkout/ > Three-step checkout flow with personal info, order review, promo codes, gift cards, member login, and Stripe payment The checkout flow guides customers from cart to confirmed booking in three steps. It supports multiple payment methods, promo codes, gift cards, member discounts, split payments, and deposit options. There are three checkout variants: standard rentals, gift card purchases, and membership purchases. ## Checkout steps ### Step 1: Personal Information The customer enters their contact details: - First name and last name (required) - Email address (required) - Phone number - Any additional required fields configured in your location settings Returning members can log in at the top of this step to pre-fill their information and unlock membership pricing. The login uses a loyalty/member session that pulls their profile, membership tier, and available credits. ### Step 2: Review A complete summary of the order including: - Booking dates, times, and duration - Inventory items and quantities - Add-ons and protection plans - Itemized pricing with subtotal, taxes, fees, and total - Deposit amount (if deposit-only payment is configured) - Promo code and gift card redemption fields - Cancellation policy disclosure ### Step 3: Payment Secure payment processing via Stripe: - **Credit/debit card** -- standard card entry - **Apple Pay and Google Pay** -- available when the customer's browser supports them - **Split payment** -- divide the total across multiple payment methods or installments - **Deposit** -- pay a configurable deposit amount now with the balance due later - **Gift card** -- apply a gift card balance toward the total The payment step handles the Stripe payment intent creation, confirmation, and error handling. A confetti animation plays on successful booking. ## Checkout variants | Variant | URL | Description | | ---------- | ---------------------- | ---------------------------------- | | Standard | `/checkout` | Standard rental booking checkout | | Gift Card | `/checkout/gift-card` | Gift card purchase flow | | Membership | `/checkout/membership` | Membership subscription enrollment | ## Features ### Member login and discounts Returning members can log in during checkout to: - Pre-fill their personal information - Apply their membership discount automatically - Use available credits toward the total - Access member-only pricing ### Promo codes Customers enter a promo code in the Review step. The system validates the code against: - Expiration date - Usage limits - Minimum spend requirements - Product/category restrictions A valid code adjusts the pricing in real time. ### Gift card redemption Customers can apply a gift card balance toward their total in the Review step. The gift card balance is verified in real time and the remaining amount is deducted from the total due. ### Split payment The split payment option allows customers to divide the total across multiple payment methods or split the bill into installments. The number of installments can be configured, and each installment amount is calculated automatically. ### Cart recovery If a customer abandons checkout, their cart and personal information are automatically saved. RentalTide generates a recovery URL that can be: - Included in automated cart recovery emails - Sent manually by staff from the Cart Recovery dashboard When the customer returns via the recovery URL, their cart and information are pre-populated. ### Private booking links Staff can generate a private booking link that pre-populates the cart with specific items and optionally includes a staff note. The link can be sent directly to a customer via email or messaging. ## Checkout notes Location settings can configure **checkout questions** -- additional fields that appear during the personal information step. For tour products, checkout questions can be defined at the product level and appear as part of the booking flow. ## Configuration Configure checkout behavior in your Location Settings: - **Required fields** -- choose which customer information fields are mandatory - **Add-ons** -- configure upsells that appear during checkout (protection plans, equipment extras) - **Payment options** -- enable full payment, deposit-only, or payment plans - **Terms** -- link to your terms and conditions (customer must accept before paying) - **Cancellation policy** -- displayed during the review step so customers understand the policy before committing - **Credit card processing fee** -- optionally pass the CC processing fee to the customer (displayed as a line item) {% callout type="tip" %} Keep required fields to a minimum to reduce checkout friction. Make sure pricing is clear and itemized on the review step. Enable cart recovery to automatically save abandoned carts. Test the full checkout flow regularly, including promo code and gift card redemption. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Payment declined** -- Ask the customer to try a different card. Check Stripe for detailed decline reasons (insufficient funds, incorrect CVC, etc.). **Error during checkout** -- Refresh the page and try again. If the issue persists, check Stripe's status page for outages. **Promo code not applying** -- Verify the code is valid, has not expired, and meets any minimum spend or usage limits. Codes are case-sensitive. **Cart expired** -- If the customer waited too long, their cart may have timed out. They will need to re-select their items and start checkout again. **Deposit amount showing as zero** -- Ensure your deposit configuration uses a non-zero percentage or fixed amount. A deposit amount of $0 is valid and indicates no deposit is required. **Member discount not applying** -- The member must log in through the checkout before the review step. Verify the membership tier has discounts configured. {% /callout %} --- # Member portal Source: https://docs.rentaltide.com/public/member-portal/ > Self-service membership portal with OTP login, tier management, credits, bookings, quick booking, and payment updates The member portal gives your membership customers a self-service dashboard where they can view their benefits, check credit balances, manage upcoming bookings, update their payment method, and make new bookings. The portal is accessible at `/member-portal`. ## Login Members log in using a one-time password (OTP) sent to their email address: 1. Enter the email address associated with their membership. 2. Receive a one-time code via email. 3. Enter the code to authenticate. No password is required. The session is stored in the browser and expires after a configurable duration. The session keys are `member_portal_session` and `member_portal_session_expiry`. ## Dashboard sections ### Membership overview The top of the dashboard shows: - **Current tier** name and description - **Membership status** (active, paused, cancelled, pending cancellation) - **Billing cycle** (monthly, annual) - **Current period** start and end dates - **Tier benefits** -- list of benefits included in the membership ### Credits When credits are enabled for the membership tier: - **Current balance** -- available credits - **Credit type** (dollar credits, booking credits, etc.) - **Last renewal date** and **next renewal date** - **Lifetime earned** -- total credits earned since membership started ### Quick book The member portal includes a **Quick Book** section that allows members to initiate a new booking directly from the portal. This pre-fills their information and applies membership pricing automatically. ### Upcoming bookings A list of future reservations that have not yet occurred, showing date, time, inventory, and status. ### Past bookings Completed rental history for the member. ## Actions | Action | Description | | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | Pause membership | Temporarily suspend the membership while retaining tier and benefits. Subject to the pause policy (maximum pauses per year, maximum pause duration). | | Resume membership | Reactivate a paused membership. Billing resumes on the next cycle. | | Cancel membership | End the membership. Cancellation takes effect at the end of the current billing period if `cancelAtPeriodEnd` is set. | | Change tier | Switch to a different membership tier. Opens a tier change dialog showing available tiers and their benefits. | | Update payment method | Update the card on file via Stripe's secure setup form. Opens a Stripe Elements payment form directly in the portal. | | Log out | End the current session and return to the login page. | ## Pause policy Membership pausing is governed by the tier's pause policy: | Setting | Description | | ------------------------- | --------------------------------------------------- | | Enabled | Whether pausing is allowed for this tier | | Max pauses per year | Maximum number of times a member can pause per year | | Max pause duration (days) | Maximum length of a single pause period | The portal tracks how many times a member has paused (`pause.pauseCount`) and prevents pausing when the limit is reached. ## Cancel policy Cancellation is governed by the tier's cancel policy: | Setting | Description | | ------------------------- | ---------------------------------------------------- | | Enabled | Whether self-service cancellation is allowed | | Minimum commitment months | Members cannot cancel before this period has elapsed | When a member cancels, their membership is flagged for cancellation at the end of the current billing period. They retain access until then. ## Configuration From your admin settings, configure membership features: - **Tiers** -- define membership levels with different benefits, pricing, and credit allocations - **Credits** -- set monthly or annual credit allocations per tier - **Discounts** -- percentage or fixed discounts per tier, applied automatically at checkout - **Priority booking** -- give members early access to availability - **Pause and cancel policies** -- configure rules for pausing and cancelling memberships - **Billing options** -- set minimum commitment periods and billing cycles {% callout type="tip" %} Share the member portal URL with your customers so they can manage their own accounts. Self-service payment updates reduce failed billing and churn. Pausing a membership retains the member's tier -- they do not have to re-qualify when they resume. Credits roll over or reset based on your rollover policy. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Cannot log in** -- Make sure the customer is using the same email address associated with their membership. Check that the membership is active and not expired. **OTP not arriving** -- Verify the email address on file. Check the spam folder. OTP emails are sent via your configured email provider. **Credits not showing** -- Credits are allocated on the billing date. If the member just signed up, credits will appear after their first billing cycle. **Discount not applying at checkout** -- The member must log in through the booking widget or checkout before the review step for discounts to apply. Verify the membership tier has discounts configured. **Cannot update payment method** -- Check for popup blockers. The Stripe payment form renders inline in the portal. **Cannot pause membership** -- The member may have reached the maximum number of pauses for the year, or the tier's pause policy may be disabled. **Cannot cancel membership** -- Self-service cancellation may be disabled for the tier, or the minimum commitment period may not have elapsed yet. {% /callout %} --- # Next steps Source: https://docs.rentaltide.com/public/next-steps/ > Post-booking customer page with action checklist, messaging, wallet pass, participants, tipping, and self-service tools The next steps page is the customer's post-booking hub. It shows everything they need to do before their rental and gives them self-service tools for managing their reservation. The page is accessible at `/next-steps?id={rentalId}` for individual bookings or `/next-steps?orderId={orderId}` for order groups. ## URL parameters | Parameter | Description | | --------------- | ---------------------------------------------------------- | | `id` | Rental/booking ID -- loads a single booking view | | `orderId` | Order ID -- loads the order group view with all line items | | `invoiceAmount` | Pre-fills a payment amount for invoice payment links | When a booking belongs to an order group, the page automatically redirects from the single-booking view to the order view. ## Page sections ### Booking hero The top section displays: - Status badge (confirmed, checked in, completed, cancelled) - Rental dates and times - Inventory name and location - **Add to Calendar** buttons (Google Calendar, Apple Calendar, Outlook) - Order group banner (when the booking is part of a multi-item order) ### Action checklist (Next Steps) A list of required and optional steps the customer needs to complete before their rental: | Step | Description | | ---------------- | ------------------------------------------------- | | Sign waiver | Complete the digital liability waiver | | Pay balance | Settle any outstanding balance | | ID verification | Verify identity via Stripe Identity or manually | | Safety briefing | Watch or acknowledge a safety video/document | | Upload documents | Upload required documents (e.g., boating license) | Each step shows its completion status with a checkmark. Incomplete required steps are highlighted. ### Booking details Full breakdown of the reservation: - Inventory item name and photo - Location with map embed (Google Maps or Mapbox) - Asset assignment (if an asset has been assigned) - Booking notes and special instructions - Tour departure information (for tour bookings) ### Pricing breakdown Itemized costs including: - Subtotal - Taxes (with per-tax-type breakdown) - Fees - Add-ons and protection plans - Discounts and promo codes - Deposit paid - Outstanding balance - Total ### Messaging Two-way messaging between the customer and your team: - Real-time chat interface - Message history with timestamps - Staff replies appear with the staff member's name ### Wallet pass Add the booking to mobile wallets: - **Apple Wallet** -- generates a `.pkpass` file - **Google Wallet** -- generates a Google Wallet pass ### Participant manager For group bookings, the customer can: - Add additional participants with name and email - Remove participants - View participant payment status and waiver completion Participant payment dialogs allow individual participants to pay their share. ### Global add-ons manager Customers can add or modify add-ons after booking (when enabled). This section displays available add-ons with pricing and lets the customer add them to their existing reservation. ### Cancellation Self-service cancellation (when enabled in your settings): - Displays the cancellation policy - Shows the cancellation window - Processes refunds according to your cancellation rules ### Reschedule Self-service rescheduling (when enabled): - Opens a date/time picker to select a new rental slot - Checks availability for the requested time - Adjusts pricing if the new slot has different rates ### Tipping After the rental is completed, a tipping section appears: - Suggested tip percentages - Custom tip amount field - Secure payment processing via Stripe ### Pay balance When there is an outstanding balance (deposit bookings or additional charges): - Shows the amount due - Provides a secure payment form - Supports partial payments ### AI Sidekick chat An AI-powered chat assistant that answers common customer questions using: - Booking details - Location information - FAQ content - Operating policies ### Nautras navigation When the Nautras integration is enabled, displays navigation instructions and links to the Nautras app for on-water navigation. ### Reviews display Shows Google and TripAdvisor review ratings and counts for your location (when configured). ## Order group view When accessed with an `orderId`, the page shows all bookings in the order as a unified view: - Order-level banner with total items and pricing - Individual booking cards for each line item - Shared waiver and payment status across the order - Unified messaging for the entire order ## Custom styling The next steps page supports custom styling through the **NextStepsStyleProvider**. Different visual themes can be applied based on your branding configuration. {% callout type="tip" %} Include the next steps link in your confirmation email so customers can easily find it. Enable all relevant checklist items to reduce day-of friction. Messaging reduces inbound phone calls. Tipping becomes available after the rental is completed. The AI Sidekick uses your booking data and location details to answer customer questions automatically. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Waiver showing as incomplete** -- The customer may need to clear their browser cache and refresh the page. The waiver status is checked in real time. **Cannot add to calendar** -- Some email clients block calendar file downloads. The customer can manually add the event using the displayed date and time. **Payment link expired** -- Send the customer a new payment link from the booking detail page. Include the `invoiceAmount` parameter in the URL. **Customer cannot cancel** -- Self-service cancellation may be disabled or the cancellation window may have passed. Check your cancellation policy settings. **Order view not loading** -- Verify the order ID in the URL is correct. If the booking was created before the orders feature was enabled, it may not have an associated order. {% /callout %} --- # Reviews Source: https://docs.rentaltide.com/public/reviews/ > Post-rental review collection with smart routing, tipping integration, platform sharing, and copy-to-clipboard The reviews page collects customer feedback after a rental and intelligently routes it -- high ratings are encouraged to share on public platforms, while low ratings are captured as private feedback. The page also supports post-rental tipping. The review page is accessible at `/review?id={rentalId}`. ## Review flow The review flow consists of multiple phases that the customer progresses through: ### Phase 1: Star rating The customer selects a star rating from 1 to 5: | Stars | Label | | ----- | --------- | | 1 | Poor | | 2 | Fair | | 3 | Okay | | 4 | Great | | 5 | Excellent | The page displays the company logo (if configured) and a personalized greeting using the customer's first name. Star labels appear dynamically as the customer hovers over or selects a rating. ### Phase 2: Written feedback After selecting a rating, the customer is prompted to write a review: - A text area for open-ended feedback - For 4-5 star ratings: "We'd love to hear what was great!" - For 1-3 star ratings: "Your feedback helps us improve" - A **Change Rating** link to go back and adjust the star rating - **Submit Review** button to save the feedback ### Phase 3: Tipping (optional) If tipping is enabled and the customer gave 4 or 5 stars, a tipping screen appears: - **Suggested tip percentages** -- configurable presets (default: 15%, 18%, 20%, 25%), displayed as buttons showing both the percentage and the calculated dollar amount - **Custom amount** -- a text input for entering a custom tip amount - **Payment processing**: - If the customer has a saved card on file, the tip is charged to that card with a single click - If no saved card, a Stripe card entry form appears inline for secure one-time payment - **Skip option** -- "No thanks, skip" link to proceed without tipping Tipping is only offered once per booking. If a tip has already been submitted, this phase is skipped. ### Phase 4: Platform sharing (high ratings) For 4-5 star ratings, if review platform URLs are configured, the customer is directed to share their review publicly: - **Copy review text** -- if the customer wrote feedback, a block displays their text with a **Copy** button for easy clipboard copying - **Platform buttons** -- branded buttons linking to each configured review platform: - Google (blue button with Google icon) - TripAdvisor (green button with globe icon) - Additional platforms as configured Clicking a platform button opens the review URL in a new tab and tracks the click-through. ### Phase 5: Thank you A confirmation screen thanking the customer for their feedback. For low ratings (1-3 stars), this is shown immediately after the feedback submission since the review is kept private. ## Smart routing The smart routing system ensures: - **4-5 star reviews** -- encouraged to post publicly on Google, TripAdvisor, or other platforms where positive reviews drive new business - **1-3 star reviews** -- captured as private feedback sent directly to your team, allowing you to address issues without negative public exposure ## Tipping configuration Tipping is configured in your location settings: | Setting | Description | | --------------------- | -------------------------------------------------------------------------- | | Enabled | Whether post-rental tipping is available | | Title | Custom heading for the tipping section (default: "Show your appreciation") | | Description | Custom description text | | Suggested percentages | Array of tip percentages to display as preset buttons | | Allow custom amount | Whether customers can enter a custom dollar amount | Tip amounts are calculated as a percentage of the booking total. The currency symbol adapts based on the location's configured currency (USD, CAD, EUR). ## Configuration ### Review platforms Configure your review platform URLs in the App Store by installing Google Reviews and/or TripAdvisor Reviews. Each platform requires: - The platform URL pointing directly to your business listing's review page - Per-location configuration (each location can have different review URLs) ### Review trigger The review request is sent to customers via email after rental completion. Configure the timing and email template content in your Email Templates settings. ## Visual design The review page uses a premium dark theme designed for high engagement: - Dark navy gradient background - Frosted glass card effect with subtle borders - Gold accent color for interactive elements and star ratings - Smooth fade transitions between phases - Mobile-responsive layout (max width 480px) {% callout type="tip" %} Send the review request within 24 hours of rental completion while the experience is fresh. Write a warm, personal email template to increase response rates. Low ratings are valuable private feedback -- use them to identify and fix operational issues. The copy-to-clipboard feature makes it easy for customers to paste their review on Google or TripAdvisor. Configure tipping to capture additional revenue from satisfied customers. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Review link not working** -- Make sure the booking ID in the URL is valid and the booking status is completed. Reviews are only available for completed bookings. **Wrong platform URL** -- Verify the platform URLs in your Google Reviews or TripAdvisor Reviews integration settings. Each URL should point directly to your business listing's review submission page. **Customer wants to change their review** -- Reviews are one-time submissions. If a customer needs to update their feedback, they should contact your support team. **Tipping not appearing** -- Verify that tipping is enabled in your location settings. Tipping only appears for 4-5 star ratings and is skipped if a tip has already been submitted for that booking. **Tip payment failing** -- For customers without a saved card, ensure the Stripe publishable key is configured correctly. Check the browser console for Stripe initialization errors. {% /callout %} --- # Staff portal Source: https://docs.rentaltide.com/public/staff-portal/ > Self-service staff portal with OTP login for schedules, availability, shift swaps, and timesheets The staff portal gives your team members a self-service page to view their schedule, set availability preferences, request shift swaps, and manage their timesheet -- all without needing admin dashboard access. The portal is accessible at `/staff-portal`. ## Login Staff log in using a one-time password (OTP) sent to their email. No password required: 1. Enter the email address associated with the staff account. 2. Receive a one-time code via email. 3. Enter the code to authenticate. The portal wraps all content in the **StaffPortalLayout** component, which provides the navigation header, logout button, and authenticated session management. ## Tabs ### Schedule View assigned shifts for the current and upcoming weeks: - **Week navigation** -- arrow buttons to move forward and backward through weeks, with the current week range displayed (e.g., "Mar 3 - Mar 9, 2026") - **Daily schedule** -- shows each day of the week with assigned shifts, including start time, end time, location, and role - **Shift details** -- each shift displays relevant details such as assigned area, duties, and notes The schedule tab uses the `usePortalSchedule` hook to fetch shifts for the selected date range. ### Availability Set weekly availability preferences and date-specific overrides: - **Weekly rules** -- define recurring availability by day of the week (e.g., "Available Monday 8am-5pm, Unavailable Wednesday") - **Date overrides** -- set availability for specific dates that override the weekly rules (e.g., "Unavailable Dec 25") - **Add/remove rules** -- add new availability rules with day, start time, and end time. Delete rules that are no longer needed. - **Save changes** -- persist availability preferences for the scheduling algorithm to use The availability tab uses `usePortalAvailabilityRules` for weekly rules and `usePortalAvailabilityOverrides` for date-specific overrides. ### Swaps Request shift swaps with other staff and respond to incoming requests: - **Outgoing requests** -- shifts you have requested to swap. Shows the status (pending, approved, rejected) and the target staff member. - **Incoming requests** -- swap requests from other staff members for your shifts. You can accept or decline each request. - **Request a swap** -- select a shift to swap and choose which staff member you want to swap with. Shift swaps require manager approval. The `usePortalIncomingSwaps` and `usePortalOutgoingSwaps` hooks manage swap data. ### Timesheet View time entries, clock in and out, and track hours: - **Time entries table** -- lists all time entries for the selected period with date, clock-in time, clock-out time, and total hours - **Clock in/out** -- start and stop time tracking for the current shift - **Weekly totals** -- sum of hours worked for the week The timesheet tab uses the `usePortalTimesheet` hook. ## Schedule display The schedule view organizes shifts by day of the week: | Day | Shifts | | ----------------- | -------------------------------------------------------------------------------------------------------- | | Sunday - Saturday | Each day shows assigned shifts with times, locations, and roles. Days without shifts are shown as empty. | Staff can navigate between weeks to view upcoming schedules and plan accordingly. {% callout type="tip" %} Share the staff portal URL with your team so they can check their schedule anytime without needing full admin access. Availability preferences feed into the scheduling algorithm when managers build the weekly schedule. Timesheet data can be exported for payroll processing. Encourage staff to keep their availability up to date to reduce scheduling conflicts. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **No schedule visible** -- The schedule may not have been published yet. Check with your manager. Only published schedules appear in the portal. **Swap request rejected** -- The manager may have denied the request due to a scheduling conflict, skill/certification mismatch, or staffing requirements. **OTP not arriving** -- Verify the email address on file in the admin Staff page. Check the spam folder. Ensure the email provider is properly configured. **Cannot clock in** -- Verify that you have an assigned shift for the current time. Clock-in may be restricted to within a window of the shift start time. **Availability changes not reflected** -- After saving availability changes, the scheduling manager must regenerate the schedule for the changes to take effect. Availability preferences are used during schedule creation, not retroactively. {% /callout %} --- # Waivers Source: https://docs.rentaltide.com/public/waivers/ > Digital waiver signing with multi-participant support, QR scanning, multi-language, dependent minors, and signature pad The waiver page lets customers read, acknowledge, and sign your liability waiver digitally. It supports multiple participants, QR code pre-fill, multi-language translations, dependent minors, and works seamlessly on mobile devices. The waiver is accessible at `/waiver` with booking context passed via URL parameters or PIN entry. ## Access methods | Method | Description | | --------------- | ------------------------------------------------------------------------------------- | | Direct link | URL from booking confirmation email with pre-filled booking context | | QR code scan | Scan a QR code at the dock to open the waiver with booking details pre-populated | | PIN entry | Enter a numeric PIN on a kiosk numpad to load the waiver (used for walk-up customers) | | Check-in flow | Waiver step within the kiosk check-in process | | Next steps page | Waiver action item on the post-booking next steps page | ## Signing flow ### Step 1: Personal information The customer enters their contact details: - First name and last name (required) - Email address (required, validated) - Phone number (optional, validated for 10-15 digits) - Address (optional, with Mapbox autocomplete) - Date of birth If the waiver is accessed via a booking link or QR code, these fields are pre-populated from the booking data. ### Step 2: Dependents (optional) For group bookings or customers with minors, the signer can add dependent participants: - First name, last name, and date of birth for each dependent - Relationship type: **child** or **ward** - Add or remove dependents using the inline controls ### Step 3: Waiver content The waiver content is displayed using a template system that supports multiple section types: | Section type | Description | | ----------------------- | --------------------------------------------------------- | | Text | Read-only informational text (rendered as sanitized HTML) | | Acknowledgment checkbox | A statement the customer must agree to by checking a box | | Signature | A signature pad where the customer draws their signature | | Multiple choice | Radio button selection from predefined options | | Checkbox group | Multiple checkboxes for selecting multiple items | Sections can span multiple pages. The waiver uses a stepper to navigate between pages. ### Step 4: Signature A full-width signature pad where the customer draws their signature: - Touch-optimized for mobile and tablet devices - Clear button to reset and redraw - Signature is captured as an image and stored securely ### Step 5: Submission After completing all required sections and signing, the customer submits the waiver. A confirmation screen is displayed. ## Multi-language support The waiver system supports multiple languages: - A **language selector** appears at the top of the waiver page - The primary language is set in the waiver template - Additional language translations can be configured in the waiver template editor - When a translation is selected, the title, description, and all section content switch to the translated version ## Waiver templates Templates are created and managed in the admin dashboard waiver editor. Each template includes: | Field | Description | | ---------------- | ------------------------------------------------------------------------ | | Title | Display name of the waiver | | Description | Optional introductory text | | Sections | Ordered list of content sections (text, acknowledgment, signature, etc.) | | Assign to | Which inventory items or categories this waiver applies to | | Primary language | The default language for the waiver | | Translations | Additional language versions of the waiver content | ### Section configuration Each section has: - **Content** -- the text or question displayed to the customer (supports HTML for text sections) - **Type** -- text, acknowledgment, signature, multiple choice, or checkbox group - **Options** -- for multiple choice and checkbox sections, the list of available choices - **Required** -- whether the section must be completed - **Page** -- which page of the waiver the section appears on ## QR code pre-fill Generate QR codes that link to pre-populated waiver forms: 1. The QR code encodes a URL with the booking ID and customer information 2. When scanned, the waiver form auto-fills personal information fields 3. The customer only needs to read, acknowledge, and sign ## Kiosk PIN entry For walk-up customers at a kiosk: 1. A numeric keypad is displayed on the kiosk screen 2. The customer enters a PIN associated with their booking 3. The waiver loads with their booking information pre-filled {% callout type="tip" %} Keep waiver content concise -- long legal text increases abandonment. Test the full signing flow on a mobile device before going live. Set up a kiosk with QR codes at your dock for walk-in customers. Signed waivers are stored in the booking detail and available for download. Use the multi-language feature if you serve international customers. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Signature not saving** -- Make sure the customer draws a clear mark on the signature pad. A single dot may not register. If the pad is unresponsive, try reloading the page. **Cannot scroll through waiver** -- On mobile, swipe to scroll. Pinch-to-zoom is supported for small text. Ensure the browser is not in a zoomed state that blocks scrolling. **Signed but still showing as unsigned** -- Clear the browser cache and refresh the page. The waiver status update may take a moment to propagate to the booking record. **QR code not working** -- Verify the QR code has not expired and contains a valid booking URL. Test by scanning with a standard QR reader app first. **Wrong language showing** -- Check the primary language setting in the waiver template. If translations are configured, use the language selector at the top of the waiver page. **Dependent section not appearing** -- Multi-participant support must be enabled in the waiver template settings. {% /callout %} --- # Reporting Source: https://docs.rentaltide.com/reporting/ > Analytics, exports, payment reports, ledger, and environmental tracking Tools for understanding your business performance, exporting data for accounting, and tracking environmental impact. {% cardGroup cols=2 %} {% card title="Analytics" href="/reporting/analytics/" /%} {% card title="Exports" href="/reporting/exports/" /%} {% card title="Payments" href="/reporting/payments/" /%} {% card title="Ledger" href="/reporting/ledger/" /%} {% card title="Carbon footprint" href="/reporting/carbon-footprint/" /%} {% /cardGroup %} --- # Analytics Source: https://docs.rentaltide.com/reporting/analytics/ > Eight-tab analytics hub with KPI dashboard, live globe, engagement funnels, session tracking, demand forecasting, dynamic pricing analysis, AI usage monitoring, and financial health scoring The analytics page is an eight-tab hub that gives you a complete picture of business performance. Each tab focuses on a different dimension of your operation, from real-time revenue to AI-powered anomaly detection. ## Date range and location All tabs share a global date range picker at the top of the page. Choose from presets (Today, This Week, This Month, Last 30 Days, etc.) or set a custom range. The location filter in the navigation bar controls which location's data is displayed. Select **All Locations** to see aggregated metrics across your entire business. Analytics data is cached locally for 5 minutes to keep page loads fast. Click the refresh button to force a reload. ## Dashboard tab The default tab displays a comprehensive overview of your business metrics. ### KPI cards Six key performance indicators are displayed at the top: | KPI | Description | | --------------------- | ----------------------------------------------- | | Total Sales | Total collected revenue for the selected period | | Booking Revenue | Revenue from rental bookings and tours | | POS Revenue | Revenue from point-of-sale transactions | | Net Sales | Total sales minus processing fees | | Average Booking Value | Average revenue per booking | | Total Bookings | Count of confirmed bookings | Additional metrics visible in the KPI summary include tax collected, tips collected, processing fees, discounts applied, gift card amounts used, equipment addon revenue, and protection plan revenue. ### Charts Below the KPIs, four chart sections provide visual breakdowns: 1. **Revenue Chart** -- daily revenue over the selected date range, split by booking and POS revenue in a stacked area chart. 2. **Sales Breakdown** -- donut chart showing the split between booking revenue and POS revenue. 3. **Top Inventory by Revenue** -- ranked bar chart of your highest-earning inventory types. 4. **Top Assets by Revenue** -- ranked bar chart of individual assets by revenue and booking count. ### Checkout metrics A dedicated section tracks checkout funnel performance: | Metric | Description | | --------------------- | ------------------------------------------------------ | | Avg Checkout Time | Average seconds from checkout start to payment | | Avg Payment Time | Average seconds spent on the payment step | | Addon Views | How many times addons were shown during checkout | | Addon Selections | How many addons were actually selected | | Addon Conversion Rate | Percentage of addon views that resulted in a selection | Each metric is compared against industry averages calculated across all RentalTide accounts, so you can benchmark your checkout performance. ### Promo code analytics Summary of promotional code and gift card usage for the selected period, including redemption counts and discount amounts. ### Revenue recognized report Accrual-based revenue recognition breakdown by GL account code. Shows revenue amounts mapped to specific account categories (boat rentals, tours, moorage, addons, etc.) with a bar chart and expandable detail table. ## Live tab A real-time 3D globe visualization showing active booking and engagement events as they happen. Events are plotted geographically with animated markers. ## Engagement tab Track how customers interact with your booking widget across its entire funnel: ### Funnel visualization A vertical funnel chart showing the drop-off at each stage: 1. Widget Loaded 2. Catalog Viewed 3. Product Clicked 4. Booking Configured 5. Checkout Started 6. Booking Completed The funnel uses session drop-off data to calculate cumulative reach at each stage, ensuring a monotonically decreasing visualization. ### Additional engagement metrics - **Daily engagement chart** -- volume of widget interactions over time. - **Temporal heatmap** -- hour-by-day grid showing peak browsing activity (useful for identifying when to run promotions). - **Source breakdown** -- split between embedded widget sessions and standalone booking page sessions. - **Platform comparison** -- your conversion rate compared to the platform-wide average across all RentalTide accounts. ## Sessions tab Detailed session-level analytics for the selected date range. View individual user sessions with their journey through the booking flow, time spent, and outcome. ## Forecast tab AI-powered demand prediction that analyzes your historical booking patterns, seasonal trends, and current pipeline. ### Forecast chart A line chart showing predicted vs. actual bookings for the selected forecast window (5, 7, or 14 days). Includes confidence intervals to indicate prediction certainty. ### Forecast table Day-by-day breakdown with: - Predicted booking count - Confidence level (high, medium, low) - Staffing recommendation (high, normal, low) - Historical data quality assessment ### Accuracy tracking A separate chart comparing past forecasts against actual results to help you calibrate trust in the predictions. ### Data upload Upload historical booking data (from before you started using RentalTide) to improve forecast accuracy. The model performs better with more historical context. {% callout type="note" %} The forecast requires at least 30 days of booking history to produce meaningful predictions. Accuracy improves as more data accumulates. {% /callout %} ## Pricing tab Analyze the relationship between your pricing strategy and customer behavior. This tab requires dynamic pricing to be enabled on your account. | Section | Description | | ------------------- | ------------------------------------------------------------ | | Pricing Trends | How your rates have changed over time across inventory types | | Price History | Detailed timeline of price adjustments | | Conversion Impact | Scatter plot of price vs. conversion rate | | Demand Correlation | Price sensitivity analysis across inventory categories | | Revenue Impact | Estimated revenue change from pricing adjustments | | Inventory Breakdown | Per-inventory pricing performance metrics | ## AI Usage tab Monitor your AI feature consumption and costs for the selected date range: - **Feature usage** -- which AI features are being called (smart scheduling, chat, forecasting, anomaly detection). - **Cost breakdown** -- token and API usage by feature and time period. ## Financial Health tab A two-part financial health assessment combining automated ledger analysis with AI-powered anomaly detection. ### Automated analysis Uses ledger insights and the revenue pipeline to display: - Revenue breakdown by category (boat rentals, tours, moorage, addons, protection plans, POS retail). - Payment method distribution (card, cash, terminal, ACH). - Processing fee analysis. - Deferred revenue and accounts receivable status. ### AI anomaly detection Click **AI Anomaly Detection** to run an on-demand AI scan of your financial data for the last 30 days. The scan returns: - **Health Score** -- a 0-100 score with color coding (green above 70, yellow 40-70, red below 40). - **Summary** -- natural-language description of your financial health. - **Anomalies** -- specific issues flagged with severity (critical, high, medium), title, description, and affected dollar amount. Examples of anomalies detected: unexpected revenue drops, refund spikes, pricing inconsistencies, unbalanced ledger entries, and unusual payment patterns. ## Permissions The analytics page requires the `analytics_access` permission. {% callout type="tip" %} Use the date range presets for quick period comparisons (this month vs. last month). The engagement funnel is especially useful for identifying where customers drop off in the booking process. Run the AI anomaly detection weekly to catch financial issues early. Revenue figures exclude refunded amounts for accurate reporting. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Dashboard shows zero** -- Check the date range and location filters. An empty location or future-only date range will return zero results. **Forecast seems inaccurate** -- The model needs at least 30 days of historical data to calibrate. Consider uploading historical data from before your RentalTide start date. **Engagement tab is empty** -- Widget analytics must be enabled and the booking widget must have the analytics snippet installed. Standalone booking page sessions are tracked automatically. **Pricing tab shows no data** -- Dynamic pricing must be enabled on your account. Contact support to activate this feature. **Financial health score is low** -- Review the flagged anomalies for specific issues. Common causes include unbalanced ledger entries, unexpected refund patterns, or missing transaction records. {% /callout %} --- # Capital Source: https://docs.rentaltide.com/reporting/capital/ > Working-capital advances funded directly to your Stripe account with weekly auto-collection, early-payoff support, and cross-currency disbursement Capital is RentalTide's working-capital advance product. Eligible operators can request up to **$10,000** against their last 12 weeks of Stripe processing volume, receive funds directly into their connected Stripe account, and repay over 12 weekly installments with auto-collection. Pay off any time without penalty. {% callout type="note" %} Capital is a **business-purpose advance**, not a consumer loan. It is offered only in markets where we hold a same-currency platform balance: **USD, CAD, and AUD**. Other currencies are not supported. {% /callout %} ## Where to find it Capital lives in the sidebar under the **Financial** product group at `/capital`. The same group contains Payments, General Ledger, and Accounts Receivable. When an advance is active or pending, a banner appears on the **Home** dashboard directly below the changelog so the status is visible at a glance. ## Eligibility To qualify for a Capital advance, your connected Stripe account must have processed at least **$10,000** in the **last 12 weeks** across your locations. Eligibility is computed automatically by reading your Stripe charges with a `created` filter for the trailing 84 days. We cache the result for 24 hours to avoid hammering Stripe; click the refresh icon on the Capital page to force a fresh computation. ### Offer tiering Your maximum offer scales with your processing history: | Trailing 12-week processed | Max advance | | --------------------------- | ----------- | | $10,000 – $24,999 | $2,500 | | $25,000 – $49,999 | $5,000 | | $50,000+ | $10,000 | ### Currency The currency of your advance is set automatically based on your connected Stripe account's `default_currency`. If your account settles in a currency we don't yet support (anything other than USD/CAD/AUD), the eligibility check shows a friendly "not yet available in your currency" message. ## Pricing | Term | Value | | ---------- | -------------------------------------------------- | | APR | 8.99% | | Term | 12 weekly installments | | Origination fee | None | | Prepayment penalty | None | The weekly payment is calculated as a standard amortizing-loan payment. For a $5,000 advance at 8.99% APR over 12 weeks the weekly amount is approximately **$420.92**, with the early weeks weighted toward interest and the later weeks toward principal. The Capital page shows a live quote as you move the amount slider, including: - Weekly payment amount - Total interest you'll pay over the term - Total repayment amount - A 4-week schedule preview before the terms modal ## Applying for an advance 1. Navigate to **Financial → Capital** in the sidebar. 2. If eligible, the page shows your maximum offer at the top. 3. Use the slider to choose any amount from $100 up to your offer. 4. Review the live quote in **Your repayment plan**. 5. Click **Review terms & accept advance**. 6. Read the terms in the modal, check both authorization boxes, and click **Accept and receive**. {% callout type="warning" title="Authorization is required" %} The terms modal requires **two explicit acknowledgements**: that you've read the terms, and that you authorize RentalTide to debit your Stripe balance weekly. Both checkboxes must be ticked before the accept button enables. {% /callout %} The legal text is published at [rentaltide.com/legal/capital-terms](https://rentaltide.com/legal/capital-terms) and the version you accepted is recorded on the advance for audit. ## Disbursement When you accept terms, RentalTide initiates a Stripe transfer from its platform balance directly to your connected Stripe account in your settlement currency. Funds arrive in your Stripe balance within **1 business day** under normal conditions, subject to Stripe's standard payout timing. You'll receive the **exact amount you selected** in your local currency. If your account is in CAD and you picked 5,000, you receive CA$5,000 (RentalTide's USD platform balance handles FX automatically). ### Pending funding If RentalTide's platform balance is temporarily insufficient to cover your advance, the advance is marked `pending_funding` and our finance team is alerted in Slack. The advance is disbursed within **3 business days** at the latest. You can cancel a pending-funding advance at any time before disbursement at no cost. ## Repayment Once disbursed, weekly auto-debits begin **7 days after disbursement** and continue for 12 weeks. ### How collection works Each week, RentalTide reverses a portion of the original disbursement transfer. Reversing the original transfer is supported across borders (Stripe blocks direct cross-country debits, but reversals work because they undo an existing transaction rather than create a new debit). - **Principal portion** is collected by reversing the original disbursement transfer. - **Interest portion** accrues to your location's `outstanding_dues` and is automatically skimmed off your **next customer charges** as a small bump to the application fee. The bump is capped at 10% of any individual charge so it's never noticeable on a single transaction. ### What you'll see The active-advance dashboard shows: - **Outstanding balance** (principal remaining — this is also your early-payoff amount) - **Available Stripe balance** (live read from Stripe) - **Future interest you'd skip** if you paid off today - **Repayment schedule** with one row per week (scheduled / paid / failed / skipped) - **Payment breakdown chart** — a stacked bar chart showing principal vs. interest by week, mortgage-style - **Activity & accounting** — chronological audit log including disbursement transfer ID, every weekly reversal ID, and your connect account ID, all with one-click copy ### Failed collections If your Stripe balance is insufficient on any scheduled debit date, the cron retries the next business day and posts an alert to our internal Slack channel. You'll see a `failed` row in the schedule with the reason. Persistent collection failures (no successful debit for 14+ days) move the advance into `defaulted` status and may result in account suspension and acceleration of the outstanding balance per the [Capital Terms](https://rentaltide.com/legal/capital-terms). ## Early payoff You can pay off the entire principal at any time with no penalty. 1. On the **Pay off early** card, click **Pay off in full**. 2. Confirm the amount and click **Pay** in the dialog. 3. RentalTide reverses the principal portion of the original disbursement transfer immediately. The advance closes, and all remaining scheduled weekly debits are cancelled. Any unpaid interest accrued up to the payoff date stays in your `outstanding_dues` recovery pool and skims from your next charges as normal. {% callout type="tip" %} The "Future interest you'd skip" stat shows exactly how much interest you save by paying off today versus letting the schedule run. {% /callout %} ### Constraints - Early payoff requires your Stripe balance to cover the full outstanding principal. The button is disabled until your balance is sufficient. - Partial early payments are not currently supported via the UI; the cron will continue collecting on schedule. ## Cancellation You can cancel an advance only while it's in `pending_funding` status. Once disbursed, the advance can be settled only by full repayment via the schedule or early payoff. ## Internal alerts RentalTide finance is notified in the `#capital` Slack channel for every meaningful event: | Event | Alert | | ---------------------------- | ------------------------------------------- | | Advance disbursed | New advance with amount, customer, transfer ID | | Pending funding | Platform balance insufficient — manual backfill needed | | Weekly principal collected | Reversal succeeded, interest accrued | | Weekly collection failed | Insufficient connect balance — retrying tomorrow | | Early payoff (full) | Final reversal succeeded | | Early payoff (partial) | Reversal amount, principal remaining | | Early payoff failed | Stripe error code and message | | Advance fully repaid | Advance closed, total interest collected | ## Status reference | Status | Meaning | | ----------------- | ----------------------------------------------------------- | | `pending_funding` | Accepted by merchant, waiting for platform-balance backfill | | `active` | Funds disbursed, weekly schedule running | | `completed` | Principal fully repaid (on schedule or early) | | `defaulted` | Persistent failed collections — escalated | | `cancelled` | Cancelled before disbursement; no funds moved | ## Frequently asked questions ### How much will my weekly payment be? It depends on the amount you take. The Capital page shows a live quote as you adjust the slider — the weekly payment, total interest, and total repayment all update in real time. ### Can I take more than one advance at a time? No. Only one active or pending advance is allowed per customer. Subsequent advances can be requested only after the prior advance is fully repaid. ### What if I close my Stripe account during the term? Closing or revoking access to the connected Stripe account before the advance is repaid in full constitutes a default. The full outstanding balance becomes immediately due. ### Why is my available offer different from another merchant's? Offer amounts scale with your trailing 12-week processed volume. A merchant with $50,000+ in processing qualifies for the full $10,000 ceiling; a merchant just over the $10,000 threshold qualifies for $2,500. ### Will repayments show up in my Stripe dashboard? Yes. Each weekly principal reversal appears in your Stripe transfers list with the description "RentalTide Capital principal repayment". Interest collected on the application fee shows up in your normal payment-fee breakdown. ### Is this regulated as a loan? Capital is structured as a business-purpose advance and is offered only in jurisdictions where it is not regulated as consumer credit. Read the full terms at [rentaltide.com/legal/capital-terms](https://rentaltide.com/legal/capital-terms). --- # Carbon Footprint Source: https://docs.rentaltide.com/reporting/carbon-footprint/ > Environmental impact tracking with CO2 emissions calculation, offset reporting, trend analysis, and equivalency metrics The carbon footprint page tracks the environmental impact of your rental operations. It calculates CO2 emissions from booking usage hours, visualizes trends over time, and reports on offset contributions through RentalTide's climate program. ## How emissions are calculated Emissions are estimated based on two factors: 1. **Usage hours** -- the system calculates total equipment usage hours from each booking's start and end times, capping at 8 hours per day for multi-day rentals. 2. **Emission rate** -- a configurable rate of CO2 emitted per hour of equipment operation (default: 10 kg CO2 per hour). The formula is: ``` CO2 (kg) = usage_hours x emission_rate_per_hour ``` For multi-day bookings, each day is calculated independently with an 8-hour cap per day. ## Headline metrics Four cards are displayed at the top of the page: | Metric | Description | Calculation | | ----------------- | --------------------------------------------------- | ------------------------------------------- | | Total Emissions | Estimated CO2 in kilograms from all rental activity | Sum of per-booking emissions | | RentalTide Offset | CO2 offset through RentalTide's climate program | 10% of total emissions | | Trees Equivalent | Trees needed to absorb the equivalent CO2 | Total emissions / 21.7 kg per tree per year | | Miles Equivalent | Equivalent car miles driven | Total emissions x 2.47 miles per kg | The offset percentage shows what portion of your total emissions is covered by the RentalTide climate program. ## Charts ### Emissions trend An area chart showing CO2 emissions per booking over time. Each data point represents one booking plotted on the date it started. Use this chart to identify seasonal patterns, the impact of fleet changes, or the effect of operational improvements. ### Impact breakdown A pie chart splitting total emissions into two segments: - **Direct Emissions** -- the net emissions after offsets (total minus offset). - **Offset by RentalTide** -- the portion offset through the climate program (10% of total). This visualization helps communicate your environmental commitment to customers and stakeholders. ## Trend indicator The page calculates an emissions trend by comparing the last three bookings against the three before them: | Indicator | Meaning | | ---------- | ------------------------------------ | | Up arrow | Emissions per booking are increasing | | Down arrow | Emissions per booking are decreasing | | Stable | No significant change | A downward trend indicates that your operations are becoming more environmentally efficient, whether through shorter rental durations, more efficient equipment, or operational changes. ## Booking detail table Below the charts, a table lists individual bookings with their emissions data: | Column | Description | | ---------------- | -------------------------------------------- | | Booking ID | Link to the booking record | | Start Date | When the rental began | | End Date | When the rental ended | | Duration (hours) | Calculated usage hours (capped at 8 per day) | | CO2 Emitted (kg) | Estimated emissions for this booking | Click a booking ID to navigate to the booking details page. ## Data source The carbon footprint page pulls data from your booking records. It includes all bookings with valid start and end dates, regardless of status. The calculations run client-side using your booking data, so no separate data pipeline is required. ## Using carbon data Carbon footprint data can be used for: - **Marketing** -- showcase your environmental commitment on your website and booking page. - **Sustainability reporting** -- include emissions data in annual sustainability reports. - **Operational decisions** -- identify high-emission patterns and prioritize fleet upgrades to lower-emission equipment. - **Carbon offset programs** -- use the emissions baseline to purchase additional carbon credits beyond the RentalTide offset. ## Permissions The carbon footprint page requires the `carbon_access` permission. {% callout type="tip" %} The emissions model uses a default rate of 10 kg CO2 per usage hour. Actual emissions vary significantly by equipment type, engine size, and fuel consumption. Use these figures as directional estimates rather than precise measurements. The 8-hour daily cap prevents multi-day bookings from inflating usage hours beyond realistic operating time. For more accurate tracking, consider pairing this data with actual fuel consumption records. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Page shows zero emissions** -- Verify that you have bookings with valid start and end dates. The page needs at least one completed booking to calculate emissions. **Trend indicator shows "stable" even though operations have changed** -- The trend compares only the last 3 bookings against the prior 3. A longer comparison window may be needed for businesses with low booking volume. **Numbers seem too high or too low** -- The default emission rate (10 kg/hour) is an estimate. Actual rates depend on equipment type. Electric boats produce zero direct emissions, while large motor yachts may exceed this rate significantly. **Chart shows "Invalid Date"** -- This occurs when a booking has a malformed start or end date. Check the booking record for data quality issues. {% /callout %} --- # Reports & Exports Source: https://docs.rentaltide.com/reporting/exports/ > Centralized download hub with 18 report types across financial statements, revenue, tax, customers, bookings, transactions, inventory, slips, and staff in CSV, Excel, or JSON format The reports and exports page is your centralized hub for downloading business data. It offers 18 report types organized into 9 categories, with support for CSV, Excel (.xlsx), and JSON output formats. ## Global controls Four controls at the top of the page apply to all exports: | Control | Description | | ---------- | ---------------------------------------------------------------------------- | | Start Date | Beginning of the date range for time-based reports (defaults to 30 days ago) | | End Date | End of the date range (defaults to today) | | Format | Output format -- CSV, Excel (.xlsx), or JSON | | Location | Controlled by the location picker in the navigation bar | Time-based reports require a valid date range. Reports marked as "All records" export everything regardless of dates. ## Available reports ### Financial Statements | Report | Date Range | Description | | ------------------------- | ---------- | -------------------------------------------------------------------- | | Financial Summary | Yes | Revenue, refunds, taxes, and cash flow grouped by period | | Journal Entries | Yes | Double-entry accounting journal with debits, credits, and GL codes | | Trial Balance | Yes | All GL accounts with debit/credit totals and balance validation | | GL Summary | Yes | General ledger account summary with transaction counts | | Accounts Receivable Aging | No | Outstanding balances with current, 30, 60, and 90+ day aging buckets | ### Revenue | Report | Date Range | Description | | ------------------ | ---------- | -------------------------------------------------------------- | | Revenue by Channel | Yes | Transaction breakdown by channel (online, POS, walk-up, phone) | | Ledger Analytics | Yes | Account breakdown, time series, and top accounts by volume | ### Tax | Report | Date Range | Description | | ---------- | ---------- | ----------------------------------------------------------- | | Tax Report | Yes | Tax collected by type (GST, PST, HST) for government filing | ### Customers | Report | Date Range | Description | | ------------- | ---------- | -------------------------------------------- | | Customer List | No | All customer records and contact information | ### Bookings | Report | Date Range | Description | | -------- | ---------- | ----------------------------------------------------------------- | | Bookings | Yes | Booking records with customer details, dates, pricing, and status | ### Transactions | Report | Date Range | Description | | ------------------------ | ---------- | ------------------------------------------------------------------- | | POS Transactions | Yes | Point-of-sale transaction history with payment details | | Tips Report | Yes | Daily breakdown of tips from POS and booking payments | | Payment Method Breakdown | Yes | Transaction totals by payment type (card, cash, account, gift card) | ### Inventory | Report | Date Range | Description | | --------------- | ---------- | ------------------------------------------------------------------------ | | Fleet Inventory | No | Rental fleet items with capacity, configuration, and location assignment | | POS Items | No | Point-of-sale product catalog with pricing and stock levels | | Pricing | No | Duration-based pricing tables and seasonal rate schedules | ### Slips & Moorage | Report | Date Range | Description | | --------------- | ---------- | -------------------------------------------------------------------- | | Slip Ledger | Yes | Slip-related GL accounts (1136, 2112, 4160) with debit/credit totals | | Moorage Revenue | Yes | Moorage revenue and deferred revenue summary | ### Staff | Report | Date Range | Description | | ---------- | ---------- | ----------------------------------------------------------------- | | Timesheets | Yes | Staff clock-in/out records with hours, breaks, and overtime flags | ## Generating a report 1. Set the **date range** using the date pickers (for time-based reports). 2. Select the **format** -- CSV, Excel, or JSON. 3. Choose the **location** from the navigation bar. 4. Click **Download** on the report card. A progress bar appears during download. The timestamp of the last download is displayed next to each report card. ## Output formats | Format | Extension | Best For | | ------ | --------- | -------------------------------------------------------- | | CSV | .csv | Spreadsheet import, accounting software, payroll systems | | Excel | .xlsx | Formatted spreadsheets with proper column types | | JSON | .json | Programmatic consumption, data warehousing, custom tools | ### Excel format details Excel exports are generated client-side using the downloaded data. For reports that return JSON from the server (Trial Balance, GL Summary, AR Aging, Revenue by Channel, Payment Method Breakdown, Ledger Analytics), the data is automatically converted into a formatted Excel worksheet. For CSV-based reports, the CSV is parsed into rows and written to an Excel sheet. ### JSON format details Some reports are natively JSON on the server (marked with a "JSON" badge on the card). These return structured data that includes nested objects and arrays. When downloading these as CSV, the system flattens the data into tabular format automatically. ## Report details ### Trial Balance Shows all GL accounts with their debit and credit totals for the selected period. Use this to verify that your books balance (total debits should equal total credits). Includes account codes, account names, and net balances. ### Accounts Receivable Aging Displays outstanding customer balances organized into aging buckets: | Bucket | Description | | -------- | -------------------------- | | Current | Invoices not yet past due | | 30 Days | 1-30 days past due | | 60 Days | 31-60 days past due | | 90+ Days | More than 90 days past due | This report does not use the date range -- it shows the current state of all outstanding balances. ### Revenue by Channel Breaks down revenue by booking source: online widget, POS walk-up, phone reservations, and other channels. Useful for understanding which acquisition channels drive the most revenue. ### Payment Method Breakdown Shows transaction volume and dollar amounts by payment type: card, cash, terminal, account charges, and gift cards. Helps with cash management and reconciliation. ### Ledger Analytics Monthly time-series data with GL account breakdowns. Shows debit and credit flows over time and highlights the accounts with the highest transaction volume. ## Location filtering When a specific location is selected, exports include only data for that location. When **All Locations** is selected, exports default to the first location's data. {% callout type="tip" %} Use the Trial Balance report at month-end to verify your books balance before closing the period. The AR Aging report is essential for tracking overdue customer accounts. Match your export date ranges to your accounting periods for clean reconciliation. The Journal Entries format is designed for direct import into accounting software like Xero and QuickBooks. Excel format preserves numeric types, making it easier to work with financial data in spreadsheets. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Export downloads an empty file** -- Widen the date range or verify the selected location has data for the chosen period. **Numbers differ from Stripe** -- Pending or processing transactions may not appear until they settle. Compare using the same date range and account for processing delays. **Excel file has "No data" in the sheet** -- The selected filters returned zero results. Adjust date range or location and try again. **CSV opens with garbled columns** -- Use Excel's "Import from Text/CSV" feature rather than double-clicking. Select comma as the delimiter. **Download button is disabled** -- For time-based reports, the date range must be valid (start date before end date). Fix the dates and the button will enable. {% /callout %} --- # Ledger Source: https://docs.rentaltide.com/reporting/ledger/ > Double-entry accounting ledger with transaction grouping, 15+ filters, manual journal entries, audit trail, balance validation, and Xero sync The ledger is a full double-entry accounting journal that records every financial event in your system. Use it to audit transactions, investigate discrepancies, create manual adjustments, and sync entries to external accounting software. ## Page layout The ledger page is divided into four sections: 1. **Export controls** -- format selection and download buttons. 2. **Filter panel** -- 15+ filters for narrowing results. 3. **Summary statistics** -- aggregate totals for the current filter set. 4. **Entry table** -- the filtered list of ledger entries or grouped transactions. ## Filtering entries The filter panel supports extensive criteria to help you find exactly what you need: | Filter | Description | | ------------------ | ------------------------------------------------------------------ | | Date Range | Start and end dates for the entry period (defaults to last 7 days) | | Location | Filter by business location | | Customer ID | Filter to a specific customer | | Account Code | GL account code (e.g., 4000 for revenue, 1100 for cash) | | Booking ID | Filter to entries related to a specific booking | | Transaction ID | Filter to a specific POS or payment transaction | | Account ID | Filter by customer account (for accounts receivable) | | Side | Show only debit or credit entries | | Min Amount | Minimum entry amount | | Max Amount | Maximum entry amount | | Text Search | Free-text search across descriptions | | Include Deleted | Show soft-deleted entries alongside active ones | | Group Transactions | Collapse related entries into transaction groups | | Balance Filter | All, Balanced only (debits equal credits), or Unbalanced only | Click **Apply Filters** to refresh the results. Click **Reset** to return to defaults. ## Transaction grouping When **Group Transactions** is enabled (the default), the ledger collapses related debit and credit entries into logical groups. Each group shows: | Field | Description | | --------------- | ----------------------------------------------------------- | | Transaction ID | The shared transaction identifier linking the entries | | Entry Count | Number of individual entries in the group | | Total Debits | Sum of all debit amounts | | Total Credits | Sum of all credit amounts | | Balanced | Whether debits equal credits (green check or red warning) | | Register | The POS register or system that created the entries | | Payment Methods | Payment types used in the transaction | | Account Codes | GL accounts involved | | Time Span | Duration between the earliest and latest entry in the group | | Has Edits | Whether any entry in the group has been modified | | Has Deleted | Whether any entry in the group has been soft-deleted | Click a group row to expand it and see the individual entries. ## Summary statistics The summary section at the top shows aggregate totals for the current filter set: | Metric | Description | | ----------------------- | ---------------------------------------------- | | Total Entries | Number of entries matching the current filters | | Total Transactions | Number of grouped transactions | | Total Debits | Sum of all debit amounts | | Total Credits | Sum of all credit amounts | | Balanced Transactions | Groups where debits equal credits | | Unbalanced Transactions | Groups where debits do not equal credits | | Account Breakdown | Per-GL-account debit and credit totals | ## Individual entry fields Each ledger entry contains: | Field | Description | | ---------------- | ----------------------------------------- | | Entry ID | Unique identifier | | Account Code | GL account code | | Amount | Dollar amount | | Side | Debit or Credit | | Description | Human-readable description of the entry | | Transaction Date | When the financial event occurred | | Created At | When the entry was recorded in the system | | Location | Business location | | Booking ID | Associated booking (if applicable) | | Transaction ID | Associated transaction (if applicable) | | Payment Method | How the payment was made | | Created By | User or system that created the entry | ### Audit fields Entries that have been modified or deleted carry additional audit information: | Field | Description | | --------------- | ------------------------------------------------------------- | | Last Edited At | Timestamp of the most recent edit | | Last Edited By | User who made the edit | | Edit Reason | Explanation for the modification | | Is Manual Entry | Whether the entry was created manually (vs. system-generated) | | Deleted At | Timestamp of soft deletion | | Deleted By | User who deleted the entry | | Delete Reason | Explanation for the deletion | ## Creating manual entries Manual journal entries allow you to record adjustments, write-offs, or corrections that did not originate from a booking or POS transaction. 1. Click **New Entry**. 2. Add one or more line items. Each line requires: - **Account Code** -- select from your configured GL codes. - **Amount** -- the dollar amount. - **Side** -- Debit or Credit. - **Description** -- what this entry represents. 3. Enter a **reason** for the manual entry. 4. Set the **location**, **transaction date**, and any other reference fields. 5. Verify that total debits equal total credits. The form warns you if the entry is unbalanced. 6. Click **Save**. Manual entries are flagged as `isManualEntry: true` in the audit trail. ## Editing entries Click the edit icon on any entry to modify it. You can change the account code, amount, side, and description. A reason field is required for all edits to maintain the audit trail. ## Deleting entries Entries are soft-deleted -- they are hidden by default but can be viewed using the **Include Deleted** filter. The delete reason and deletion timestamp are recorded. Deleted entries can be distinguished from active ones in the grouped transaction view. Deleting ledger entries requires admin permissions. ## Export The ledger supports two export formats: | Format | Description | | ------ | --------------------------------------------------- | | CSV | Comma-separated values for spreadsheet applications | | Excel | Native Excel (.xlsx) format with formatted columns | Export options include: - **Include Deleted** -- include soft-deleted entries in the export. - **Group Transactions** -- export grouped transactions rather than individual entries. - **Include Audit Trail** -- add edit history columns to the export. - **Export Type** -- Ledger (standard journal) or AR Report (accounts receivable focus). ## Xero integration Each ledger entry tracks its Xero sync status: | Status | Meaning | | ---------- | --------------------------------------------- | | Not Synced | Entry has not been pushed to Xero | | Pending | Sync has been queued | | Synced | Successfully synced to Xero with a journal ID | | Failed | Sync attempt failed (error message available) | Synced entries display the Xero transaction ID and journal ID for cross-reference. Failed entries show the error message and last attempt timestamp. {% callout type="note" %} Xero sync requires an active Xero OAuth connection configured in the [App Store](/admin/app-store). GL codes in RentalTide must match codes in your Xero chart of accounts. {% /callout %} ## GL account codes The ledger uses a standard chart of accounts. Common codes include: | Code | Name | Category | | --------- | ------------------- | --------- | | 1100 | Cash | Asset | | 1136 | Deferred Revenue | Asset | | 2112 | Unearned Revenue | Liability | | 4000 | Revenue | Revenue | | 4160 | Moorage Revenue | Revenue | | 6545 | Boat Rental Revenue | Revenue | | 8190-8196 | Processing Fees | Expense | Your complete GL code list is configured in account settings and can be customized for your business. ## Permissions The ledger page requires the `reports_access` permission. Manual entry creation and editing require admin-level access. {% callout type="tip" %} Enable **Group Transactions** to see related debits and credits together -- this makes understanding a complete financial event much easier. Use the **Unbalanced** filter to quickly spot discrepancies that need investigation. Manual entries are useful for adjustments, write-offs, or corrections that did not originate from a booking or POS transaction. Run the **AR Report** export regularly to track outstanding customer balances. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Ledger shows unbalanced transactions** -- Use the Unbalanced filter to isolate problem groups. Common causes include interrupted transactions, failed payment processing, or partial refunds that were not fully recorded. **Missing entries** -- Check the date range filter (defaults to last 7 days). Also verify that **Include Deleted** is set correctly for your search. **Xero sync failing** -- Re-authenticate your Xero connection in the App Store. Verify that all GL codes used in your ledger exist in your Xero chart of accounts. Check the error message on failed entries for specific issues. **Cannot create a manual entry** -- Manual entry creation requires admin permissions. Contact your account administrator. **Export is too large** -- Narrow the date range or filter by specific account codes to reduce the result set before exporting. {% /callout %} --- # Payments Source: https://docs.rentaltide.com/reporting/payments/ > Stripe Connect payment reporting with direct access to payouts, transaction details, disputes, and balance information The payments page provides a direct link to your Stripe Connect dashboard for detailed payment reporting. RentalTide processes all payments through Stripe Connect, and this page gives you quick access to Stripe's native reporting tools. ## How it works RentalTide uses Stripe Connect to process payments for each location. Each location has its own Stripe connected account with a unique `connectId`. The payments page reads this identifier and opens the corresponding Stripe dashboard in a new browser tab. ## Accessing reports 1. Select the **location** you want to view from the location picker in the navigation bar. 2. Click **View Reports**. 3. Stripe opens in a new tab, authenticated to that location's connected account. {% callout type="note" %} You must select a specific location -- the page prompts you to choose one if All Locations is selected. Each location has its own Stripe account and must be viewed separately. {% /callout %} ## Available in Stripe Once inside the Stripe dashboard, you have access to: ### Payouts View all payouts to your bank account with dates, amounts, and status. Track pending payouts and see when funds will arrive. Stripe provides automatic payout reconciliation reports. ### Transaction details Drill into individual charges, refunds, and transfers. Each transaction shows the full payment lifecycle including authorization, capture, and settlement. Filter by date, amount, status, or payment method. ### Disputes and chargebacks Review active disputes and chargebacks. Respond to disputes directly in Stripe with evidence uploads. Track dispute resolution outcomes and associated fees. ### Balance Check your current Stripe balance including: - **Available balance** -- funds ready for payout. - **Pending balance** -- funds from recent transactions awaiting settlement. - **Connect reserve** -- any held funds for risk management. ### Stripe-native exports Stripe offers its own export features within the dashboard: - Transaction-level CSV exports. - Payout reconciliation reports. - Monthly financial reports. - 1099 tax forms (for U.S. accounts). ## Relationship to RentalTide reports The payments page and the RentalTide analytics/export pages serve different purposes: | Feature | Payments (Stripe) | Analytics / Exports (RentalTide) | | --------------- | ---------------------------- | ----------------------------------------------- | | Data source | Stripe payment processor | RentalTide application database | | Real-time | Yes | Cached (5-minute refresh) | | Scope | Payment transactions only | Bookings, POS, inventory, staff, and financials | | Reconciliation | Settlement-level detail | Business-level aggregation | | Refund tracking | Full Stripe refund lifecycle | Refund amounts on bookings | For day-to-day financial reporting, the RentalTide [Analytics](/reporting/analytics) and [Exports](/reporting/exports) pages are typically more useful. Use the Stripe dashboard for payment-specific tasks like dispute management, payout tracking, and bank reconciliation. ## Permissions The payments page requires the `reports_access` permission. {% callout type="tip" %} Bookmark the Stripe dashboard link for each location if you access it frequently. Use Stripe's built-in date range filters for month-end reconciliation. Stripe data is real-time with no caching delay, making it the best source for checking recent transaction status. Compare Stripe payout amounts against your bank statements to verify reconciliation. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **"Select one location" message appears** -- The payments page requires a specific location. Change the location picker from All Locations to a single site. **Stripe dashboard shows a different account** -- Each location has its own Stripe connected account. Make sure you have selected the correct location in RentalTide before clicking View Reports. **Cannot access Stripe** -- Verify that Stripe Connect has been set up for the selected location. New locations need to complete the Stripe onboarding process before payment reports are available. **Amounts differ between Stripe and RentalTide** -- Stripe shows settled amounts after processing fees. RentalTide shows gross amounts before Stripe fees. Additionally, timing differences may exist for transactions near the boundary of your selected date range. {% /callout %} --- # Staffing Source: https://docs.rentaltide.com/staffing/ > Schedule, timesheets, time off, shift swaps, and staff tracking Tools for scheduling your team, tracking hours, managing time off, and monitoring staff in the field. {% cardGroup cols=2 %} {% card title="Schedule" href="/staffing/schedule/" /%} {% card title="Timesheets" href="/staffing/timesheets/" /%} {% card title="Time off" href="/staffing/time-off/" /%} {% card title="Shift swaps" href="/staffing/shift-swaps/" /%} {% card title="Staff tracking" href="/staffing/staff-tracking/" /%} {% /cardGroup %} --- # Schedule Source: https://docs.rentaltide.com/staffing/schedule/ > Staff shift scheduling with weekly grid, AI generation, reusable templates, recurring shifts, geofence management, and kiosk integration The schedule page is your central hub for building and managing staff shifts. It displays a weekly grid of all staff members and their assigned shifts, with tools for manual scheduling, AI-powered generation, reusable templates, and geofence configuration. ## Page layout The schedule page has two tabs, visible to managers and admins: 1. **Schedule** -- the weekly shift grid with navigation and creation tools. 2. **Geofences** -- draw and manage location geofence boundaries on a satellite map (manager-only). A **Staff Portal URL** is displayed at the top of the page. Share this link with your team so they can view their schedules, set availability, request time off, and initiate shift swaps from any device. ## Weekly schedule grid The grid shows one row per staff member and one column per day of the week (Sunday through Saturday). Each cell displays the shifts assigned to that person on that day. ### Navigation | Control | Action | | ---------------------- | ------------------------------------------------- | | Previous / Next arrows | Move back or forward one week | | Today button | Jump to the current week | | Staff count chip | Shows total staff members on the schedule | | Shifts count chip | Shows total number of shifts for the visible week | ### Reading the grid - Shift blocks display the start and end times. - Click any shift block to open the edit dialog where you can change times, reassign staff, delete the shift, or request a swap. - When viewing **All Locations**, a location badge appears on each shift so you can distinguish assignments across sites. - Today's column is highlighted for quick reference. ## Creating a shift 1. Click **Add New Shift** in the toolbar. 2. Select a **location** (defaults to the currently selected location). 3. Choose the **staff member** from the dropdown. Both Auth0 users and kiosk-only staff appear here. 4. Set the **start time** and **end time**. 5. Optionally enable **Recurring** and choose a recurrence pattern. 6. Click **Create**. The staff member receives a push notification when a new shift is assigned. ## Editing and deleting shifts Click any shift block in the grid to open the edit dialog: - **Edit** -- change the assigned staff member, location, start time, or end time. The staff member is notified of the change. - **Delete** -- remove the shift entirely. A confirmation dialog prevents accidental deletion. - **Request Swap** -- initiate a shift swap request from this shift (see the [Shift Swaps](/staffing/shift-swaps) page). ## AI schedule generation Click **AI Schedule** in the toolbar to have RentalTide generate an optimized schedule for the selected week and location. The AI considers: - Staff availability preferences and overrides - Skills and certifications - Historical booking demand patterns for the date range - Labor rule compliance Each generated shift is created as an individual schedule entry. Review the results in the grid, then edit or delete any shifts that need adjustment. {% callout type="note" %} AI scheduling requires a specific location to be selected -- it is disabled when viewing All Locations. {% /callout %} ## Templates Templates let you save a shift pattern and apply it to any staff member and week. ### Creating a template 1. Click **Manage Templates** in the toolbar. 2. Enter a **template name** (e.g., "Morning Dock Shift"). 3. Set the **start time** and **end time**. 4. Select the **days of the week** this template applies to. 5. Click **Create**. Templates are stored per location. ### Applying a template 1. Open **Manage Templates**. 2. Find the template you want to apply. 3. Select the **staff member** and **start date** (the beginning of the target week). 4. Click **Apply**. Shifts are created for each selected day within that week. ### Editing and deleting templates From the Manage Templates dialog, click the edit or delete icon on any existing template. Editing a template does not change shifts that were already created from it. ## Recurring shifts When creating a shift, enable the **Recurring** toggle to have the shift repeat automatically. Set a recurrence pattern (daily, weekly, etc.) and the system will generate matching shifts. ## Kiosk mode Click **Kiosk** in the header to enable kiosk mode, which turns the current device into a self-service clock-in station. Staff members clock in using their PIN. Click **Lock** to secure the kiosk screen when it is unattended. Kiosk staff members -- those who clock in via PIN rather than a full login -- appear alongside Auth0-authenticated users in the schedule grid. Their shifts and time entries are tracked identically. ## Geofence tab The geofence tab (manager-only) lets you define a geographic boundary for each location. This boundary is used to verify that staff clock in and out from the correct site. 1. Select a location from the dropdown. 2. Use the polygon drawing tool on the satellite map to outline your site boundary. 3. Toggle **Geofence Enabled** to activate or deactivate enforcement. 4. Click **Save**. When a staff member clocks in or out from outside the geofence, the time entry is flagged for manager review. ## Permissions The schedule page requires the `staff_schedule_access` permission. Users with Admin or SuperAdmin roles have access automatically. {% callout type="tip" %} Use templates for recurring weekly patterns to save time during schedule building. Share the staff portal URL with your team so they can check their own schedules without needing admin access. The geofence feature works with the TideOps mobile app to verify staff location at clock-in. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Staff member not appearing on the schedule** -- Verify they have been added in Staff Management and assigned to the correct location. Kiosk-only staff also appear if they have clocked in at least once. **AI Schedule button is disabled** -- Select a specific location from the location picker. AI scheduling does not work in All Locations mode. **Template not applying shifts** -- Confirm the selected days of the week match working days in the target week. Templates only create shifts on the days configured in the template. **Geofence not saving** -- Draw a complete polygon (close the shape). The save button is disabled until a valid polygon exists on the map. {% /callout %} --- # Shift Swaps Source: https://docs.rentaltide.com/staffing/shift-swaps/ > Three-step shift swap workflow with staff request, target acceptance, manager approval, and pending time-off review The shift swaps page is the central hub for managing shift trade requests and pending time-off approvals. It combines two functions: processing shift swap requests between staff members and reviewing time-off override requests. ## Page sections The page displays two sections: 1. **Pending Time Off Requests** (manager-only) -- a table of staff availability overrides awaiting approval. 2. **Swap Requests Panel** -- incoming and outgoing shift swap requests. ## Shift swap workflow Shift swaps follow a three-step process with notifications at each stage: ### Step 1: Staff requests a swap A staff member initiates a swap from either the schedule page or the staff portal: 1. Select the shift they want to give up. 2. Optionally choose a specific colleague to swap with, or leave it open for anyone. 3. Add an optional message explaining the reason. 4. Submit the request. The request is created with a **pending** status and expires after 7 days if no action is taken. If a target colleague was specified, they receive a push notification. ### Step 2: Target accepts The target staff member (or any eligible colleague for open requests) reviews the swap: 1. View the incoming swap request with the shift details and message. 2. Select one of their own upcoming shifts to offer in exchange. 3. Click **Accept**. The request status changes to **accepted** and the original requester is notified that the swap is pending manager approval. ### Step 3: Manager approves A manager with the `staff_schedule_access` permission reviews the accepted swap: 1. View both the requester's and target's shift details. 2. Click **Approve** to execute the swap, or **Reject** with an optional reason. When approved, the system automatically: - Swaps the `staffId` on both schedule records so each person now owns the other's shift. - Sends push notifications and in-app notifications to both staff members. - Updates the swap request status to **approved**. When rejected, the requester receives a notification with the rejection reason. ## Swap request statuses | Status | Meaning | | --------- | ------------------------------------------------------- | | Pending | Request submitted, waiting for target to accept | | Accepted | Target accepted, waiting for manager approval | | Approved | Manager approved, shifts have been swapped | | Rejected | Manager denied the swap | | Cancelled | Requester cancelled the request before it was processed | | Expired | Request expired after 7 days without action | ## Incoming vs. outgoing requests The swap panel shows two views: - **Incoming** -- swap requests targeting the current user, plus any open (unassigned) requests from colleagues. Your own requests are filtered out. - **Outgoing** -- swap requests you have submitted. You can cancel pending requests from this view. ## Cancelling a request A requester can cancel their own swap request at any time before it is approved. Click **Cancel** on the outgoing request. Only the original requester can cancel -- not the target or another staff member. ## Pending time-off requests The top section of the page (visible to managers only) shows a table of pending availability overrides from staff. Each row displays: | Column | Description | | ------- | --------------------------------------------------- | | Staff | The staff member's name | | Date | The requested date | | Type | "Off" (unavailable) or "Available" (modified hours) | | Hours | Full day or the specific time window | | Reason | The staff member's explanation | | Actions | Approve or Deny buttons | Click **Approve** to confirm the time-off request or **Deny** to reject it. The staff member receives a push notification with the decision. ## Notifications The swap system sends notifications at each transition: | Event | Recipient | Channel | | -------------------- | ------------ | -------------------------- | | Swap request created | Target staff | Push notification + in-app | | Swap accepted | Requester | Push notification + in-app | | Swap approved | Both staff | Push notification + in-app | | Swap rejected | Requester | Push notification + in-app | | Time off approved | Staff member | Push notification | | Time off rejected | Staff member | Push notification | ## Permissions - Any staff member with `staff_schedule_access` can view and create swap requests. - Manager approval and time-off decisions require the same permission plus Admin or SuperAdmin role. {% callout type="tip" %} Encourage staff to submit swap requests early so there is adequate time for the target to accept and the manager to review. Open requests (without a specific target) are visible to all eligible colleagues, which can fill swaps faster. Review pending time-off requests promptly -- they block staff from planning until resolved. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Cannot approve a swap** -- The swap must be in "accepted" status first. The target staff member needs to accept before the manager can approve. **Swap request disappeared** -- Check if it expired (7-day expiry) or if the requester cancelled it. Expired requests are no longer shown in the active list. **Both staff do not see the updated schedule** -- After approval, both staff should refresh their schedule view. The shift reassignment happens immediately on approval. **Manager cannot see pending time-off requests** -- The section only appears when there are pending requests. If no overrides are waiting for review, the section is hidden. {% /callout %} --- # Staff Tracking Source: https://docs.rentaltide.com/staffing/staff-tracking/ > Real-time GPS tracking of on-shift staff with live map, geofence status, scheduled vs. tracked indicators, and WebSocket updates The staff tracking page provides a real-time map view of your team's locations during their shifts. It combines live GPS data from the TideOps mobile app with schedule data to give you a complete picture of who is where. ## Map view The page displays a full-screen Mapbox satellite map with markers for each tracked staff member. Each marker shows the staff member's initials and is color-coded by status: | Color | Meaning | | ------------------ | -------------------------------------------------------- | | Indigo | On shift and inside the location geofence | | Red | On shift but outside the location geofence | | Gray | Scheduled but not actively tracked (last known position) | | Blue (highlighted) | Currently selected staff member | Click any marker to select a staff member and view their details in the sidebar panel. ## Header indicators The header bar displays real-time counts: | Indicator | Description | | --------- | ------------------------------------------------------------------------------- | | On Shift | Number of staff members actively reporting their location | | On-Site | Number of staff members currently inside a location geofence | | Scheduled | Number of staff who are scheduled but not yet tracked (no active location data) | ## How tracking works 1. **Location updates** -- the TideOps mobile app sends GPS coordinates to the server every 60 seconds while a staff member is clocked in. 2. **Geofence evaluation** -- each location update is checked against the geofence boundary configured for that location (see [Schedule > Geofence tab](/staffing/schedule)). 3. **WebSocket broadcast** -- the server pushes location updates to all connected manager dashboards in real time via WebSocket, so the map refreshes without polling. 4. **Schedule correlation** -- the page fetches today's schedule and cross-references it with active location data to identify who is tracked, who is scheduled but not tracked, and who is unscheduled. ## Staff categories The tracking page groups staff into three categories: ### Actively tracked Staff who have the TideOps app running and are sending location updates. Their markers on the map update in real time and show exact position, geofence status, and last report timestamp. ### Scheduled with last known location Staff who are on today's schedule but are not currently sending location updates. If a last known position exists (from a previous session), it is displayed with a gray marker. This helps you see where someone was last seen. ### Scheduled without location Staff who are on today's schedule but have never sent location data (TideOps not installed, location permissions denied, or first-time setup). These appear in a sidebar list rather than on the map. ## Staff sidebar Click a marker or a name in the scheduled-without-location list to open the staff detail panel. The sidebar shows: - Staff member name and initials - Geofence status (inside or outside) - Last reported timestamp (e.g., "3m ago" or "Just now") - Assigned location ## Schedule filtering The page only shows staff with shifts within a one-hour window of the current time. This means: - Staff whose shift started up to 1 hour in the future appear as "scheduled." - Staff whose shift ended up to 1 hour ago still appear until they are fully off the clock. This window prevents the map from being cluttered with shifts that are not relevant to the current moment. ## Staff identity resolution The tracking system handles two types of staff identities: - **Auth0 users** -- staff who log in with email and password. - **Kiosk staff** -- staff who clock in with a PIN and may have a separate UUID. The system cross-references these identities so that a kiosk staff member's location data is correctly matched to their schedule, even if the IDs differ. The name displayed always comes from the most specific profile available. ## Refresh Click the refresh button in the map controls to force a reload of all staff locations. Location data also auto-refreshes via WebSocket connections for connected browsers. ## Requirements Staff tracking requires: 1. The **TideOps** mobile app installed on the staff member's device. 2. **Location permissions** granted in the app. 3. An active shift -- tracking only runs during clocked-in hours. 4. The `matrix_access` permission for managers viewing the tracking page. ## Privacy - Tracking is active only during scheduled and clocked-in work hours. - Location data is not collected when a staff member is off the clock. - GPS coordinates are stored with timestamps for audit purposes but are only retained for the operational period. {% callout type="tip" %} Pair staff tracking with geofences to get automatic alerts when staff clock in from outside your site boundary. The "Scheduled" indicator helps identify staff who may need help setting up the TideOps app. Use the refresh button if the map seems stale -- WebSocket reconnections may occasionally delay updates. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Staff member is on shift but not appearing on the map** -- Confirm they have the TideOps app installed with location permissions enabled. Check that they have clocked in for their current shift. **Marker shows red (outside geofence)** -- The staff member's GPS position is outside the geofence polygon drawn on the Schedule page. This may indicate they are off-site, or the geofence boundary may need to be expanded. **"Scheduled" count is high but "On Shift" is low** -- Many staff are on the schedule but have not clocked in or do not have the TideOps app. Follow up to ensure app installation. **Map is blank** -- Verify that you have the `matrix_access` permission. Also check that there are staff scheduled for the current time window. {% /callout %} --- # Availability & Time Off Source: https://docs.rentaltide.com/staffing/time-off/ > Staff self-service availability management with weekly recurring rules, date-specific overrides, and manager approval workflow The availability page lets staff members define their recurring weekly schedule preferences and submit date-specific time-off overrides. Managers review and approve override requests to ensure adequate coverage. ## How it works The availability system has two layers: 1. **Weekly availability rules** -- recurring patterns that define which days and hours a staff member is generally available to work. 2. **Date-specific overrides** -- one-time entries for specific dates where availability differs from the weekly pattern (time off, schedule changes, or extra availability). Staff manage both from the self-service portal or from this page when logged in. Overrides submitted by staff are held in a **pending** state until a manager approves or rejects them. ## Weekly availability rules Each day of the week (Sunday through Saturday) can be configured with: | Field | Description | | ---------------- | ---------------------------------------------------------------- | | Available toggle | Whether the staff member is available on this day | | Start Time | Earliest available time | | End Time | Latest available time | | Notes | Optional notes (e.g., "Only mornings" or "School pickup at 3pm") | ### Setting weekly rules 1. Open the availability page. 2. For each day of the week, toggle availability on or off. 3. If available, set the start and end times. 4. Add any notes for the scheduling manager. 5. Click **Save** on each row you change. Changes to weekly rules take effect immediately and are visible to managers when building schedules. These do not require approval -- they are informational preferences. ## Date-specific overrides Overrides let staff request time off or modify availability for a specific date. Each override includes: | Field | Description | | ---------------- | --------------------------------------------------------------------------- | | Date | The specific date the override applies to | | Available | Whether the staff member is available or unavailable | | Start / End Time | If available, the modified hours (leave blank for a full-day off) | | Reason | Explanation for the override (e.g., "Doctor appointment" or "Family event") | ### Submitting an override 1. Select the **date** for the override. 2. Set availability to **Off** (for time off) or **Available** (for modified hours). 3. If taking a partial day, set the start and end times. 4. Enter an optional **reason**. 5. Click **Submit**. The override enters a **pending** state and appears in the manager's approval queue on the [Shift Swaps](/staffing/shift-swaps) page. ### Override statuses | Status | Meaning | | -------- | ------------------------------------------- | | Pending | Submitted by staff, awaiting manager review | | Approved | Manager has approved the request | | Rejected | Manager has denied the request | ### Viewing overrides The override list shows all overrides for the next 90 days. Each entry displays the date, type (off or available), hours, reason, and current status. Staff can delete their own overrides as long as they have not yet been approved. ## Manager approval Managers approve or reject pending overrides from the [Shift Swaps](/staffing/shift-swaps) page, which displays a **Pending Time Off Requests** section. For each pending request, the manager sees: - Staff member name - Requested date - Type (Off or Available) - Hours (Full day or specific times) - Reason Click **Approve** or **Deny** to process the request. The staff member receives a push notification with the decision. ## Integration with scheduling Availability rules and approved overrides inform the scheduling process: - The **AI Schedule** generator on the [Schedule](/staffing/schedule) page uses availability data to avoid assigning shifts during unavailable times. - Managers can view all staff availability when building schedules manually. - The system does not strictly enforce availability -- managers can schedule outside of stated preferences when operationally necessary. ## Permissions All authenticated staff members can view and manage their own availability. Manager-level actions (viewing all staff availability, approving overrides) require the `staff_schedule_access` permission. {% callout type="tip" %} Encourage staff to keep their weekly availability current so AI scheduling and manual planning work from accurate data. Override requests submitted well in advance give managers time to adjust coverage. Weekly rules are preferences, not guarantees -- managers may still assign shifts outside stated hours during peak periods. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Override is stuck in Pending** -- A manager needs to approve or reject it from the Shift Swaps page. Remind your manager if the request has been pending for an extended period. **Weekly availability not saving** -- Verify you are clicking the save button on each individual day row. Changes are saved per day, not as a batch. **Staff cannot see the availability page** -- They need the `staff_schedule_access` permission or access through the staff portal. Check their user permissions in Staff Management. {% /callout %} --- # Timesheets Source: https://docs.rentaltide.com/staffing/timesheets/ > Employee time tracking with clock-in/out records, break management, overtime detection, pay period navigation, manager approval, and payroll CSV export The timesheets page gives managers a complete view of staff time entries across pay periods. Review clock-in and clock-out records, track breaks, flag overtime, approve entries, and export payroll-ready data. ## Pay period navigation The page is organized around configurable pay periods. Use the navigation controls to move between periods: | Control | Action | | ---------------------- | -------------------------------------------------------------------------------- | | Current button | Jump to the pay period containing today | | Previous / Next arrows | Move one pay period backward or forward | | Date range chip | Shows the start and end dates of the current period | | Period type chip | Displays the active pay period type (Weekly, Biweekly, Semi-monthly, or Monthly) | ## Pay period settings Click the settings icon to configure your pay period: | Setting | Description | | ------------------------- | ----------------------------------------------------------------- | | Period Type | Weekly, Biweekly, Semi-monthly, or Monthly | | Start Day | Which day of the week the period begins (for weekly and biweekly) | | Anchor Date | Reference date for biweekly period alignment | | Overtime Daily Threshold | Hours per day before overtime kicks in (default: 8) | | Overtime Period Threshold | Hours per period before overtime kicks in (default: 40) | Pay period settings are saved at the account level and apply to all locations. ## Viewing time entries The timesheet panel displays a table of all time entries within the selected pay period. Each entry shows: | Column | Description | | ----------- | ----------------------------------------------------------------------- | | Staff Name | Employee name (from Auth0 login or kiosk profile) | | Date | The date of the shift | | Clock In | Timestamp when the employee clocked in | | Clock Out | Timestamp when the employee clocked out (or "Active" if still on shift) | | Break | Total break time in minutes | | Total Hours | Net hours worked (clock-out minus clock-in minus breaks) | | Status | Current state of the entry | | Location | The location where the shift was worked | ### Entry statuses | Status | Meaning | | ----------- | ---------------------------------- | | Clocked In | Staff member is currently on shift | | On Break | Staff member is on an active break | | Clocked Out | Shift completed, awaiting review | | Approved | Manager has approved the entry | Entries where the clock-in or clock-out occurred outside the location geofence are flagged with a location indicator for manager review. ## Clock-in and clock-out Staff clock in through one of three methods: 1. **Kiosk** -- enter their PIN on a shared tablet at the location. 2. **Staff Portal** -- log in to the self-service portal from any device. 3. **TideOps Mobile App** -- clock in from the field with GPS coordinates captured. When clocking out, the system automatically: - Calculates net hours worked (subtracting break time). - Checks the daily overtime threshold against the configured limit. - Checks the weekly/period overtime threshold against cumulative hours. - Records GPS coordinates if provided and evaluates geofence compliance. Auto clock-out is supported for shifts that exceed a maximum duration without manual clock-out. ## Break tracking Staff can start and end breaks during their shift: 1. Start a break -- status changes to **On Break** and the timer begins. 2. End the break -- the duration is added to the cumulative break minutes for that entry. Multiple breaks per shift are supported. The total break time is subtracted from gross hours to calculate net hours worked. ## Overtime detection Overtime is calculated at clock-out based on two thresholds: - **Daily** -- if the current shift exceeds the daily threshold (default 8 hours minus breaks), it is flagged as overtime. - **Period** -- if the cumulative hours for the pay period (including the current shift) exceed the period threshold (default 40 hours), it is flagged as overtime. Overtime entries are visually distinguished in the timesheet table. ## Manager actions Managers with the `staff_schedule_access` permission can: - **Approve entries** -- click the approve button to mark a completed entry as approved. - **Edit entries** -- adjust clock-in time, clock-out time, break minutes, notes, or status. Edits are available through the edit dialog on each row. - **Force clock-out** -- end an active shift from the manager view if a staff member forgot. ## Payroll export Click **Export Payroll** to download time entry data as a CSV file. 1. Click **Export Payroll** in the header. 2. The date range defaults to the current pay period. Adjust if needed. 3. Click **Download CSV**. ### Export columns | Column | Description | | ----------- | ------------------------------- | | Staff Name | Employee name | | Date | Shift date | | Clock In | ISO timestamp | | Clock Out | ISO timestamp | | Break (min) | Total break minutes | | Total Hours | Net hours worked | | Overtime | Yes or No | | Status | Entry status at time of export | | Notes | Any notes attached to the entry | The export respects the selected location filter. If a specific location is selected, only entries for that location are included. ## Filtering Use the location picker in the navigation bar to filter entries by location. Select **All Locations** to see entries across all sites. {% callout type="tip" %} Review timesheets before the end of each pay period to catch missing clock-outs. Export payroll data on a consistent schedule that matches your payroll provider's import window. The CSV format is compatible with most payroll systems including ADP, Gusto, and QuickBooks. {% /callout %} {% callout type="warning" title="Troubleshooting" %} **Entry shows "Active" but the shift ended hours ago** -- The staff member forgot to clock out. Use the edit dialog to set the correct clock-out time manually. **Overtime flag seems wrong** -- Check the pay period settings. Overtime thresholds are configurable and may differ from your local labor law defaults. **Export is empty** -- Verify that the date range covers the correct pay period and that a location with time entries is selected. **Staff member not appearing in timesheets** -- They must have at least one clock-in during the selected pay period. Verify they are using the correct login or kiosk PIN. {% /callout %}