Skip to content

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)