faiNET
faiNET

Welcome to faiNET-FaisalNetworks — chat with AI, build apps, and deploy them, all from one account.

Get API
Build App
Host App
Check Your API
Buy Domains
Use Templates
Get API
Build App
Host App
Check Your API
Buy Domains
Use Templates

By continuing, you agree to faiNET's Terms of Service and Privacy Policy.

Preview Mode

Take a local, read-only tour of faiNET. Payments, deployments, and account changes are unavailable in Preview Mode.

👁 Preview Mode — you're browsing without an account
Faisal Hadawal
· WEB & MOBILE DEVELOPMENT STUDIO ·

faiNET

OWNER: FAISAL HADAWAL
Free Pro Advance
📄
Use Template
🔌
Get API
🚀
Host for your web
📱
Build App
+50PROJECTS
+10KUSERS
+12MONTHS EXPERIENCE
Editor not loading below? Some sites block embedding.

API Keys Management & Studio

Create 20-digit API keys starting with FaiNxxx... (no repeated characters). Use these keys to power a Translator app, a Messenger, an AI Chatbot, or a Search Engine.

Create New API Key

Translator App (text-to-text, language detection)
Messenger (chat + notifications)
AI Chatbot (text, photo & audio understanding)
Search Engine (web search results)

Active API Keys (0/10)

Playground

Test any of your API keys against a real AI model, powered by this site's own Cloudflare Functions.

Sends a real request through your first API key to an AI model. Uses real OpenRouter credits — send deliberately.

This key also works from any other app — just send it as a Bearer token to this same endpoint:
curl -X POST https://YOUR-SITE.pages.dev/api/chat \ -H "Authorization: Bearer YOUR_FAINET_KEY" \ -H "Content-Type: application/json" \ -d '{"message":"hello"}'

Development & Hosting

Pick a project, then deploy, configure and monitor it.

Project Overview

ProjectfaiNET.com
StatusNot deployed
Live Link
Last Deploy

Deploy Files

Click, or drag & drop a folder/files here

Live Link & Logs

Waiting for deploy…

Configuration

Environment Variables

Saved with your project. On every Deploy, these are injected as window.ENV into your HTML files automatically — read them in your JS with window.ENV.KEY.

Guide

1. Pick your project above.
2. Go to Deploy, drag & drop your project folder/files (or click to select), then hit Deploy.
3. Your project goes live at fainet.pages.dev/u/<yourFaisalID>/<project>/ — check it under Deploy.
4. Give your project a memorable name when creating it — that becomes part of the live link.
5. Files upload straight to your faiNET account — no build step needed for plain HTML/CSS/JS.

App Builder

Build mobile and desktop apps easily.

faiNET App Builder

Coming soon.

Buy a Domain

Coming soon — real domain search & registration is being finished up.

Buy a Domain

Search for a domain and connect it to your faiNET site.

All Available Domains

My Domains

Templates

Ready-made starters from the community — like, comment, and download.

Default
Top
Others
Yours

faiNET Ecosystem Projects

Complete systems, apps, and learning experiments built by Faisal Hadawal. (Separate from your own projects under Development.)

Notifications

Updates about your account, deploys, and payments.

faiNET Platform Policies & Terms

Review our guidelines, privacy terms, API usage rules, and developer standards.

1. API Key & Chatbot File Upload Policy

API keys generated here grant full permissions for connected Chatbots and external apps to upload and analyze text, photos, audio, network files, docs, and zips.

2. Development & Deployment Security

All files uploaded via Development hosting are encrypted and securely processed.

3. App Builder Guidelines

App Builder generates application packages based on provided web URLs.

4. Privacy & Data Protection

Personal credentials and sessions are securely managed by Faisal Hadawal.

5. Subscription & Payment Terms

Payments are processed directly via Hesab Pay, without needing external ID verification.

6. Faisal ID — Unified Identity

Every account is tied to a single Faisal ID (a unique handle, similar to a GitHub username). This same ID is meant to carry across all of Faisal Hadawal's products — faiNET, fcode, faisal-AI-assistant, and future apps — so one identity works everywhere.

System Settings & Plans

Manage your platform preferences, appearance, subscription tiers, and support options.

Appearance & Theme
Switch between Dark Neon and Clean Light interface styles.
⚡ Subscription & Resource Plans
Choose the appropriate tier for your project requirements.
Free Plan
$0 / forever
  • 10 API keys
  • 30 Dev deployments
  • 10 App Builder
Pro Plan
$20 / month
  • 100 API keys
  • 300 Dev deployments
  • 100 App Builder
Advanced Plan
$199 / year
  • 1,000 API keys
  • 3,000 Dev deployments
  • 1,000 App Builder
Support & Donate ($2 - $500)
Support Faisal Hadawal's independent development studio and open-source projects.
Payment History
Real record of your upgrades and donations, tied to your account.

Log in with a real email account to see your history here.

powered by cloudflare

Main Control

Manage every faiNET account and platform-wide settings. Visible only to admins.

Platform Management

Add User

Users (0)

Profile

Set your name, cover photo, and profile photo — shown at the top of Home.

Your faiNET Site

Deploy under Development to publish your site at this address.

Name

Cover Photo

Profile Photo

\n` : ''; for (const file of pendingFiles) { const relPath = (file.webkitRelativePath || file.name).replace(/^[^/]+\//, ''); const finalPath = relPath || file.name; let contentBase64 = await new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = () => resolve(reader.result.split(',')[1]); reader.onerror = reject; reader.readAsDataURL(file); }); // Real effect for Variables: inject window.ENV into every HTML file // right before (or at the top if there's no ), so the // project's own JS can read the values it saved. if (varsScript && /\.html?$/i.test(finalPath)) { const html = atob(contentBase64); const injected = /<\/head>/i.test(html) ? html.replace(/<\/head>/i, varsScript + '') : varsScript + html; contentBase64 = btoa(unescape(encodeURIComponent(injected))); } const res = await fetch('/api/deploy', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + sessionToken }, body: JSON.stringify({ project: subdomain, path: finalPath, contentBase64 }) }); const result = await res.json(); if (!res.ok || !result.ok) { deployConsole.innerHTML += `
⚠ Failed on ${finalPath}: ${result.error || res.statusText}
`; deployConsole.scrollTop = deployConsole.scrollHeight; return; } liveUrl = result.url; deployConsole.innerHTML += `
✓ ${finalPath}
`; deployConsole.scrollTop = deployConsole.scrollHeight; } data.deployed = true; data.liveLink = liveUrl.replace(/^https?:\/\//, ''); data.lastDeploy = new Date().toLocaleString(); setCurrentProjectData(data); renderProjectPanels(); deployConsole.innerHTML += `
✅ Deployed for real! Live at ${liveUrl}
`; deployConsole.scrollTop = deployConsole.scrollHeight; showToast('Deployed live!', 'success'); pushNotification('Your project was deployed successfully.', ICON_ROCKET); } catch (err) { deployConsole.innerHTML += `
⚠ Could not reach the deploy backend.\n${err.message}
`; deployConsole.scrollTop = deployConsole.scrollHeight; } }); // Configuration document.getElementById('devSaveConfigBtn').addEventListener('click', () => { const data = getCurrentProjectData(); data.subdomain = document.getElementById('devSubdomainInput').value.trim() || slugify(devProjectSelect.value); setCurrentProjectData(data); renderProjectPanels(); alertToast('Configuration saved for ' + devProjectSelect.value); }); // Variables document.getElementById('devAddVarBtn').addEventListener('click', () => { const key = document.getElementById('devVarKey').value.trim(); const value = document.getElementById('devVarValue').value.trim(); if (!key || !value) { alertToast('Enter both a key and a value.'); return; } const data = getCurrentProjectData(); data.vars = data.vars || []; data.vars.push({ key, value }); setCurrentProjectData(data); document.getElementById('devVarKey').value = ''; document.getElementById('devVarValue').value = ''; renderProjectPanels(); }); window.deleteDevVar = function(index) { const data = getCurrentProjectData(); data.vars.splice(index, 1); setCurrentProjectData(data); renderProjectPanels(); }; renderProjectPanels(); if (devProjectSelect.value) loadProjectFromBackend(devProjectSelect.value); // --- LIVE CHAT: real AI test via Netlify Functions -> OpenRouter, also usable externally with the same key --- async function registerKeyWithBackend(key, name, expiration) { const token = localStorage.getItem('faiNET_session_token'); if (!token) return; try { await fetch('/api/register-key', { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: 'Bearer ' + token }, body: JSON.stringify({ key, name, expiration }) }); } catch (err) { // Offline — key still works for display, will sync next time. } } async function fetchMyKeysFromBackend() { const token = localStorage.getItem('faiNET_session_token'); if (!token) return; try { const res = await fetch('/api/my-keys', { headers: { Authorization: 'Bearer ' + token } }); if (!res.ok) return; const { keys } = await res.json(); // Server is the source of truth for a logged-in account. const merged = (keys || []).map(k => ({ name: k.name, key: k.key, expiration: k.expiration || 'never', createdAt: new Date(k.created).toISOString() })); saveStoredKeys(merged); refreshKeys(); } catch (err) { // Offline — local cache is used as-is. } } document.getElementById('pgSendBtn').addEventListener('click', async () => { const msg = document.getElementById('pgMessageInput').value.trim(); const resultBox = document.getElementById('pgResult'); const keys = getStoredKeys(); if (!keys.length) { showToast('Create an API key first.', 'error'); return; } if (!msg) { showToast('Type a message first.', 'error'); return; } const activeKey = keys[0].key; resultBox.style.display = 'block'; resultBox.textContent = 'Sending...'; try { const res = await fetch('/api/chat', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + activeKey }, body: JSON.stringify({ message: msg }) }); const data = await res.json(); if (!res.ok) { resultBox.textContent = 'Error: ' + (data.error || res.statusText); return; } resultBox.textContent = data.reply; } catch (err) { resultBox.textContent = 'Could not reach the backend.\n\nThis only works once deployed on Netlify (Functions don\'t run when the file is opened locally).\n\n' + err.message; } }); document.getElementById('searchSendBtn').addEventListener('click', async () => { const query = document.getElementById('searchQueryInput').value.trim(); const resultBox = document.getElementById('searchResultBox'); const keys = getStoredKeys(); if (!keys.length) { showToast('Create an API key first.', 'error'); return; } if (!query) { showToast('Type a search query first.', 'error'); return; } const activeKey = keys[0].key; resultBox.style.display = 'block'; resultBox.innerHTML = '
Searching...
'; try { const res = await fetch('/api/search', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + activeKey }, body: JSON.stringify({ query }) }); const data = await res.json(); if (!res.ok) { resultBox.innerHTML = `
Error: ${escapeHtml(data.error || res.statusText)}
`; return; } let html = ''; if (data.answer) { html += `
Answer: ${escapeHtml(data.answer)}
`; } html += (data.results || []).map(r => `
${escapeHtml(r.title || r.url)}
${escapeHtml((r.content || '').slice(0, 220))}${(r.content || '').length > 220 ? '…' : ''}
`).join(''); resultBox.innerHTML = html || '
No results.
'; } catch (err) { resultBox.innerHTML = `
Could not reach the backend.\n\nThis only works once deployed on Cloudflare Pages.\n\n${escapeHtml(err.message)}
`; } }); // --- BUY DOMAIN (client-side demo: fake availability + pricing) --- // Real, at-cost registry wholesale pricing (approximate, like Cloudflare Registrar // charges) — faiNET adds a flat $0.50 markup per domain, first year and renewal alike. const FAINET_DOMAIN_MARKUP = 0.50; const DOMAIN_WHOLESALE = { '.art': { first: 6.49, renew: 19.49 }, '.com': { first: 9.49, renew: 9.49 }, '.net': { first: 10.49, renew: 10.49 }, '.org': { first: 9.49, renew: 9.49 }, '.ai': { first: 69.49, renew: 69.49 }, '.io': { first: 34.49, renew: 34.49 }, '.dev': { first: 11.49, renew: 11.49 }, '.app': { first: 11.49, renew: 11.49 }, '.co': { first: 22.49, renew: 22.49 }, '.xyz': { first: 1.49, renew: 9.49 } }; const DOMAIN_PRICING = Object.fromEntries( Object.entries(DOMAIN_WHOLESALE).map(([tld, p]) => [tld, { first: p.first + FAINET_DOMAIN_MARKUP, renew: p.renew + FAINET_DOMAIN_MARKUP }]) ); const domainSearchInput = document.getElementById('domainSearchInput'); const domainTldSelect = document.getElementById('domainTldSelect'); const domainSearchBtn = document.getElementById('domainSearchBtn'); const domainResultBox = document.getElementById('domainResultBox'); const myDomainsList = document.getElementById('myDomainsList'); domainTldSelect.innerHTML = Object.keys(DOMAIN_PRICING).map(tld => ``).join(''); function isAdminUser() { const me = JSON.parse(localStorage.getItem('faiNET_logged_in') || 'null'); return !!(me && me.isAdmin); } function renderDomainPriceTable() { const box = document.getElementById('domainPriceTable'); const adminFree = isAdminUser(); document.getElementById('domainAdminNote').style.display = adminFree ? 'inline' : 'none'; box.innerHTML = Object.entries(DOMAIN_PRICING).map(([tld, price]) => `
${tld} ${adminFree ? 'Free (admin)' : `$${price.first.toFixed(2)} first yr · $${price.renew.toFixed(2)}/yr renew`}
`).join(''); } // Legacy fake-domain helpers removed — search/buy now uses the real // Cloudflare Registrar API (see renderDomainResult / buyDomain below). function normalizeDomainName(raw) { return raw.trim().toLowerCase().replace(/[^a-z0-9-]/g, ''); } const DOMAIN_MARKUP = 3; // your profit per domain, added on top of Cloudflare's at-cost price async function renderDomainResult(name, tld) { const domain = name + tld; domainResultBox.style.display = 'block'; domainResultBox.innerHTML = '

Checking real availability…

'; try { const res = await fetch('/api/domain-search?q=' + encodeURIComponent(domain)); const data = await res.json(); if (!res.ok) { domainResultBox.innerHTML = `

${data.error || 'Search failed.'}

`; return; } const match = (data.domains || []).find(d => d.name === domain) || (data.domains || [])[0]; if (!match || !match.registrable) { domainResultBox.innerHTML = `
${domain}
✕ Taken / unavailable
`; return; } const sellPrice = (parseFloat(match.cost) + DOMAIN_MARKUP).toFixed(2); domainResultBox.innerHTML = `
${match.name}
✓ Available
$${sellPrice}
first year · real registration
`; document.getElementById('domainBuyBtn').addEventListener('click', () => buyDomain(match.name, sellPrice)); } catch (err) { domainResultBox.innerHTML = '

Could not reach the domain search backend.

'; } } async function buyDomain(domain, sellPrice) { const token = localStorage.getItem('faiNET_session_token'); if (!token) { showToast('Log in with a real email account first.', 'error'); return; } const reference = prompt(`Send $${sellPrice} via Hesab Pay, then paste your transaction reference to claim ${domain}:`); if (!reference) return; try { const res = await fetch('/api/submit-domain-purchase', { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: 'Bearer ' + token }, body: JSON.stringify({ domain, sellPrice, reference }) }); const data = await res.json(); if (!res.ok || !data.ok) { showToast(data.error || 'Could not submit domain claim.', 'error'); return; } domainResultBox.style.display = 'none'; domainSearchInput.value = ''; showToast(`Claim submitted for ${domain} — pending admin review before real registration.`, 'success'); pushNotification(`Domain claim submitted: ${domain}`, ICON_ROCKET); } catch (err) { showToast('Could not reach the backend.', 'error'); } } async function renderMyDomains() { const token = localStorage.getItem('faiNET_session_token'); let list = []; if (token) { try { const res = await fetch('/api/my-domains', { headers: { Authorization: 'Bearer ' + token } }); if (res.ok) { const d = await res.json(); list = d.domains || []; } } catch (err) { /* offline — show empty until reconnected */ } } if (!list.length) { myDomainsList.innerHTML = '

No domains yet — search above to buy one.

'; return; } myDomainsList.innerHTML = ''; list.forEach(d => { const row = document.createElement('div'); row.className = 'owned-domain-row'; const registered = new Date(d.registeredAt).toLocaleDateString(); row.innerHTML = `
${d.domain}
Registered ${registered} · $${Number(d.sellPrice).toFixed(2)}
Active`; myDomainsList.appendChild(row); }); } domainSearchBtn.addEventListener('click', () => { const name = normalizeDomainName(domainSearchInput.value); if (!name) { showToast('Type a domain name first.', 'error'); return; } renderDomainResult(name, domainTldSelect.value); }); domainSearchInput.addEventListener('keydown', (e) => { if (e.key === 'Enter') domainSearchBtn.click(); }); renderMyDomains(); renderDomainPriceTable(); // --- TEMPLATES (client-side prototype, stored in localStorage) --- const ICON_HEART = ''; const ICON_COMMENT = ''; const ICON_DOWNLOAD = ''; // Real, working starter templates — base64-encoded HTML so no escaping // issues with the backticks/${} inside their own