supabase/
├── functions/
│ ├── formulas-list/index.ts ← API 1: GET all formulas
│ ├── formula-schema/index.ts ← API 2: GET one formula schema
│ └── calculate/index.ts ← API 3: POST run calculation
├── migrations/
│ └── 20260720000000_create_api_keys.sql
# Inside your project folder
supabase db pushThis creates the api_keys table in Supabase.
Then generate an API key for your first client (run in Supabase SQL editor):
insert into public.api_keys (key, client_name)
values ('mvl_live_your_random_key_here', 'Client Name');Use any random string as the key — e.g. mvl_live_xK9mP2qR7vL4nW8j.
The functions read METAVAL_API_KEY from Supabase secrets.
Set it to the same key you inserted above:
supabase secrets set METAVAL_API_KEY=mvl_live_xK9mP2qR7vL4nW8jThe functions also auto-have access to:
SUPABASE_URLSUPABASE_SERVICE_ROLE_KEY
These are injected automatically by Supabase — you don't set them manually.
supabase functions deploy formulas-list
supabase functions deploy formula-schema
supabase functions deploy calculateEach takes ~30 seconds. After deploy, your URLs are:
https://wvdzdcbuflgqnoffslnz.supabase.co/functions/v1/formulas-list
https://wvdzdcbuflgqnoffslnz.supabase.co/functions/v1/formula-schema
https://wvdzdcbuflgqnoffslnz.supabase.co/functions/v1/calculate
curl -X GET \
https://wvdzdcbuflgqnoffslnz.supabase.co/functions/v1/formulas-list \
-H "x-api-key: mvl_live_xK9mP2qR7vL4nW8j"Expected response:
{
"formulas": [
{ "slug": "cv-calculator", "name": "CV Calculator...", "tag": "Flow Coefficient", "icon": "💧", "description": "..." },
{ "slug": "waterjet-force", "name": "Waterjet Force...", "tag": "Thrust", "icon": "🚀", "description": "..." }
]
}curl -X GET \
"https://wvdzdcbuflgqnoffslnz.supabase.co/functions/v1/formula-schema?slug=cv-calculator" \
-H "x-api-key: mvl_live_xK9mP2qR7vL4nW8j"Expected response:
{
"slug": "cv-calculator",
"name": "CV Calculator (Flow Coefficient)",
"formula": "Cv = QL × √SG / √ΔP",
"inputs": [
{
"id": "flow",
"label": "Flow Rate",
"default": 45,
"units": [
{ "value": "gpm", "label": "GPM" },
{ "value": "m3h", "label": "m³/hr" },
{ "value": "lpm", "label": "L/min" }
]
},
...
]
}Note: No calculate.steps, no toBase, no fromBase in response.
curl -X POST \
https://wvdzdcbuflgqnoffslnz.supabase.co/functions/v1/calculate \
-H "x-api-key: mvl_live_xK9mP2qR7vL4nW8j" \
-H "Content-Type: application/json" \
-d '{
"slug": "cv-calculator",
"inputs": {
"flow": { "value": 45, "unit": "m3h" },
"sg": { "value": 1, "unit": "sg" },
"pressure": { "value": 0.8492, "unit": "bar" }
}
}'Expected response:
{
"slug": "cv-calculator",
"results": [
{ "label": "Cv (Flow Coefficient)", "value": "56.4549", "unit": "—", "highlight": true }
],
"derived": []
}Waterjet test:
Expected:
{
"slug": "waterjet-force",
"results": [
{ "label": "WJF / Thrust", "value": "557.48", "unit": "kg" },
{ "label": "WJF / Thrust", "value": "5467.22", "unit": "N", "highlight": true }
],
"derived": [
{ "label": "X-Section Area", "value": "0.1590", "unit": "m²" },
{ "label": "Flow Rate", "value": "0.6667", "unit": "m³/s" },
{ "label": "Velocity (V)", "value": "4.1935", "unit": "m/s" },
{ "label": "Mass Flow Rate", "value": "666.67", "unit": "kg/s" }
]
}Send them exactly these 3 things:
Base URL: https://wvdzdcbuflgqnoffslnz.supabase.co/functions/v1
API Key: mvl_live_xK9mP2qR7vL4nW8j (send per client, generate a new one each time)
Endpoints:
GET /formulas-list → list all formulas
GET /formula-schema?slug={slug} → get input fields for one formula
POST /calculate → run calculation
| Error | Cause | Fix |
|---|---|---|
401 Unauthorized |
Wrong or missing API key | Checkx-api-key header |
404 Formula not found |
Wrong slug | Call API 1 first to get correct slugs |
400 Invalid inputs |
Wrong unit string | Call API 2 first to see allowed units |
500 Calculation failed |
Bad formula steps in DB | Check formula JSON in Supabase dashboard |
| CORS error | Missing Origin header in test | Use curl or Postman, not browser fetch |
-- Generate a new key per client — never share keys between clients
insert into public.api_keys (key, client_name)
values ('mvl_live_newclient_abc123', 'New Platform Name');Then share only their key. If they misuse it:
update public.api_keys set active = false where client_name = 'New Platform Name';GET https://wvdzdcbuflgqnoffslnz.supabase.co/functions/v1/formulas-list GET https://wvdzdcbuflgqnoffslnz.supabase.co/functions/v1/formula-schema?slug={slug} POST https://wvdzdcbuflgqnoffslnz.supabase.co/functions/v1/calculate
x-api-key: mvl_live_xK9mP2qR7vL4nW8j
distance-conversion pressure-drop-darcy-weisbach butterfly-valve-torque-calculator globe-valve-torque-calculator gate-valve-torque-calculator ball-valve-torque-calculator cv-calculator-flow-coefficient thrust-calculator
Base URL : https://wvdzdcbuflgqnoffslnz.supabase.co/functions/v1