Queries

These endpoints allow you to create queries and connections to your databases.

Data connectors let you perform queries against your databases directly from Studio without saving or caching them to Studio. Studio supports several popular databases; learn more here.

Create Query Dataset

Create a query-based dataset without executing the query.

List Data Connectors

List all data connectors added to the authorized account.

List Data Connectors (Organization)

List all data connectors added to your organization.


${value.text.secondary}
`; } async function selectItem({ target }) { if (target.tagName === "BUTTON") { const link = target.dataset.object; const addressDetail = await fetchAddressDetails(link); const { location = {} } = addressDetail; const { address = "", country = "", postcode = "", locality = "", region = "", } = location; addressInput.value = address; address2Input.value = ""; countryInput.value = country; postcodeInput.value = postcode; cityInput.value = locality; regionInput.value = region; // generate new session token after a complete search sessionToken = generateRandomSessionToken(); address2Input && address2Input.focus(); dropDownField.style.display = "none"; } } async function fetchAddressDetails(link) { try { const results = await fetch(`https://api.foursquare.com${link}`, { method: "get", headers: new Headers({ Accept: "application/json", Authorization: fsqAPIToken, }), }); const data = await results.json(); return data; } catch (err) { logError(err); } } function highlightedNameElement(textObject) { if (!textObject) return ""; const { primary, highlight } = textObject; if (highlight && highlight.length) { let beginning = 0; let hightligtedWords = ""; for (let i = 0; i < highlight.length; i++) { const { start, length } = highlight[i]; hightligtedWords += primary.substr(beginning, start - beginning); hightligtedWords += "" + primary.substr(start, length) + ""; beginning = start + length; } hightligtedWords += primary.substr(beginning); return hightligtedWords; } return primary; } function debounce(func, timeout = 300) { let timer; return (...args) => { clearTimeout(timer); timer = setTimeout(() => { func.apply(this, args); }, timeout); }; } } localAddressAutoFillJs(); } if (state && state.params && state.params.slug === "local-search-map") { function loadLocalMapSearchJs() { mapboxgl.accessToken = "pk.eyJ1IjoiZm91cnNxdWFyZSIsImEiOiJjbDNqNXdrN20wN3JtM2JvMWFqZGxoaGljIn0.uSxJ2t7E96TrBFsn3cXT_g"; const fsqAPIToken = "fsq3bgqdcpLAJFkodk8gisc2F+NenA7gK/zI97A9nKQAXIw="; let userLat = 40.7128; let userLng = -74.006; let sessionToken = generateRandomSessionToken(); const inputField = document.getElementById("explorer-search"); const dropDownField = document.getElementById("explorer-dropdown"); const ulField = document.getElementById("explorer-suggestions"); const errorField = document.getElementById("explorer-error"); const notFoundField = document.getElementById("explorer-not-found"); const onChangeAutoComplete = debounce(changeAutoComplete); inputField.addEventListener("input", onChangeAutoComplete); ulField.addEventListener("click", selectItem); function success(pos) { const { latitude, longitude } = pos.coords; userLat = latitude; userLng = longitude; flyToLocation(userLat, userLng); } function logError(err) { console.warn(`ERROR(${err.code}): ${err.message}`); } navigator.geolocation.getCurrentPosition(success, logError, { enableHighAccuracy: true, timeout: 5000, maximumAge: 0, }); const map = new mapboxgl.Map({ container: "map", style: "mapbox://styles/mapbox/light-v10", center: [userLng, userLat], zoom: 12, }); map.addControl(new mapboxgl.GeolocateControl()); map.addControl(new mapboxgl.NavigationControl()); let currentMarker; /* Generate a random string with 32 characters. Session Token is a user-generated token to identify a session for billing purposes. Learn more about session tokens. https://docs.foursquare.com/reference/session-tokens */ function generateRandomSessionToken(length = 32) { let result = ""; const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; for (let i = 0; i < length; i++) { result += characters[Math.floor(Math.random() * characters.length)]; } return result; } let isFetching = false; async function changeAutoComplete({ target }) { const { value: inputSearch = "" } = target; ulField.innerHTML = ""; notFoundField.style.display = "none"; errorField.style.display = "none"; if (inputSearch.length && !isFetching) { try { isFetching = true; const results = await autoComplete(inputSearch); if (results && results.length) { results.forEach((value) => { addItem(value); }); } else { notFoundField.innerHTML = `Foursquare can't find ${inputSearch}. Make sure your search is spelled correctly. Don't see the place you're looking for?.`; notFoundField.style.display = "block"; } } catch (err) { errorField.style.display = "block"; logError(err); } finally { isFetching = false; dropDownField.style.display = "block"; } } else { dropDownField.style.display = "none"; } } async function autoComplete(query) { const { lng, lat } = map.getCenter(); userLat = lat; userLng = lng; try { const searchParams = new URLSearchParams({ query, types: "place", ll: `${userLat},${userLng}`, radius: 50000, session_token: sessionToken, }).toString(); const searchResults = await fetch( `https://api.foursquare.com/v3/autocomplete?${searchParams}`, { method: "get", headers: new Headers({ Accept: "application/json", Authorization: fsqAPIToken, }), } ); const data = await searchResults.json(); return data.results; } catch (error) { throw error; } } function addItem(value) { const placeDetail = value[value.type]; if (!placeDetail || !placeDetail.geocodes || !placeDetail.geocodes.main) return; const { latitude, longitude } = placeDetail.geocodes.main; const fsqId = placeDetail.fsq_id; const dataObject = JSON.stringify({ latitude, longitude, fsqId }); ulField.innerHTML += `
  • ${highlightedNameElement(value.text)}
    ${value.text.secondary}
  • `; } async function selectItem({ target }) { if (target.tagName === "LI") { const valueObject = JSON.parse(target.dataset.object); const { latitude, longitude, fsqId } = valueObject; const placeDetail = await fetchPlacesDetails(fsqId); addMarkerAndPopup(latitude, longitude, placeDetail); flyToLocation(latitude, longitude); // generate new session token after a complete search sessionToken = generateRandomSessionToken(); const name = target.dataset.name; inputField.value = target.children[0].textContent; dropDownField.style.display = "none"; } } async function fetchPlacesDetails(fsqId) { try { const searchParams = new URLSearchParams({ fields: "fsq_id,name,geocodes,location,photos,rating", session_token: sessionToken, }).toString(); const results = await fetch( `https://api.foursquare.com/v3/places/${fsqId}?${searchParams}`, { method: "get", headers: new Headers({ Accept: "application/json", Authorization: fsqAPIToken, }), } ); const data = await results.json(); return data; } catch (err) { logError(err); } } function createPopup(placeDetail) { const { location = {}, name = "", photos = [], rating } = placeDetail; let photoUrl = "https://files.readme.io/c163d6e-placeholder.svg"; if (photos.length && photos[0]) { photoUrl = `${photos[0].prefix}56${photos[0].suffix}`; } const popupHTML = `
    photo of ${name}
    ${name}
    ${location.address}
    ${ rating ? `
    ${rating}
    ` : `
    ` }
    `; const markerHeight = 35; const markerRadius = 14; const linearOffset = 8; const verticalOffset = 8; const popupOffsets = { top: [0, verticalOffset], "top-left": [0, verticalOffset], "top-right": [0, verticalOffset], bottom: [0, -(markerHeight + verticalOffset)], "bottom-left": [ 0, (markerHeight + verticalOffset - markerRadius + linearOffset) * -1, ], "bottom-right": [ 0, (markerHeight + verticalOffset - markerRadius + linearOffset) * -1, ], left: [ markerRadius + linearOffset, (markerHeight - markerRadius) * -1, ], right: [ -(markerRadius + linearOffset), (markerHeight - markerRadius) * -1, ], }; return new mapboxgl.Popup({ offset: popupOffsets, closeButton: false, }).setHTML(popupHTML); } function addMarkerAndPopup(lat, lng, placeDetail) { if (currentMarker) currentMarker.remove(); currentMarker = new mapboxgl.Marker({ color: "#3333FF", }) .setLngLat([lng, lat]) .setPopup(createPopup(placeDetail)) .addTo(map); currentMarker.togglePopup(); } function flyToLocation(lat, lng) { map.flyTo({ center: [lng, lat], }); } function highlightedNameElement(textObject) { if (!textObject) return ""; const { primary, highlight } = textObject; if (highlight && highlight.length) { let beginning = 0; let hightligtedWords = ""; for (let i = 0; i < highlight.length; i++) { const { start, length } = highlight[i]; hightligtedWords += primary.substr(beginning, start - beginning); hightligtedWords += "" + primary.substr(start, length) + ""; beginning = start + length; } hightligtedWords += primary.substr(beginning); return hightligtedWords; } return primary; } function debounce(func, timeout = 300) { let timer; return (...args) => { clearTimeout(timer); timer = setTimeout(() => { func.apply(this, args); }, timeout); }; } } loadLocalMapSearchJs(); } }); $(window).on("pageLoad", function (e, state) { const openSearchPopup = () => { const headerSearch = document.getElementById("hub-search-results"); if (headerSearch) { headerSearch.classList.add("hub-search-results-active"); document .getElementsByClassName("Input Input_md SearchBox-InputUQZAW9QXMe-c")[0] ?.focus(); } }; const triggerSearchButton = document.getElementsByClassName( "landing-page-trigger-search-button" )[0]; if (triggerSearchButton) { triggerSearchButton.addEventListener("click", openSearchPopup); } }); // START: Add Segment Tracking to Try It button // TODO: Verify this runs on route changes, so button gets instrumented on every page $(window).on("load", function (e, state) { var tryItBtn = document.querySelector(".rm-TryIt"); // in case the button has not yet renedered if (tryItBtn === undefined) return; tryItBtn.addEventListener("click", () => { console.log("Try It button Clicked (project)"); analytics.track("Try It button Clicked"); }); }); // END: Add Segment Tracking to Try It button // CUSTOM LAUNCH TOP NAV CODE - README document.addEventListener('DOMContentLoaded', () => { setTimeout(() => { document.querySelectorAll('.Header-leftADQdGVqx1wqU a[href]').forEach(a => { a.addEventListener('click', e => { e.preventDefault(); window.location.href = a.href; }); }); }, 100); }); // CUSTOM LAUNCH SIDEBAR CODE (FINAL project: inject Places first, then Users under Welcome) // Runs after a short delay to avoid flicker or unwanted auto-expansion. document.addEventListener("DOMContentLoaded", function () { // Delay entire injection by 1 second setTimeout(() => { (async function() { // Normalize path (strip trailing slash) const path = window.location.pathname.replace(/\/$/, ''); // Only act on the FINAL project paths if (!path.startsWith('/developer/reference/')) { return; } // Pages to pull from: Places API overview and Users API overview // **Places first**, then Users const toInject = [ { otherPageUrl: '/fsq-developers-places/reference/places-api-overview', targetSectionText: 'Places API' }, { otherPageUrl: '/fsq-developers-users/reference/users-api-overview', targetSectionText: 'Users API' } ]; // If versioned (e.g. /v2023-05-01/ in URL), insert version segment into otherPageUrl const versionMatch = window.location.pathname.match(/\/(v\d{4}-\d{2}-\d{2})\//); function applyVersion(url) { if (versionMatch) { const version = versionMatch[1]; return url.replace('/reference/', `/${version}/reference/`); } return url; } // Fetch & cache a single section's HTML from another page async function fetchSectionHtml(otherPageUrl, targetSectionText) { const versionedUrl = applyVersion(otherPageUrl); const cacheKey = `crossSection:${versionedUrl}:${targetSectionText}`; const cached = sessionStorage.getItem(cacheKey); if (cached) { return cached; } try { const resp = await fetch(versionedUrl, { credentials: 'same-origin' }); if (!resp.ok) { console.warn('[CrossInject] Fetch failed', resp.status, versionedUrl); return null; } const htmlText = await resp.text(); // Parse to DOM const parser = new DOMParser(); const doc = parser.parseFromString(htmlText, 'text/html'); // Find the sidebar section const sidebarSelector = '.rm-Sidebar'; const otherSidebar = doc.querySelector(sidebarSelector); if (!otherSidebar) { console.warn('[CrossInject] Sidebar not found for', versionedUrl); return null; } // Locate the
    whose

    includes targetSectionText let foundSection = null; otherSidebar.querySelectorAll('section').forEach(sec => { if (foundSection) return; const h2 = sec.querySelector('h2'); if (h2 && h2.textContent.trim().includes(targetSectionText)) { foundSection = sec; } }); if (!foundSection) { console.warn('[CrossInject] Section not found:', targetSectionText, 'in', versionedUrl); return null; } const sectionHtml = foundSection.outerHTML; try { sessionStorage.setItem(cacheKey, sectionHtml); } catch (_) {} return sectionHtml; } catch (err) { console.error('[CrossInject] Error fetching/parsing:', err); return null; } } // Wait until the current page's sidebar is present function whenSidebarReady(fn) { const interval = setInterval(() => { const sidebarNav = document.querySelector('.rm-Sidebar'); if (sidebarNav) { clearInterval(interval); fn(sidebarNav); } }, 100); // Stop polling after 5s setTimeout(() => clearInterval(interval), 5000); } // Collapse helper for a section element function collapseSection(sec) { const h2 = sec.querySelector('h2'); const ul = sec.querySelector('ul'); if (h2) { h2.classList.remove('section-expanded'); h2.classList.add('section-collapsed'); h2.setAttribute('aria-expanded', 'false'); } if (ul) { ul.classList.add('section-collapsed'); ul.classList.remove('section-list-expanded'); } } // Expand helper function expandSection(sec) { const h2 = sec.querySelector('h2'); const ul = sec.querySelector('ul'); if (h2) { h2.classList.remove('section-collapsed'); h2.classList.add('section-expanded'); h2.setAttribute('aria-expanded', 'true'); } if (ul) { ul.classList.remove('section-collapsed'); ul.classList.add('section-list-expanded'); } } // Fetch all needed sections in parallel const results = await Promise.all( toInject.map(item => fetchSectionHtml(item.otherPageUrl, item.targetSectionText) .then(html => ({ ...item, sectionHtml: html })) ) ); const validSections = results.filter(r => r.sectionHtml); if (validSections.length === 0) { return; } // Once our sidebar is ready, inject under "Welcome" whenSidebarReady(sidebarNav => { const contentDiv = sidebarNav.querySelector('.hub-sidebar-content'); if (!contentDiv) { console.warn('[CrossInject] .hub-sidebar-content not found; abort insertion.'); return; } // Find "Welcome" section const welcomeSection = Array.from(contentDiv.querySelectorAll('section')).find(sec => { const h2 = sec.querySelector('h2'); return h2 && h2.textContent.trim() === 'Welcome'; }); let insertAfter = welcomeSection; validSections.forEach(({ targetSectionText, sectionHtml }) => { const wrapper = document.createElement('div'); wrapper.innerHTML = sectionHtml; const originalSectionNode = wrapper.firstElementChild; if (!originalSectionNode) { console.warn('[CrossInject] No section node for', targetSectionText); return; } const sectionClone = originalSectionNode.cloneNode(true); // Adapt heading & toggle as needed: const injectedH2 = sectionClone.querySelector('h2'); const injectedUL = sectionClone.querySelector('ul'); if (injectedH2 && injectedUL) { // Copy classes from an existing template

    if present const templateH2 = sidebarNav.querySelector('.hub-sidebar-content section h2'); if (templateH2) { injectedH2.className = templateH2.className; } else { injectedH2.classList.add('Sidebar-headingTRQyOa2pk0gh', 'rm-Sidebar-heading'); } injectedH2.setAttribute('tabindex', '0'); // Remove existing chevrons, clone from template or fallback Array.from(injectedH2.querySelectorAll('.icon-chevron')).forEach(el => el.remove()); if (templateH2) { templateH2.querySelectorAll('.icon-chevron').forEach(iconSpan => { injectedH2.appendChild(iconSpan.cloneNode(true)); }); } else { const fallbackSpan = document.createElement('span'); fallbackSpan.className = 'icon-chevron'; injectedH2.appendChild(fallbackSpan); } // Initially collapsed collapseSection(sectionClone); // Toggle handler const toggleFn = () => { const isCollapsed = injectedUL.classList.contains('section-collapsed'); if (isCollapsed) { expandSection(sectionClone); } else { collapseSection(sectionClone); } }; injectedH2.style.cursor = 'pointer'; injectedH2.addEventListener('click', toggleFn); injectedH2.addEventListener('keydown', e => { if (e.key === 'Enter' || e.key === ' ' || e.key === 'Spacebar') { e.preventDefault(); toggleFn(); } }); } // Nested toggles sectionClone.querySelectorAll('a.Sidebar-link_parent').forEach(aParent => { let btn = aParent.querySelector('button'); if (!btn && aParent.nextElementSibling && aParent.nextElementSibling.tagName === 'BUTTON') { btn = aParent.nextElementSibling; } let subUl = null; if (btn) { const maybeUl = btn.parentElement.nextElementSibling; if (maybeUl && maybeUl.classList.contains('subpages')) subUl = maybeUl; } if (!subUl) { const parentLi = aParent.closest('li'); if (parentLi) { const maybe = parentLi.querySelector('ul.subpages'); if (maybe) subUl = maybe; } } if (btn && subUl) { // collapsed by default btn.setAttribute('aria-expanded', 'false'); subUl.classList.add('section-collapsed'); subUl.classList.remove('section-list-expanded'); btn.style.cursor = 'pointer'; btn.addEventListener('click', e => { e.preventDefault(); const expanded = btn.getAttribute('aria-expanded') === 'true'; if (expanded) { btn.setAttribute('aria-expanded', 'false'); subUl.classList.add('section-collapsed'); subUl.classList.remove('section-list-expanded'); } else { btn.setAttribute('aria-expanded', 'true'); subUl.classList.remove('section-collapsed'); subUl.classList.add('section-list-expanded'); } }); } }); // Insert right after Welcome (Places first, then Users) if (insertAfter && insertAfter.parentElement === contentDiv) { insertAfter.insertAdjacentElement('afterend', sectionClone); insertAfter = sectionClone; } else { contentDiv.appendChild(sectionClone); } console.log(`[CrossInject] Injected "${targetSectionText}" after Welcome.`); }); // After injecting both, auto-expand whichever matches current path function normalizeHref(href) { try { const url = new URL(href, window.location.origin); return url.pathname.replace(/\/$/, ''); } catch { return href.replace(/\/$/, ''); } } const normPath = window.location.pathname.replace(/\/$/, ''); // Clear any previous active marks: contentDiv.querySelectorAll('a[aria-current]').forEach(a => { a.removeAttribute('aria-current'); a.classList.remove('active'); }); // Find matches among injected links: const allLinks = Array.from(contentDiv.querySelectorAll('a')); allLinks.forEach(a => { const href = a.getAttribute('href'); if (!href) return; if (normalizeHref(href) === normPath) { // mark active a.setAttribute('aria-current', 'page'); a.classList.add('active'); // expand its parent section let sec = a.closest('section'); if (sec) expandSection(sec); // expand ancestors let anc = a.parentElement; while (anc && anc !== contentDiv) { if (anc.tagName === 'UL' && anc.classList.contains('subpages')) { anc.classList.remove('section-collapsed'); anc.classList.add('section-list-expanded'); const parentLi = anc.closest('li'); if (parentLi) { const btn = parentLi.querySelector('button[aria-expanded]'); if (btn) btn.setAttribute('aria-expanded', 'true'); } } if (anc.tagName === 'SECTION') { expandSection(anc); } anc = anc.parentElement; } } }); // If none matched exactly, all remain collapsed. }); })(); }, 600); });