Skip to main content
RapidDev - Software Development Agency
bubble-integrationsBubble API Connector

Practo

Connect Bubble to Practo's partner API (Practo Ray) by adding the API Connector plugin and placing your partner API key in a Private header — Bubble proxies calls server-side, so CORS is not an issue. Because Practo handles sensitive patient health data, Privacy rules on every Bubble Data Type that stores Practo-sourced records are mandatory, not optional. Practo Ray partner credentials are required before any API call is possible.

What you'll learn

  • How to configure Bubble's API Connector with Practo Ray partner credentials as a Private header
  • How to initialize API Connector calls with real clinic data to unlock them as usable data sources
  • How to build custom appointment queue and patient check-in pages on top of Practo data
  • How to set Bubble Privacy rules to protect sensitive patient health information
  • How to handle Practo API pagination for large patient or appointment lists
  • How to add action calls for appointment status updates via the API Connector
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate19 min read2–4 hours (after receiving partner credentials)Health & FitnessLast updated July 2026RapidDev Engineering Team
TL;DR

Connect Bubble to Practo's partner API (Practo Ray) by adding the API Connector plugin and placing your partner API key in a Private header — Bubble proxies calls server-side, so CORS is not an issue. Because Practo handles sensitive patient health data, Privacy rules on every Bubble Data Type that stores Practo-sourced records are mandatory, not optional. Practo Ray partner credentials are required before any API call is possible.

Quick facts about this guide
FactValue
ToolPracto
CategoryHealth & Fitness
MethodBubble API Connector
DifficultyIntermediate
Time required2–4 hours (after receiving partner credentials)
Last updatedJuly 2026

Building a Custom Clinic Operations Panel on Top of Practo in Bubble

Practo Ray is the dominant clinic management platform across India and South Asia, handling appointment scheduling, electronic patient records, and consultation tracking for tens of thousands of clinics. For clinic owners and hospital IT teams, Practo's default interface works well for day-to-day operations — but building custom workflows on top of Practo data (appointment routing, custom dashboards, integration with proprietary hospital systems) requires API access.

Practo's API is not a public developer API with a self-serve sign-up — it is a partner program API for healthcare businesses enrolled in the Practo Ray program. Before building anything in Bubble, the clinic must have Practo Ray partner credentials (an API key assigned to the facility). Without these credentials, no calls to api.practo.com will succeed. Start the Practo Ray partner enrollment before writing any Bubble configuration.

Once partner credentials are in hand, the Bubble integration is straightforward: the API Connector plugin calls api.practo.com from Bubble's servers with the partner key in a Private header. Because Bubble proxies API calls server-side, CORS is not an issue — unlike FlutterFlow or a vanilla React frontend where API keys in headers can be intercepted. The Private checkbox in the API Connector's header configuration ensures the key never leaves Bubble's server infrastructure.

The most important ethical and legal consideration: appointment records and patient data retrieved from Practo constitute Protected Health Information (PHI) under India's PDPB (Personal Data Protection Bill) and potentially HIPAA if the clinic also serves international patients. Bubble's database should be used as a view layer over the Practo API wherever possible — avoid storing full patient records in Bubble unless your data processing agreements and Bubble plan explicitly support it. When you do store data, Bubble Privacy rules are your primary access control mechanism and must be configured before any patient data is saved.

Integration method

Bubble API Connector

Call the Practo Ray partner API (api.practo.com) from Bubble's API Connector with your partner API key placed in a Private header. Bubble runs these calls server-side — your credentials never reach the browser. Partner credentials from Practo Ray's program are required; there is no public self-serve API key.

Prerequisites

  • Active Practo Ray partner credentials (API key assigned to your clinic) — there is no sandbox or public dev key; apply through Practo Ray enrollment before starting the Bubble build
  • A Bubble account (the free plan is sufficient for API Connector read calls; Backend Workflows for inbound webhooks require a paid plan)
  • Your Practo site/clinic ID (assigned during Practo Ray enrollment — used as a parameter in most API calls)
  • Basic understanding of Bubble's API Connector plugin, Data Types, and Privacy rules
  • Legal authorization from your clinic's data officer to store any patient data in Bubble's database, in compliance with applicable health data regulations

Step-by-step guide

1

Apply for Practo Ray partner credentials and understand the data constraints

Practo's API access is reserved for clinics and healthcare businesses enrolled in the Practo Ray program. To apply, contact Practo directly through their website (practo.com/ray) or your existing Practo account manager. Explain your use case — building a custom operations dashboard, kiosk check-in flow, or multi-clinic aggregation panel. Practo will provide an API key linked to your clinic's site ID. While waiting for credentials, clarify two critical constraints with your clinic's legal or data officer: (1) Patient data from Practo (names, phone numbers, appointment history, medical notes) is sensitive health information. In India it is regulated under data privacy legislation; for clinics serving international patients, additional regulations may apply. Before storing any Practo-sourced patient records in Bubble's database, ensure your data processing agreements cover this. (2) Practo's API does not have publicly documented endpoint specifications — Practo provides documentation to approved partners, but endpoints and parameters may change without public notice. Build defensively: every Bubble workflow that calls Practo must handle empty or error responses gracefully, not crash. Also note: Practo's sibling platform documentation from other integration platforms confirms the base URL is https://api.practo.com, but exact endpoint paths and parameter formats should be verified against the documentation Practo provides with your partner credentials. This guide uses patterns consistent with REST conventions and confirmed partner documentation patterns.

Pro tip: Ask Practo for a test environment or a test clinic site ID during onboarding. Some API programs provide a sandbox with synthetic data — this lets you initialize and test the Bubble API Connector without touching live patient records.

Expected result: You have a Practo Ray API key and your clinic's site ID. You have reviewed the data privacy constraints and confirmed your legal authorization to build with Practo data. You have the API documentation from Practo.

2

Install the API Connector and configure the Practo API group

In your Bubble editor, click the Plugins tab in the left sidebar. Click 'Add plugins', search for 'API Connector', and install the API Connector by Bubble (free, official Bubble plugin). After installation, the API Connector appears in your Plugins tab. Click on API Connector and then click 'Add another API'. Name this API group 'Practo'. In the Authentication section, select 'None or self-handled' — you will add the API key manually as a custom header rather than using Bubble's built-in OAuth flow. Set the API base URL to https://api.practo.com. Now add a shared header that applies to all Practo calls. Click 'Add a shared header'. Set the key to Api-Key (match this exactly to what Practo's documentation specifies — it may be Api-Key, api-key, or x-api-key depending on your partner documentation). Set the value to your partner API key. CRITICAL: check the 'Private' checkbox next to this header. This tells Bubble to keep this header server-side and never include it in any data sent to the browser. The Private checkbox is the core security mechanism in Bubble's API Connector — without it, your partner key would be visible in browser network requests. If your Practo API documentation specifies a site ID or clinic ID header, add it as another shared header. If it is a URL parameter instead, you will configure it at the call level in the next step.

practo_api_connector_config.json
1{
2 "api_name": "Practo",
3 "base_url": "https://api.practo.com",
4 "authentication": "None or self-handled",
5 "shared_headers": [
6 {
7 "key": "Api-Key",
8 "value": "YOUR_PRACTO_PARTNER_API_KEY",
9 "private": true
10 },
11 {
12 "key": "Content-Type",
13 "value": "application/json",
14 "private": false
15 }
16 ]
17}

Pro tip: If Practo's documentation shows the key as a URL parameter rather than a header (e.g., ?api_key=...), configure it as a shared URL parameter in the API Connector and mark it Private. The Private flag works on both headers and parameters.

Expected result: The API Connector 'Practo' group exists in Bubble with the base URL set to https://api.practo.com and the Api-Key header added with the Private checkbox checked. The setup is ready for adding individual API calls.

3

Add the appointments list call and initialize with real clinic data

Within the Practo API group, click 'Add another call'. Name this call 'Get Appointments'. Set the method to GET and the endpoint path to the appointments endpoint from your Practo partner documentation (typically something like /v1/appointments or /appointments, with your clinic's site ID as a path segment or query parameter). Add URL parameters that Practo requires: date (today's date in the format Practo expects, e.g., YYYY-MM-DD), site_id (your clinic identifier), and optionally status (to filter by appointment status) and page/per_page (for pagination). For the date parameter, you can set a default test value for initialization and make it dynamic when used in workflows. Set 'Use as' to 'Data' — this tells Bubble this call returns a list of records you can bind to UI elements, not just trigger a side effect. Click 'Initialize call'. Bubble will make a real HTTP GET request to the Practo API using your credentials. The initialization must succeed with actual data from your clinic — Bubble records the response shape and makes each field available as a selectable property in the editor. IMPORTANT: If initialization fails with 'There was an issue setting up your call', the most common causes are: (1) incorrect API key (copy-paste error, extra whitespace), (2) the endpoint path differs from what Practo's documentation shows, or (3) required parameters are missing or in the wrong format. Check the exact error by temporarily removing the Private checkbox, running the call, and looking at the browser's network inspector — then re-check Private immediately. After successful initialization, add a second call for individual appointment details (GET /appointments/{id}), a third for patient lookup if your use case needs it, and a POST call for updating appointment status.

practo_api_calls.json
1{
2 "call_name": "Get Appointments",
3 "method": "GET",
4 "path": "/v1/appointments",
5 "use_as": "Data",
6 "parameters": [
7 { "key": "date", "value": "2026-07-09", "description": "Date in YYYY-MM-DD format" },
8 { "key": "site_id", "value": "YOUR_CLINIC_SITE_ID", "description": "Practo clinic site identifier" },
9 { "key": "status", "value": "scheduled", "description": "Filter: scheduled, checked-in, completed" },
10 { "key": "page", "value": "1", "description": "Page number for pagination" },
11 { "key": "per_page", "value": "50", "description": "Records per page" }
12 ]
13}
14
15{
16 "call_name": "Update Appointment Status",
17 "method": "POST",
18 "path": "/v1/appointments/<appointment_id>/status",
19 "use_as": "Action",
20 "body": {
21 "status": "<dynamic: new status>"
22 }
23}

Pro tip: Initialize with real clinic data that has at least 5–10 appointments. Bubble infers field types from the initialization response — an empty or minimal response may result in fields being incorrectly typed (e.g., a date field recognized as text). More representative data gives better type inference.

Expected result: The 'Get Appointments' call is successfully initialized and shows as a usable data source in Bubble's editor. The response fields (appointment ID, patient name, scheduled time, doctor, status) are detectable and selectable in the editor. A status update action call is also initialized.

4

Create Bubble Data Types and configure Privacy rules for patient data

Even when using Practo primarily as a live API data source (not storing records), you may need Bubble Data Types for operational state — tracking check-in status, adding internal notes, or caching appointment data for display. If your workflow stores any Practo-sourced patient information in Bubble, Privacy rules are mandatory. Create an Appointment Data Type with fields: practo_appointment_id (text), patient_name (text), patient_phone (text), scheduled_time (date), doctor_name (text), status (text), checked_in_at (date), clinic_staff_note (text), user (User — the clinic staff member who last interacted with this record). Create a Patient Data Type only if you are storing patient records (not just appointment references): patient_id (text), name (text), phone (text), last_appointment (date). Now go to the Data tab → Privacy tab. For Appointment: click 'Define rules for Appointment'. Add a condition: 'This Appointment is visible when Current User is logged in AND Current User has a role of clinic_staff'. Never use 'Everyone can view' for appointment or patient records. For the Patient type (if used): same restriction — clinic staff only. Click 'Find fields exposed to others' and confirm that no fields are accessible to logged-out users or users without the clinic staff role. For Bubble apps used by multiple clinic staff members, add a 'role' option field to the User Data Type (values: reception, nurse, doctor, admin) and configure Privacy rules to match appropriate access levels — receptionists see appointment queue but not consultation notes, doctors see their own patient records only, admins see all. RapidDev's team regularly builds custom clinic dashboards on top of healthcare APIs — for complex multi-role access control or PDPB compliance questions, a free scoping call is available at rapidevelopers.com/contact.

Pro tip: If you are using Practo purely as a display layer (no data stored in Bubble — just fetching and showing), you do not need Data Types for Practo records. You can bind the API Connector call directly to a Repeating Group's data source without persisting anything. This is the lowest-risk approach for handling sensitive patient data.

Expected result: Appointment and Patient Data Types (if used) exist with Privacy rules restricting visibility to authenticated clinic staff. The 'Find fields exposed to others' tool shows no patient fields are publicly accessible. Role-based access is configured on the User type.

5

Build the appointment queue dashboard page

Create a new page in Bubble named 'appointment_queue'. Set a page condition: 'Only show page content when Current User is logged in AND has clinic_staff role' — redirect to a login page otherwise. This ensures patients or unauthenticated users cannot access the queue. Add a Repeating Group to the page. For the data source, click 'Do a search for' and in the Type dropdown look for the API Connector call. Select 'Get Appointments' from the Practo API group. Wire the date parameter to today's date (use the expression 'Current date/time') and the site_id to a constant or app-level configuration value. Set pagination: use Bubble's built-in pagination on the Repeating Group, or manually pass the page parameter to load records in batches. Inside each cell of the Repeating Group, add Text elements for: Current cell's appointment's scheduled_time (formatted as HH:MM AM/PM), Current cell's appointment's patient_name, Current cell's appointment's doctor_name, Current cell's appointment's status. Add a Dropdown element with options (Waiting, Checked In, In Consultation, Completed) that triggers a workflow on change: run API Connector action 'Update Appointment Status' with the current cell's appointment ID and the selected dropdown value. Add a 'Refresh' button above the Repeating Group that re-runs the API Connector Get Appointments call. For auto-refresh, use a Timer element (Bubble Toolbox plugin) set to trigger every 120 seconds and re-run the appointments search. For pagination handling of large clinic queues: add 'Load More' button below the Repeating Group that increments the page parameter and fetches the next batch. Practo's API returns paginated results — never try to fetch all records at once for clinics with large appointment volumes, as this can hit Bubble's 30-second workflow timeout and wastes API rate limit quota.

Pro tip: Display appointment times in the clinic's local timezone. Practo API timestamps may be in UTC — use Bubble's date formatting with timezone conversion to show the correct local time on the dashboard. Verify the timezone format Practo returns by checking the initialization response carefully.

Expected result: A clinic operations dashboard page shows today's appointment queue from Practo in a Repeating Group, with scheduled time, patient name, doctor, and status columns. Staff can update appointment status via the dropdown. A refresh button and optional auto-refresh keep the queue current.

6

Handle pagination and add error response management

Practo's API returns paginated responses for appointment lists. A busy clinic with 80+ appointments in a day must load them in pages, typically 20–50 records per page. In your Bubble workflow, store the current page number in an App State or a Bubble Data Thing so the 'Load More' button can increment it correctly. For error handling, Bubble's API Connector will throw a workflow error if the Practo API returns a non-2xx status code. Add error handling to every workflow that calls Practo: in the Workflow editor, click the action → Add a 'When an error occurs' handler → show a custom error popup with a friendly message like 'Appointments could not be loaded — please check your connection and try again'. Specifically handle the case where Practo's API key has expired or been revoked (401 Unauthorized response): the error handler should redirect clinic staff to an admin page with instructions to contact the Practo partner account manager. An unhandled 401 that silently shows an empty appointment queue could cause a clinic to miss patient appointments. For empty state: if the Practo call returns an empty appointments list (no appointments today, or no records matching the filter), the Repeating Group will be empty. Add an 'Empty list' state element to the Repeating Group with a message like 'No appointments scheduled for today' — this distinguishes an empty response from an error response.

practo_error_handling.txt
1// Error response handling pattern in Bubble API Connector
2// Add to each Practo-connected workflow:
3
4// Step 1: Call Practo Get Appointments
5// Add error handler: 'When Get Appointments fails'
6// Action: Show element 'ErrorPopup'
7// Set state: ErrorPopup's error_message = error body's message
8
9// Sample Practo error response shapes to handle:
10// 401: { "error": "Unauthorized", "message": "Invalid API key" }
11// 404: { "error": "Not Found", "message": "Site ID not found" }
12// 429: { "error": "Rate Limited", "message": "Too many requests" }
13// 500: { "error": "Server Error", "message": "Internal server error" }

Pro tip: Practo's API does not have fully public documentation, which means endpoint behavior and error response formats may vary from what partner documentation describes. Log every error response to a Bubble Data Thing (ErrorLog type with endpoint, status_code, response_body, timestamp fields) during testing so you have a record of any undocumented behavior to report to Practo's partner support.

Expected result: All Practo API Connector calls have error handlers configured. A 401 response redirects to re-authentication instructions. A 429 rate limit response shows a retry message. Empty appointment lists show a clear 'no appointments' state rather than a blank page.

Common use cases

Custom appointment queue management dashboard

Build a Bubble display screen for clinic reception desks showing today's appointment queue: patient name (or token number), scheduled time, doctor assigned, and current status (waiting, in-consultation, completed). The dashboard pulls today's appointments from the Practo Ray API on page load, with a refresh button that re-runs the API Connector call. Receptionists can update appointment status via Practo API action calls without switching to the full Practo Ray interface.

Bubble Prompt

Build a Bubble page showing today's appointment queue as a Repeating Group with columns for token number, appointment time, patient name, assigned doctor, and status. Filter to today's date only. Add a status dropdown per row that triggers an API Connector action call to update the appointment status in Practo. Auto-refresh the list every 2 minutes.

Copy this prompt to try it in Bubble

Multi-clinic group operations overview

For hospital groups managing multiple Practo-connected clinic sites, build a Bubble operations dashboard that aggregates appointment counts, wait times, and patient throughput across all sites. Each clinic's Practo data is fetched via separate API Connector calls (with site-specific parameters), combined in Bubble, and displayed as a management summary. Clinic managers see which sites are running behind and can drill down to individual appointment queues.

Bubble Prompt

Build a Bubble admin page with a Repeating Group of clinic sites, each showing today's total appointments, number completed, number in waiting, and average wait time. Clicking a clinic row opens a detail panel with the full appointment queue for that site. Data from Practo API filtered by site_id parameter.

Copy this prompt to try it in Bubble

Patient check-in kiosk flow

Create a Bubble patient-facing check-in page on a tablet in the clinic waiting room. Patients enter their mobile number, the API Connector looks up their appointment for today from Practo, and if found, marks them as checked in. The reception dashboard updates in near real-time (polling every 60 seconds). No patient account creation required — the workflow operates entirely on Practo appointment data.

Bubble Prompt

Build a Bubble check-in page: a phone number input field, a 'Check In' button that calls Practo API to find today's appointment for that phone number, and a confirmation screen showing the patient's token number and estimated wait time. On successful check-in, call a Practo API action to update the appointment status to 'checked-in'.

Copy this prompt to try it in Bubble

Troubleshooting

'There was an issue setting up your call' when clicking Initialize in the API Connector

Cause: The initialization request failed — most commonly because the API key is incorrect, the endpoint path differs from what is configured, or required parameters (like site_id or date) are missing or in the wrong format.

Solution: Temporarily uncheck the Private checkbox on the Api-Key header, open your browser's developer tools (F12 → Network tab), click Initialize again, and look at the actual request and response in the network log. Check the response body for error details like 'Invalid API key' or 'Missing parameter'. Fix the issue, then immediately re-check the Private checkbox. Never leave partner API keys without the Private flag in production.

Appointments show on the dashboard but patient names or sensitive fields are blank

Cause: Privacy rules on the Appointment Data Type may be blocking the fields from being readable in the context of the current page. Or the API Connector call's initialization response did not include those fields (e.g., Practo omits patient_name from the list endpoint and requires a separate GET per appointment for details).

Solution: Check two things: (1) Go to Data → Privacy → Appointment and verify the Privacy rule permits reading all fields for logged-in clinic staff users. (2) Review the API Connector's initialized call response structure to confirm whether patient_name is returned in the list endpoint or requires a detail call. Some healthcare APIs return minimal data in list views for performance and privacy reasons, requiring separate calls per record.

The appointment status update action call returns a 403 Forbidden error

Cause: The partner API key may not have write permissions to update appointment status — some Practo partner tiers have read-only API keys by default. Or the endpoint path or body format for the status update does not match what Practo expects.

Solution: Contact your Practo partner account manager and confirm that your API key has write permissions for appointment status updates. Request the exact endpoint path and body format for status mutations from Practo's partner documentation. Verify the request body format (JSON vs. form-encoded) matches what Practo requires.

The Repeating Group shows 50 appointments but there are 80+ in the system today

Cause: Practo's API returns paginated responses. The first call loads page 1 with the per_page limit (e.g., 50 records). Records beyond the first page are not loaded.

Solution: Add a 'Load More' button below the Repeating Group that increments the page parameter and re-runs the Get Appointments call. Alternatively, store all loaded appointments in a Bubble Data Type as they are fetched, then bind the Repeating Group to the Data Type search (which is not paginated). For the Bubble 30-second timeout concern: fetch pages one at a time via user-triggered button clicks rather than using a recursive workflow to load all pages automatically.

Best practices

  • Never store Practo patient data in Bubble's database without explicit legal authorization and appropriate data processing agreements. Use Bubble as a view layer over the Practo API wherever possible — fetch and display, do not persist.
  • Always check the 'Private' checkbox on your Practo Api-Key header in the API Connector. Without it, your partner credentials appear in browser network requests and can be extracted by anyone using your app.
  • Configure Bubble Privacy rules on every Data Type that touches patient or appointment data before adding any records. Health data stored without privacy rules is publicly queryable via Bubble's API endpoints — a serious data breach risk.
  • Initialize each API Connector call with real clinic data containing representative records. An initialization with empty or minimal data leads to poorly typed fields and harder debugging later when real data arrives.
  • Handle empty and error responses explicitly in every Bubble workflow that calls Practo. An unhandled API error should never result in a blank appointment queue — clinic staff need to know whether the queue is empty or whether data failed to load.
  • Use pagination for appointment lists. Clinics with high daily appointment volumes (100+) will exceed any single-page response limit. Design the UI with 'Load More' or automatic pagination from the start rather than retrofitting it.
  • Verify the timezone of all timestamps returned by the Practo API. Display appointment times in the clinic's local timezone using Bubble's date formatting. A time displayed in UTC for an India-based clinic will be 5.5 hours off.
  • Treat Practo's partner API as potentially underdocumented. Log all API responses (status code, endpoint, key response fields) to a Bubble ErrorLog or AuditLog Data Type during testing. This gives you evidence of any endpoint changes or undocumented behavior to discuss with Practo's partner support.

Alternatives

Frequently asked questions

Can I use Practo's API without being enrolled in the Practo Ray partner program?

No. Practo's API is a partner program API — there is no public developer portal where you can create an API key independently. The clinic must be an active Practo Ray subscriber, and the API access is assigned to the clinic's account during partner onboarding. Start the Practo Ray enrollment process before writing any Bubble configuration.

Is there a Practo API sandbox for testing?

Ask your Practo partner account manager specifically about sandbox access. Some healthcare API partner programs provide a test environment with synthetic patient and appointment data — this is the safest way to initialize and test the Bubble API Connector without using live patient records. If no sandbox is available, use a test clinic site with minimal real data during development.

Can I store patient records from Practo in Bubble's database?

You can technically store data in Bubble, but this creates significant legal and compliance obligations. Patient records from Practo are sensitive health information protected under India's data privacy legislation (and potentially HIPAA for international patients). Before storing any Practo-sourced patient data in Bubble, ensure your clinic has appropriate data processing agreements in place and that your Bubble plan's data residency satisfies regulatory requirements. Using Bubble as a view layer (fetch-and-display without persisting) is the lower-risk approach.

Why does my Practo API call succeed in testing but fail in production?

The most common cause is environment-specific API keys — Practo may provide separate API keys for test and production environments, and the production key may not yet be configured in Bubble. Check whether the Practo partner program issued different credentials for production versus development, and update the Private header in the Bubble API Connector accordingly when deploying.

Can Bubble receive real-time updates when an appointment is booked or changed in Practo?

This depends on whether Practo supports outbound webhooks in their partner API. If Practo sends webhook events on appointment creation or status changes, you can receive them via a Bubble Backend Workflow (requires a paid Bubble plan for the Workflow API). Check your Practo partner documentation for webhook support. If Practo does not support webhooks, use a polling approach: a scheduled Bubble workflow that calls Get Appointments on a time interval (e.g., every 2 minutes) and compares results to detect changes.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Integrations are where projects stall

We wire Bubble integrations like this one every week — auth, webhooks, edge cases included. Fixed-price builds from $13K, delivered in 6–10 weeks.

Talk to an integration engineer

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.