HTTP & Supabase¶
HTTP.* lets your world call external web services — most usefully your own database (e.g. Supabase) for things that must survive a restart: player profiles, progression, leaderboards, rewards. (For "this session" state, use Storage — it's faster and needs no backend.)
HTTP runs server‑side only, so endpoints and keys are used on the server, never shipped to players.
Never put an API key in a script
World bundles aren't encrypted — anything in a script is readable by others. So you don't paste keys into headers. Instead you store a credential in the Provider Manager (encrypted on your account) and reference it by handle; the server injects the key at request time. Keys never travel in your world.
1. Store a credential (Provider Manager)¶
Open Window ▸ SocialScape ▸ Provider Manager, Add a provider with Type = HTTP (credential):
| Field | Meaning |
|---|---|
| Handle | A name your scripts reference, e.g. my-supabase. |
| Base URL | The API root, e.g. https://YOUR-PROJECT.supabase.co. |
| Auth | How the key is attached (see the table below). |
| API Key | Stored encrypted on your account; never displayed again. |
Auth schemes¶
| Scheme | What it sends | Use for |
|---|---|---|
bearer |
Authorization: Bearer <key> |
most REST APIs (OpenAI‑style) |
apikey |
apikey: <key> |
services using an apikey header |
supabase |
both apikey: <key> and Authorization: Bearer <key> — the same key |
Supabase (it wants both; one key is correct) |
header |
<YourHeaderName>: <key> |
a single custom header, e.g. X-Api-Key |
none |
nothing — you place the key yourself | anything unusual (below) |
Supabase uses one key in two headers
Supabase's server pattern puts the same anon/service key in both apikey and Authorization: Bearer. So you only enter one key — supabase auth sends it to both. (Want a different Authorization value, like a user JWT? Use none + HTTP.Secret, below.)
Anything the schemes don't cover → none + HTTP.Secret
Basic auth, a key in the query string, a user JWT, or two separate keys? Set Auth = none and build the request yourself with HTTP.Secret("handle"). For two distinct keys, store two credentials and reference each by handle.
2a. Call it by handle — HTTP.*Via¶
The server resolves the handle → base URL + auth, prepends the base URL to your path, and sends. Your script never sees the key or the URL:
using System.Collections;
using UnityEngine;
using NexusVM.Unity;
class Leaderboard : NexusBehaviour
{
IEnumerator SaveScore(string userId, int score)
{
string body = "{\"user_id\": \"" + userId + "\", \"score\": " + score + "}";
var result = HTTP.PostVia("my-supabase", "/rest/v1/scores", body);
yield return result; // wait for the request
if (result.Success) Debug.Log("Saved: " + result.Body);
else Debug.LogError("Failed (" + result.StatusCode + "): " + result.Error);
}
}
| Method | Signature |
|---|---|
| GET | HTTP.GetVia(handle, path[, headers]) |
| POST/PUT/PATCH | HTTP.PostVia/PutVia/PatchVia(handle, path, body[, headers]) |
| DELETE | HTTP.DeleteVia(handle, path[, headers]) |
2b. Reference just the secret — HTTP.Secret¶
For APIs with unusual auth, keep the full‑URL calls and drop the key into a header with HTTP.Secret(handle). It returns an opaque reference; the real key is substituted server‑side at send‑time and is never readable in your script:
var headers = new Dictionary<string, string>();
headers["X-Api-Key"] = HTTP.Secret("my-vendor-key");
var result = HTTP.Get("https://api.vendor.com/v1/status", headers);
yield return result;
Reading the result¶
Every call returns an HTTPAsyncResult you yield return, then read:
Success (bool) · StatusCode (int) · Body (response string) · Error (string).
Letting an NPC answer from a request
Calling HTTP from inside an NPC action? Mark the action Async so the NPC waits for the result and speaks it in one turn (e.g. "what's my score?"). See Custom actions ▸ Async actions.
Public APIs (no key) — raw calls¶
For endpoints that need no credential, use the plain calls with a full URL:
HTTP.Get/Post/Put/Patch/Delete(url[, body][, headers]). Use these only when there's no secret involved.
Supabase pattern¶
Store a supabase‑auth credential (handle my-supabase, base URL https://YOUR-PROJECT.supabase.co), then:
| Do | Call |
|---|---|
| Read a row | HTTP.GetVia("my-supabase", "/rest/v1/profiles?user_id=eq." + userId) |
| Insert | HTTP.PostVia("my-supabase", "/rest/v1/profiles", json) |
| Update | HTTP.PatchVia("my-supabase", "/rest/v1/profiles?user_id=eq." + userId, json) |
| Delete | HTTP.DeleteVia("my-supabase", "/rest/v1/profiles?user_id=eq." + userId) |
Always key durable records by the player's stable account id (Player.GetUserId), not the per‑session id. (Tip: still scope your Supabase key with RLS — defence in depth.)
When to use what¶
| Need | Use |
|---|---|
| Counter/flag for the current session | Storage |
| Data that survives restarts (profiles, leaderboards) | HTTP → your DB (via a credential) |
| A third‑party API needing a key | a Provider Manager HTTP credential + *Via / HTTP.Secret |
| A public, keyless endpoint | raw HTTP.Get(url) |