Open the panel

Using the API from LSL PRO ​

Your scripts in Second Life can use the API directly, with llHTTPRequest. Everything here was tested in Second Life.

The pattern ​

Every script has the same three parts: your key at the top, a request, and an http_response that reads the answer.

lsl
string API = "https://api.fastyvendor.com/api/v1";
string KEY = "fsk_…";    // this script must be no-copy and no-modify

key gRequest = NULL_KEY;

default
{
    touch_start(integer n)
    {
        gRequest = llHTTPRequest(API + "/me",
            [HTTP_CUSTOM_HEADER, "Authorization", "Bearer " + KEY], "");
    }

    http_response(key id, integer status, list meta, string body)
    {
        if (id != gRequest) return;
        gRequest = NULL_KEY;

        if (status == 200)
            llOwnerSay("Connected to " + llJsonGetValue(body, ["store", "name"]));
        else
            llOwnerSay("Fasty: " + llJsonGetValue(body, ["error", "message"]));
    }
}

Set the script to no-copy and no-modify

Anyone who can read the script can use your key. Set the script's permissions before you use a real key, and never give a copy of the object to someone else with your key inside.

Reading JSON ​

llJsonGetValue walks into the answer with a list of field names and positions:

lsl
llJsonGetValue(body, ["store", "name"]);          // "Luna Couture"
llJsonGetValue(body, ["items", 0, "price"]);      // the price of the first item
llJsonGetValue(body, ["error", "message"]);       // the error message
What you getWhat it means
JSON_TRUE / JSON_FALSEThe value is true or false. Compare with these, not with the text.
JSON_NULLThe value is null.
JSON_INVALIDThat field doesn't exist.

Go through a list with a counter, stopping at JSON_INVALID:

lsl
integer i;
string name = llJsonGetValue(body, ["items", 0, "name"]);
while (name != JSON_INVALID)
{
    llOwnerSay(name);
    name = llJsonGetValue(body, ["items", ++i, "name"]);
}

Sending data ​

Send HTTP_METHOD and HTTP_MIMETYPE, with the body as text. Build it with llList2Json so names with quotes can't break it:

lsl
string body = llList2Json(JSON_OBJECT, ["delta", 10, "note", "Won a round"]);

llHTTPRequest(API + "/customers/" + (string)winner + "/points",
    [HTTP_METHOD, "POST", HTTP_MIMETYPE, "application/json",
     HTTP_CUSTOM_HEADER, "Authorization", "Bearer " + KEY,
     HTTP_CUSTOM_HEADER, "Idempotency-Key", "round-" + (string)gRound + "-" + (string)winner],
    body);

PATCH works too. Use HTTP_METHOD, "PATCH" and send only the fields you want to change.

What is different in LSL ​

Long answers get cut. LSL keeps only the first 2 KB of an answer. For lists, add HTTP_BODY_MAXLENGTH, 16384, and ask for small pages with limit. A license check only needs limit=1.

Errors arrive in the body. LSL can't read response headers, so read error.message and error.retry_after with llJsonGetValue.

One script, many requests. Answers arrive in any order. Keep the key llHTTPRequest returns and compare it in http_response, as in the pattern above.

Memory. A big answer takes a big piece of your 64 KB. Read what you need, then clear the variable.

Second Life's limit ​

One object can send about 25 requests every 20 seconds. Past that, llHTTPRequest returns NULL_KEY and the owner sees Too many HTTP requests too fast.

So spread your requests out, and remember the answers. A door that checks a license on every touch should keep the avatars it already checked:

lsl
list gAllowed;     // avatars already checked in this session

integer known(key who) { return llListFindList(gAllowed, [who]) != -1; }

remember(key who)
{
    gAllowed = llList2List(gAllowed + [who], -50, -1);    // keeps the last 50
}

Complete examples ​

GuideWhat it builds
Unlock something for buyersAn object that opens only for those who bought a product
Reward players with pointsA game that gives loyalty points to the winner
Send prizes to winnersA contest that delivers a product to the winner

The reference has an LSL example for every route.