NAV
curl CLI Browser JS NodeJS Python Go

Introduction

Welcome to the Skynet SDK docs!

We have SDK support for several languages:

as well as the Skynet CLI (written in Go).

These SDKs are wrappers around HTTP calls to the corresponding Skynet endpoints. Full documentation for the Skynet HTTP API can be found in the Sia API Documentation.

A Note About Language Differences

Though we tried to keep the SDKs as similar to each other as possible in usage, differences between the languages -- the idiosyncracies and best practices of each -- resulted in differences between the SDKs. We've noted them where necessary throughout the documentation.

Function Parameters

In most of the SDKs the additional options may be left out of the function calls, in which case the default options are used. In Go the options must always be passed in, as the language does not support optional function parameters.

Case

Note that the casing of functions and their parameters differs between the languages:

Language Case
Javascript camelCase
Python snake_case
Go PascalCase

For consistency throughout this document, functions and their parameters are documented using camelCase.

Standard Responses

Functions will respond with the desired content on success and with errors or exceptions on failure. The error messages may contain HTTP status codes (see the Sia Docs).

Functions will fail differently in each SDK depending on the language:

Language Failure Mode
Javascript Exceptions are raised and must be caught with a try-catch block.
Python Same as above.
Go Errors are returned and must be checked for explicitly.

Using The Shell

function skynet() {
  curl -X POST "https://siasky.net/skynet/skyfile" -F "file=@$1" \
    | jq ".skylink" | xargs -I _ echo "https://siasky.net/_"
}

Our shell examples present only simple curl calls. You may find it helpful to write wrappers around these in Bash, or the shell language of your choice, to make them more reusable. To the right we have provided a simple example which uses jq.

Getting Started

Making Your First API Call

curl -L -X POST "https://siasky.net/skynet/skyfile/<siapath>" -F file=@image.jpg
skynet upload "./image.jpg"
import { SkynetClient } from "skynet-js";

const client = new SkynetClient();

// Assume we have a file from an input form.

async function uploadExample() {
  try {
    const { skylink } = await client.uploadFile(file);
    console.log(`Upload successful, skylink: ${skylink}`);
  } catch (error) {
    console.log(error)
  }
}
const { SkynetClient } = require('@nebulous/skynet');

const client = new SkynetClient();

(async () => {
    const skylink = await client.uploadFile("./image.jpg");
    console.log(`Upload successful, skylink: ${skylink}`);
})();
import siaskynet as skynet

client = skynet.SkynetClient()

skylink = client.upload_file("image.jpg")
print("Upload successful, skylink: " + skylink)
package main

import (
    "fmt"
    skynet "github.com/NebulousLabs/go-skynet/v2"
)

var client = skynet.New()

func main() {
    skylink, err := client.UploadFile("./image.jpg", skynet.DefaultUploadOptions)
    if err != nil {
        panic("Unable to upload: " + err.Error())
    }
    fmt.Printf("Upload successful, skylink: %v\n", skylink)
}

The SDKs are set up to be as simple as possible. Despite the many options for configuration, most users will be able to get started with a single API call. In the example on the right, we upload the file image.jpg to the default Skynet portal, https://siasky.net.

Skynet Client

The above examples also demonstrate the use of the Skynet client. This client is required to make any API calls. It sets the portal that will be used for all requests. It can also be initialized with custom connection options that will be applied in all calls, unless calling an API method with the same options, which then take precedent and override what was set in client initialization.

Please see Using The Skynet Client for more information.

Portal Selection

In order to use a specific portal, you will need to use it as the first argument in client creation. Please see Basic Portal Selection for more information.

Setting Additional Options

Each SDK function also accepts additional options. These vary depending on the endpoint and are documented alongside each function.

Common Options

Every function accepts the following common options:

Option Description Default
endpointPath The relative path on the portal where the endpoint may be found for the function being called. Some portals, for example, may offer alternate download paths. ""
APIKey The API password used for authentication. ""
customUserAgent Allows changing the User Agent, as some portals may reject user agents that are not Sia-Agent for security reasons. ""
query Allows passing custom query parameters. Can be used to pass options to an endpoint that are not implemented in the SDK yet. Can also be used in the browser when opening a web app to pass options to the app. ""

Useful Constants

Here are some constants exported by the SDKs which may be of use in applications.

Constant Description Default
defaultPortalUrl The default Skynet portal to use, if one is not provided. "https://siasky.net"
uriSkynetPrefix The Skynet URI prefix. "sia://"

Using The Skynet Client

The Skynet Client is required to make any API calls. It sets the portal that will be used for all requests. It can also be initialized with custom connection options that will be applied in all calls, unless calling an API method with the same options (which then take precedent and override what was set in client initialization).

Basic Portal Selection

import { SkynetClient } from "skynet-js";

// Or SkynetClient() without arguments to use the default portal.
const client = new SkynetClient("https://some-other-portal.xyz");
const { SkynetClient } = require('@nebulous/skynet');

// Or SkynetClient() without arguments to use the default portal.
const client = new SkynetClient("https://some-other-portal.xyz");
import siaskynet as skynet

# Or SkynetClient() without arguments to use the default portal.
client = skynet.SkynetClient("https://some-other-portal.xyz")
package main

import (
    "fmt"
    skynet "github.com/NebulousLabs/go-skynet/v2"
)

var client = skynet.NewCustom("https://some-other-portal.xyz", skynet.Options{})

To make any API calls you will need to first create a new client with the desired portal. The client can be initialized without arguments to let the client choose it for you (see below) or the portal can be specified. See the code example on the right.

Default Portal Selection

The default portal used is https://siasky.net for all SDKs except Browser JS, which tries to use the portal which is running the sky app. The default portal is accessible through the exported function, defaultPortalUrl, and no configuration is required to use it. Having a reasonable choice already selected keeps friction for new developers low.

In the future the default selection will be smarter and there will be more options for default portal selection, such as configuration files. Please see this issue.

Setting Connection Options

import { SkynetClient } from "skynet-js";

const client = new SkynetClient("", { APIKey: "foobar" });
const { SkynetClient } = require('@nebulous/skynet');

const client = new SkynetClient("", { APIKey: "foobar" });
import siaskynet as skynet

# Or SkynetClient() without arguments to use the default portal.
client = skynet.SkynetClient("", {"api_key": "foobar"})
package main

import (
    "fmt"
    skynet "github.com/NebulousLabs/go-skynet/v2"
)

var client = skynet.NewCustom("", skynet.Options{APIKey: "foobar"})

Apart from setting a persistent portal, client initialization also allows you to choose persistent connection settings. These will be applied on every subsequent API call using the client, unless the setting is overridden in a particular call.

Please see Setting Additional Options.

Uploading To Skynet

Uploading A File

curl -L -X POST "https://siasky.net/skynet/skyfile/<siapath>" -F file=@image.jpg
skynet upload "./image.jpg"
import { SkynetClient } from "skynet-js";

const client = new SkynetClient();

// NOTE: This example is different from the other SDKs because we cannot just
// take a path to a local file.

async function uploadExample() {
  try {
    const { skylink } = await client.uploadFile(file);
  } catch (error) {
    console.log(error)
  }
}
const { SkynetClient } = require('@nebulous/skynet');

const client = new SkynetClient();

(async () => {
    const skylink = await client.uploadFile("./image.jpg");
    console.log(`Upload successful, skylink: ${skylink}`);
})();
import siaskynet as skynet

client = skynet.SkynetClient()

skylink = client.upload_file("image.jpg")
print("Upload successful, skylink: " + skylink)
package main

import (
    "fmt"
    skynet "github.com/NebulousLabs/go-skynet/v2"
)

var client = skynet.New()

func main() {
    skylink, err := client.UploadFile("./image.jpg", skynet.DefaultUploadOptions)
    if err != nil {
        panic("Unable to upload: " + err.Error())
    }
    fmt.Printf("Upload successful, skylink: %v\n", skylink)
}

Uploading a file to Skynet can be done through a Skynet portal or your local siad instance.

Parameters

Field Description
path The local path where the file to upload may be found.

Browser JS:

Field Description
file The File object returned from an input form.

Additional Options

Field Description Default
portalFileFieldName The field name for files on the portal. Usually should not need to be changed. "file"
portalDirectoryFileFieldName The field name for directories on the portal. Usually should not need to be changed. "files[]"
customFilename Custom filename. This is the filename that will be returned when downloading the file in a browser. ""
customDirname Custom dirname. If this is empty, the base name of the directory being uploaded will be used by default. ""
skykeyName The name of the skykey on the portal used to encrypt the upload. ""
skykeyID The ID of the skykey on the portal used to encrypt the upload. ""
timeout_seconds The timeout in seconds. ""

Response

{
  "skylink": "CABAB_1Dt0FJsxqsu_J4TodNCbCGvtFf1Uys_3EgzOlTcg",
  "merkleroot": "QAf9Q7dBSbMarLvyeE6HTQmwhr7RX9VMrP9xIMzpU3I",
  "bitfield": 2048
}
Successfully uploaded file! Skylink: sia://CABAB_1Dt0FJsxqsu_J4TodNCbCGvtFf1Uys_3EgzOlTcg
"sia://CABAB_1Dt0FJsxqsu_J4TodNCbCGvtFf1Uys_3EgzOlTcg"
"sia://CABAB_1Dt0FJsxqsu_J4TodNCbCGvtFf1Uys_3EgzOlTcg"
"sia://CABAB_1Dt0FJsxqsu_J4TodNCbCGvtFf1Uys_3EgzOlTcg"
"sia://CABAB_1Dt0FJsxqsu_J4TodNCbCGvtFf1Uys_3EgzOlTcg"
Field Description
skylink This is the skylink that can be used when downloading to retrieve the file that has been uploaded. It is a 46-character base64 encoded string that consists of the merkle root, offset, fetch size, and Skylink version which can be used to access the content.
merkleroot (curl only) This is the hash that is encoded into the skylink.
bitfield (curl only) This is the bitfield that gets encoded into the skylink. The bitfield contains a version, an offset and a length in a heavily compressed and optimized format.

Uploading A Directory

curl -L -X POST "https://siasky.net/skynet/<siapath>?filename=images" -F files[]=@./images/image1.png -F files[]=@./images/image2.png
skynet upload "./images"
import { getRelativeFilePath, getRootDirectory, SkynetClient } from "skynet-js";

const client = new SkynetClient();

// Assume we have a list of files from an input form.

async function uploadDirectoryExample() {
  try {
    // Get the directory name from the list of files.
    // Can also be named manually, i.e. if you build the files yourself
    // instead of getting them from an input form.
    const filename = getRootDirectory(files[0]);

    // Use reduce to build the map of files indexed by filepaths
    // (relative from the directory).
    const directory = files.reduce((accumulator, file) => {
      const path = getRelativeFilePath(file);

      return { ...accumulator, [path]: file };
    }, {});

    const { skylink } = await client.uploadDirectory(directory, filename);
  } catch (error) {
    console.log(error);
  }
}
const { SkynetClient } = require('@nebulous/skynet');

const client = new SkynetClient();

(async () => {
    const url = await client.uploadDirectory("./images");
    console.log(`Upload successful, url: ${url}`);
})();
import siaskynet as skynet

client = skynet.SkynetClient()

url = client.upload_directory("./images")
print("Upload successful, url: " + url)
package main

import (
    "fmt"
    skynet "github.com/NebulousLabs/go-skynet/v2"
)

var client = skynet.New()

func main() {
    url, err := client.UploadDirectory("./images", skynet.DefaultUploadOptions)
    if err != nil {
        panic("Unable to upload: " + err.Error())
    }
    fmt.Printf("Upload successful, url: %v\n", url)
}

It is possible to upload a directory as a single piece of content. Doing this will allow you to address your content under one skylink, and access the files by their path. This is especially useful for webapps.

For example, let's say you upload a web app with the following simple structure:

src
|-- favicon.ico
|-- index.html
|-- css
    |-- main.css
|-- js
    |-- app.js

The four files can be accessed as follows:

[portal url]/[skylink]/favicon.ico
[portal url]/[skylink]/index.html
[portal url]/[skylink]/css/main.css
[portal url]/[skylink]/js/app.js

Parameters

Field Description
path The local path where the directory to upload may be found.

Browser JS:

Field Description
directory Object containing Files from an input form to upload, indexed by their path strings.
filename The name of the directory.

Additional Options

See Uploading A File.

Response

{
  "skylink": "EAAV-eT8wBIF1EPgT6WQkWWsb3mYyEO1xz9iFueK5zCtqg",
  "merkleroot": "QAf9Q7dBSbMarLvyeE6HTQmwhr7RX9VMrP9xIMzpU3I",
  "bitfield": 2048
}
Successfully uploaded directory! Skylink: sia://EAAV-eT8wBIF1EPgT6WQkWWsb3mYyEO1xz9iFueK5zCtqg
"sia://EAAV-eT8wBIF1EPgT6WQkWWsb3mYyEO1xz9iFueK5zCtqg"
"sia://EAAV-eT8wBIF1EPgT6WQkWWsb3mYyEO1xz9iFueK5zCtqg"
"sia://EAAV-eT8wBIF1EPgT6WQkWWsb3mYyEO1xz9iFueK5zCtqg"
"sia://EAAV-eT8wBIF1EPgT6WQkWWsb3mYyEO1xz9iFueK5zCtqg"

See Uploading A File.

Uploading With Encryption

Coming Soon
skynet upload "./image.jpg" --skykey-name "my-skykey"
// NOTE: this feature has not yet been implemented for this SDK.

import { SkynetClient } from "skynet-js";

const client = new SkynetClient();

// Assume we have a file from an input form.

async uploadEncryptionExample() {
  try {
    const { skylink } = await client.upload(file, { skykeyName: "my-skykey" });
  } catch (error) {
    console.log(error)
  }
}
// NOTE: this feature has not yet been implemented for this SDK.

const { SkynetClient } = require('@nebulous/skynet');

const client = new SkynetClient();

(async () => {
    const skylink = await client.uploadFile(
        "./image.jpg",
        { skykeyName: "my-skykey" }
    );
    console.log(`Upload successful, skylink: ${skylink}');
})();
# NOTE: this feature has not yet been implemented for this SDK.

import siaskynet as skynet

client = skynet.SkynetClient()

skylink = client.upload_file("image.jpg", { skykeyName: "my-skykey" })
print("Upload successful, skylink: " + skylink)
package main

import (
    "fmt"
    skynet "github.com/NebulousLabs/go-skynet/v2"
)

var client = skynet.New()

func main() {
    opts := skynet.DefaultUploadOptions
    opts.SkykeyName = "my-skykey"
    skylink, err := client.UploadFile("./image.jpg", opts)
    if err != nil {
        panic("Unable to upload: " + err.Error())
    }
    fmt.Printf("Upload successful, skylink: %v\n", skylink)
}

If you have a skykey on the portal you can ask the portal to encrypt the uploaded content for you. Simply pass the skykey name or ID in the custom options when uploading a file or directory.

See the additional options in Uploading A File.

Also see Encryption.

Downloading From Skynet

Downloading A File

curl -A "Sia-Agent" "https://siasky.net/CABAB_1Dt0FJsxqsu_J4TodNCbCGvtFf1Uys_3EgzOlTcg" -o dst.jpg
skynet download "XABvi7JtJbQSMAcDwnUnmp2FKDPjg8_tTTFP4BwMSxVdEg" "./dst.jpg"
import { SkynetClient } from "skynet-js";

const client = new SkynetClient();
const skylink = "XABvi7JtJbQSMAcDwnUnmp2FKDPjg8_tTTFP4BwMSxVdEg";

try {
  client.downloadFile(skylink);
  // Or client.openFile(skylink) to open it in a new browser tab.
} catch (error) {
  console.log(error);
}
const { SkynetClient } = require('@nebulous/skynet');

const client = new SkynetClient();
const skylink = "XABvi7JtJbQSMAcDwnUnmp2FKDPjg8_tTTFP4BwMSxVdEg";

(async () => {
    await client.downloadFile("./dst.jpg", skylink);
    console.log('Download successful');
})();
import siaskynet as skynet

client = skynet.SkynetClient()
skylink = "XABvi7JtJbQSMAcDwnUnmp2FKDPjg8_tTTFP4BwMSxVdEg"

client.download_file("./dst.jpg", skylink)
print("Download successful")
package main

import (
    "fmt"
    skynet "github.com/NebulousLabs/go-skynet/v2"
)

const skylink = "XABvi7JtJbQSMAcDwnUnmp2FKDPjg8_tTTFP4BwMSxVdEg"
var client = skynet.New()

func main() {
    err := client.DownloadFile("./dst.go", skylink, skynet.DefaultDownloadOptions)
    if err != nil {
        panic("Something went wrong, please try again.\nError: " + err.Error())
    }
    fmt.Println("Download successful")
}

This function downloads a skylink using HTTP streaming. The call blocks until the data is received. There is a 30s default timeout applied to downloading a skylink. If the data can not be found within this 30s time constraint, a 404 error will be returned. This timeout is configurable.

Parameters

Field Description
path The local path where the file should be downloaded to.
skylink The skylink that should be downloaded. The skylink can contain an optional path.

Browser JS:

Field Description
skylink The skylink that should be downloaded. The skylink can contain an optional path.

Additional Options

Field Description Default
path The path to use after the skylink. See the next section. ""
skykeyName The name of the skykey on the portal used to decrypt the download. ""
skykeyID The ID of the skykey on the portal used to decrypt the download. ""
timeout_seconds The timeout in seconds. ""

Response

Empty on success.

Downloading A File From An Uploaded Directory

curl -A "Sia-Agent" "https://siasky.net/XABvi7JtJbQSMAcDwnUnmp2FKDPjg8_tTTFP4BwMSxVdEg/dir2/file3" -o dst.jpg
skynet download "XABvi7JtJbQSMAcDwnUnmp2FKDPjg8_tTTFP4BwMSxVdEg/dir2/file3" "./dst.jpg"
import { SkynetClient } from "skynet-js";

const client = new SkynetClient();

// Using the skylink.
try {
  const skylink = "XABvi7JtJbQSMAcDwnUnmp2FKDPjg8_tTTFP4BwMSxVdEg/dir2/file3";
  client.downloadFile(skylink);
} catch (error) {
  console.log(error);
}

// Using the path option.
try {
  const skylink = "XABvi7JtJbQSMAcDwnUnmp2FKDPjg8_tTTFP4BwMSxVdEg";
  client.downloadFile(skylink, { path: "dir2/file3" });
} catch (error) {
  console.log(error);
}
const { SkynetClient } = require('@nebulous/skynet');

const client = new SkynetClient();

// Using the skylink.
(async () => {
  const skylink = "XABvi7JtJbQSMAcDwnUnmp2FKDPjg8_tTTFP4BwMSxVdEg/dir2/file3";
    await client.downloadFile("./dst.jpg", skylink);
    console.log('Download successful');
})();

// Using the path option.
(async () => {
  const skylink = "XABvi7JtJbQSMAcDwnUnmp2FKDPjg8_tTTFP4BwMSxVdEg";
    await client.downloadFile("./dst.jpg", skylink, { path: "dir2/file3" });
    console.log('Download successful');
})()
import siaskynet as skynet

client = skynet.SkynetClient()

# Using the skylink.
skylink = "XABvi7JtJbQSMAcDwnUnmp2FKDPjg8_tTTFP4BwMSxVdEg/dir2/file3"
client.download_file("./dst.jpg", skylink)
print("Download successful")

# Using the path option.
skylink = "XABvi7JtJbQSMAcDwnUnmp2FKDPjg8_tTTFP4BwMSxVdEg"
client.download_file("./dst.jpg", skylink, { "path": "dir2/file3" })
print("Download successful")
package main

import (
    "fmt"
    skynet "github.com/NebulousLabs/go-skynet/v2"
)

var client = skynet.New()

func main() {
    // Using the skylink.
    skylink := "XABvi7JtJbQSMAcDwnUnmp2FKDPjg8_tTTFP4BwMSxVdEg/dir2/file3"
    opts := skynet.DefaultDownloadOptions
    err := client.DownloadFile("./dst.go", skylink, opts)
    if err != nil {
        panic("Something went wrong, please try again.\nError: " + err.Error())
    }
    fmt.Println("Download successful")

    // Using the path option.
    skylink = "XABvi7JtJbQSMAcDwnUnmp2FKDPjg8_tTTFP4BwMSxVdEg"
    opts.Path = "dir2/file3";
    err := client.DownloadFile("./dst.go", skylink, opts)
    if err != nil {
        panic("Something went wrong, please try again.\nError: " + err.Error())
    }
    fmt.Println("Download successful")
}

It is possible to download files from uploaded directories if their paths relative to the uploaded directory are known. There are two ways to do this.

The skylink being passed in can contain an optional path. This path can specify a directory or a particular file. If specified, only that file or directory will be returned. The examples here use the directory structure from Uploading A Directory to illustrate this.

The Path Additional Parameter

There is a caveat to the above approach: the skylink is used as-is and any special characters in the appended path are not encoded. We recommend using the additional option path to let the SDK properly encode it for you.

The path option also is easier to use if you would otherwise have to manually append the path to the skylink.

Getting Metadata

curl -I -A "Sia-Agent" "https://siasky.net/CABAB_1Dt0FJsxqsu_J4TodNCbCGvtFf1Uys_3EgzOlTcg"
# NOTE: this function has not yet been implemented for this SDK.

skynet metadata "XABvi7JtJbQSMAcDwnUnmp2FKDPjg8_tTTFP4BwMSxVdEg"
// NOTE: this function has not yet been implemented for this SDK.

import { SkynetClient } from "skynet-js";

const client = new SkynetClient();
const skylink = "XABvi7JtJbQSMAcDwnUnmp2FKDPjg8_tTTFP4BwMSxVdEg";

async metadataExample() {
  try {
    const md = await client.getMetadata(skylink);
  } catch (error) {
    console.log(error);
  }
}
// NOTE: this function has not yet been implemented for this SDK.

const { SkynetClient } = require('@nebulous/skynet');

const client = new SkynetClient();
const skylink = "XABvi7JtJbQSMAcDwnUnmp2FKDPjg8_tTTFP4BwMSxVdEg";

(async () => {
    const md = await client.getMetadata(skylink);
    console.log(Get metadata successful');
})();
import siaskynet as skynet

client = skynet.SkynetClient()
skylink = "XABvi7JtJbQSMAcDwnUnmp2FKDPjg8_tTTFP4BwMSxVdEg"

md = client.get_metadata(skylink)
// NOTE: this function has not yet been implemented for this SDK.

package main

import (
    "fmt"
    skynet "github.com/NebulousLabs/go-skynet/v2"
)

const skylink = "XABvi7JtJbQSMAcDwnUnmp2FKDPjg8_tTTFP4BwMSxVdEg"
var client = skynet.New()

func main() {
    md, err := client.Metadata(skylink, skynet.DefaultMetadataOptions)
    if err != nil {
        panic("Something went wrong, please try again.\nError: " + err.Error())
    }
    fmt.Printf("Get metadata successful, metadata: %+v\n", md)
}

It is possible to get metadata about a file or directory without fetching the entire content. These API calls will perform a HEAD request that fetches the headers for the given skylink. These headers are identical to the ones that would be returned if the request had been a GET request.

Parameters

Field Description
skylink The skylink that should be downloaded. The skylink can contain an optional path. This path can specify a directory or a particular file. If specified, only that file or directory will be returned.

Additional Options

See Downloading A File.

Response

{
"mode":     640,
"filename": "folder",
"subfiles": [
  {
  "mode":         640,
  "filename":     "folder/file1.txt",
  "contenttype":  "text/plain",
  "offset":       0,
  "len":          6
  }
]
}
{
"mode":     640,
"filename": "folder",
"subfiles": [
  {
  "mode":         640,
  "filename":     "folder/file1.txt",
  "contenttype":  "text/plain",
  "offset":       0,
  "len":          6
  }
]
}
{
"mode":     640,
"filename": "folder",
"subfiles": [
  {
  "mode":         640,
  "filename":     "folder/file1.txt",
  "contenttype":  "text/plain",
  "offset":       0,
  "len":          6
  }
]
}
{
"mode":     640,
"filename": "folder",
"subfiles": [
  {
  "mode":         640,
  "filename":     "folder/file1.txt",
  "contenttype":  "text/plain",
  "offset":       0,
  "len":          6
  }
]
}
{
"mode":     640,
"filename": "folder",
"subfiles": [
  {
  "mode":         640,
  "filename":     "folder/file1.txt",
  "contenttype":  "text/plain",
  "offset":       0,
  "len":          6
  }
]
}
{
"mode":     640,
"filename": "folder",
"subfiles": [
  {
  "mode":         640,
  "filename":     "folder/file1.txt",
  "contenttype":  "text/plain",
  "offset":       0,
  "len":          6
  }
]
}

Coming Soon

Downloading With Decryption

Coming Soon
skynet download [skylink] [destination] --skykey-name "my-skykey"
// NOTE: this feature has not yet been implemented for this SDK.

import { SkynetClient } from "skynet-js";

const client = new SkynetClient();
const skylink = "XABvi7JtJbQSMAcDwnUnmp2FKDPjg8_tTTFP4BwMSxVdEg";

try {
  client.download(skylink, { skykeyName: "my-skykey" });
} catch (error) {
  console.log(error);
}
// NOTE: this feature has not yet been implemented for this SDK.

const { SkynetClient } = require('@nebulous/skynet');

const client = new SkynetClient();
const skylink = "XABvi7JtJbQSMAcDwnUnmp2FKDPjg8_tTTFP4BwMSxVdEg";

(async () => {
    await client.downloadFile(
        "./dst.jpg",
        skylink,
        { skykeyName: "my-skykey" }
    );
    console.log('Download successful');
})();
# NOTE: this feature has not yet been implemented for this SDK.

import siaskynet as skynet

client = skynet.SkynetClient()
skylink = "XABvi7JtJbQSMAcDwnUnmp2FKDPjg8_tTTFP4BwMSxVdEg"

client.download_file("./dst.jpg", skylink, { skykeyName: "my-skykey" })
print("Download successful")
package main

import (
    "fmt"
    skynet "github.com/NebulousLabs/go-skynet/v2"
)

const skylink = "XABvi7JtJbQSMAcDwnUnmp2FKDPjg8_tTTFP4BwMSxVdEg"
var client = skynet.New()

func main() {
    // Must have a 'skylink' from an earlier upload.

    opts := skynet.DefaultDownloadOptions
    opts.SkykeyName = "my-skykey"
    err := client.DownloadFile("./dst.go", skylink, opts)
    if err != nil {
        panic("Something went wrong, please try again.\nError: " + err.Error())
    }
    fmt.Println("Download successful")
}

If you have a skykey on the portal you can ask the portal to decrypt the downloaded content for you. Simply pass the skykey name or ID in the custom options when downloading.

See the additional options in Downloading A File.

Also see Encryption.

Encryption

Encryption and decryption in Skynet are performed using skykeys. Skykeys can be created and queried using the functions in this section. The name or ID of a skykey must be provided when uploading or downloading with encryption.

See also:

Creating A Skykey

curl -A "Sia-Agent"  -u "":<apipassword> -d "name=key_to_the_castle" -d "type=private-id" "localhost:9980/skynet/createskykey"
skynet skykey create "testcreateskykey"
// NOTE: this function has not yet been implemented for this SDK.

import { SkynetClient } from "skynet-js";

const client = new SkynetClient();
const name = "testcreateskykey";

async function createSkykeyExample() {
  try {
    const skykey = await client.createSkykey(name, "private-id");
  } catch (error) {
    console.log(error)
  }
}
// NOTE: this function has not yet been implemented for this SDK.

const { SkynetClient } = require('@nebulous/skynet');

const client = new SkynetClient();
const name = "testcreateskykey";

(async () => {
    const skykey = await client.createSkykey(name, "private-id");
})();
# NOTE: this function has not yet been implemented for this SDK.

import siaskynet as skynet

client = skynet.SkynetClient()
name = "testcreateskykey"

skykey = client.create_skykey(name, "private-id")
print("Create skykey successful, skykey: " + skykey)
package main

import (
    "fmt"
    skynet "github.com/NebulousLabs/go-skynet/v2"
)

const name = "testcreateskykey"
var client = skynet.New()

func main() {
    fmt.Printf("Creating skykey with name %v...\n", name)
    skykey, err := client.CreateSkykey(name, "private-id", skynet.DefaultCreateSkykeyOptions)
    if err != nil {
        panic("Unable to create skykey: " + err.Error())
    }
    fmt.Printf("Created skykey %v\n", skykey)

This function creates a skykey stored under the given name.

Parameters

Parameter Description
name Desired name of the skykey.
type Desired type of the skykey. The two supported types are "public-id" and "private-id". Users should use "private-id" skykeys unless they have a specific reason to use "public-id" skykeys which reveal skykey IDs and show which skyfiles are encrypted with the same skykey.

Response

{
  "skykey": "skykey:AUI0eAOXWXHwW6KOLyI5O1OYduVvHxAA8qUR_fJ8Kluasb-ykPlHBEjDczrL21hmjhH0zAoQ3-Qq?name=testskykey1",
  "name": "key_to_the_castle",
  "id": "ai5z8cf5NWbcvPBaBn0DFQ==",
  "type": "private-id"
}
Coming Soon
{
  "skykey": "skykey:AUI0eAOXWXHwW6KOLyI5O1OYduVvHxAA8qUR_fJ8Kluasb-ykPlHBEjDczrL21hmjhH0zAoQ3-Qq?name=testskykey1",
  "name": "key_to_the_castle",
  "id": "ai5z8cf5NWbcvPBaBn0DFQ==",
  "type": "private-id"
}
{
  "skykey": "skykey:AUI0eAOXWXHwW6KOLyI5O1OYduVvHxAA8qUR_fJ8Kluasb-ykPlHBEjDczrL21hmjhH0zAoQ3-Qq?name=testskykey1",
  "name": "key_to_the_castle",
  "id": "ai5z8cf5NWbcvPBaBn0DFQ==",
  "type": "private-id"
}
{
  "skykey": "skykey:AUI0eAOXWXHwW6KOLyI5O1OYduVvHxAA8qUR_fJ8Kluasb-ykPlHBEjDczrL21hmjhH0zAoQ3-Qq?name=testskykey1",
  "name": "key_to_the_castle",
  "id": "ai5z8cf5NWbcvPBaBn0DFQ==",
  "type": "private-id"
}
{
  "skykey": "skykey:AUI0eAOXWXHwW6KOLyI5O1OYduVvHxAA8qUR_fJ8Kluasb-ykPlHBEjDczrL21hmjhH0zAoQ3-Qq?name=testskykey1",
  "name": "key_to_the_castle",
  "id": "ai5z8cf5NWbcvPBaBn0DFQ==",
  "type": "private-id"
}
Field Type Description
skykey string Base-64 encoded Skykey
name string Name of the Skykey
id string ID of the Skykey
type string Desired type of the skykey. See above for more information.

Adding A Skykey

curl -A "Sia-Agent" -u "":<apipassword> -d "skykey=BAAAAAAAAABrZXkxAAAAAAAAAAQgAAAAAAAAADiObVg49-0juJ8udAx4qMW-TEHgDxfjA0fjJSNBuJ4a" "localhost:9980/skynet/addskykey"
skynet skykey add "skykey:AUI0eAOXWXHwW6KOLyI5O1OYduVvHxAA8qUR_fJ8Kluasb-ykPlHBEjDczrL21hmjhH0zAoQ3-Qq"
// NOTE: this function has not yet been implemented for this SDK.

import { SkynetClient } from "skynet-js";

const client = new SkynetClient();
const skykey = "skykey:AUI0eAOXWXHwW6KOLyI5O1OYduVvHxAA8qUR_fJ8Kluasb-ykPlHBEjDczrL21hmjhH0zAoQ3-Qq";

async function addSkykeyExample() {
  try {
    await client.addSkykey(skykey);
  } catch (error) {
    console.log(error)
  }
}
// NOTE: this function has not yet been implemented for this SDK.

const { SkynetClient } = require('@nebulous/skynet');

const client = new SkynetClient();
const skykey = "skykey:AUI0eAOXWXHwW6KOLyI5O1OYduVvHxAA8qUR_fJ8Kluasb-ykPlHBEjDczrL21hmjhH0zAoQ3-Qq";

(async () => {
    await client.addSkykey(skykey);
})();
# NOTE: this function has not yet been implemented for this SDK.

import siaskynet as skynet

client = skynet.SkynetClient()
skykey = "skykey:AUI0eAOXWXHwW6KOLyI5O1OYduVvHxAA8qUR_fJ8Kluasb-ykPlHBEjDczrL21hmjhH0zAoQ3-Qq"

client.add_skykey(skykey)
print("Add skykey successful")
package main

import (
    "fmt"
    skynet "github.com/NebulousLabs/go-skynet/v2"
)

const skykey = "skykey:AUI0eAOXWXHwW6KOLyI5O1OYduVvHxAA8qUR_fJ8Kluasb-ykPlHBEjDczrL21hmjhH0zAoQ3-Qq"
var client = skynet.New()

func main() {
    fmt.Printf("Adding skykey %v...\n", skykey)
    err := client.AddSkykey(skykey, skynet.DefaultAddSkykeyOptions)
    if err != nil {
        panic("Unable to add skykey: " + err.Error())
    }

This function stores the given skykey with the renter's skykey manager.

Parameters

Parameter Description
skykey Base-64 encoded skykey

Response

Error or exception on failure.

Getting A Skykey By Name

# -G option is required to send --data (-d) with a GET.
curl -X GET -G -A "Sia-Agent" -u "":<apipassword> -d "name=key_to_the_castle" "localhost:9980/skynet/skykey"
skynet skykey get name "testcreateskykey"
// NOTE: this function has not yet been implemented for this SDK.

import { SkynetClient } from "skynet-js";

const client = new SkynetClient();
const name = "testcreateskykey";

async function getSkykeyByNameExample() {
  try {
    const skykey = await client.getSkykeyByName(name);
  } catch (error) {
    console.log(error)
  }
}
// NOTE: this function has not yet been implemented for this SDK.

const { SkynetClient } = require('@nebulous/skynet');

const client = new SkynetClient();
const name = "testcreateskykey";

(async () => {
    const skykey = await client.getSkykeyByName(name);
})();
# NOTE: this function has not yet been implemented for this SDK.

import siaskynet as skynet

client = skynet.SkynetClient()
name = "testcreateskykey"

skykey = client.get_skykey_by_name(name)
print("Get skykey successful, skykey: " + skykey)
package main

import (
    "fmt"
    skynet "github.com/NebulousLabs/go-skynet/v2"
)

const name = "testcreateskykey"
var client = skynet.New()

func main() {
    fmt.Printf("Getting skykey with name %v...\n", name)
    skykey, err := client.GetSkykeyByName(name, skynet.DefaultGetSkykeyOptions)
    if err != nil {
        panic("Unable to get skykey: " + err.Error())
    }
    fmt.Printf("Skykey: %#v\n", skykey)

This function returns the base-64 encoded skykey stored under that name.

Parameters

Parameter Description
name Name of the skykey being queried.

Response

See Creating A Skykey.

Getting A Skykey By ID

# -G option is required to send --data (-d) with a GET.
curl -X GET -G -A "Sia-Agent" -u "":<apipassword> -d "id=qwxONTt4agqbEmzPlSywaQ==" "localhost:9980/skynet/skykey"
skynet skykey get id "pJAPPfWkWXpss3BvMDCJCw=="
// NOTE: this function has not yet been implemented for this SDK.

import { SkynetClient } from "skynet-js";

const client = new SkynetClient();
const id = "pJAPPfWkWXpss3BvMDCJCw==";

async function getSkykeyByIdExample() {
  try {
    const skykey = await client.getSkykeyById(id);
  } catch (error) {
    console.log(error)
  }
}
// NOTE: this function has not yet been implemented for this SDK.

const { SkynetClient } = require('@nebulous/skynet');

const client = new SkynetClient();
const id = "pJAPPfWkWXpss3BvMDCJCw==";

(async () => {
    const skykey = await client.getSkykeyById(id);
})();
# NOTE: this function has not yet been implemented for this SDK.

import siaskynet as skynet

client = skynet.SkynetClient()
id = "pJAPPfWkWXpss3BvMDCJCw=="

skykey = client.get_skykey_by_id(id)
print("Get skykey successful, skykey: " + skykey)
package main

import skynet "github.com/NebulousLabs/go-skynet/v2"

const id = "pJAPPfWkWXpss3BvMDCJCw=="
var client = skynet.New()

func main() {
    fmt.Printf("Getting skykey with id %v...\n", id)
    skykey, err := client.GetSkykeyByID(id, skynet.DefaultGetSkykeyOptions)
    if err != nil {
        panic("Unable to get skykey: " + err.Error())
    }
    fmt.Printf("Skykey: %#v\n", skykey)
}

This function returns the base-64 encoded skykey stored under that ID.

Parameters

Parameter Description
id ID of the skykey being queried.

Response

See Creating A Skykey.

Listing Skykeys

curl -A "Sia-Agent" -u "":<apipassword> "localhost:9980/skynet/skykeys"
skynet skykey list
// NOTE: this function has not yet been implemented for this SDK.

import { SkynetClient } from "skynet-js";

const client = new SkynetClient();

async function getSkykeysExample() {
  try {
    const skykeys = await client.getSkykeys();
  } catch (error) {
    console.log(error)
  }
}
// NOTE: this function has not yet been implemented for this SDK.

const { SkynetClient } = require('@nebulous/skynet');

const client = new SkynetClient();

(async () => {
    const skykeys = await client.getSkykeys();
})();
# NOTE: this function has not yet been implemented for this SDK.

import siaskynet as skynet

client = skynet.SkynetClient()

skykeys = client.get_skykeys()
print("Get skykeys successful, skykeys: " + skykeys)
package main

import (
    "fmt"
    skynet "github.com/NebulousLabs/go-skynet/v2"
)

var client = skynet.New()

func main() {
    fmt.Println("Listing skykeys...")
    skykeys, err := client.ListSkykeys(skynet.DefaultListSkykeysOptions)
    if err != nil {
        panic("Unable to get skykeys: " + err.Error())
    }
    fmt.Printf("Skykeys: %v\n", skykeys)
}

This function lists all skykeys on the given portal.

Parameters

None

Response

List of Skykeys (see Creating A Skykey).

Handshake

Handshake is a protocol which allows the creation of update-able content with persistent links, backed by the Skynet infrastructure. For more information on using Handshake with Skynet, please see this blog post.

The SDKs contain support for downloading from Handshake domains as well as for resolving Handshake domains to retrieve the underlying skylinks.

Downloading Handshake Files

curl -A "Sia-Agent" "https://siasky.net/hns/doesn"
# NOTE: this function has not yet been implemented for this SDK.

skynet hns download "doesn" "./dst.html"
import { SkynetClient } from "skynet-js";

const client = new SkynetClient();
const domain = "doesn";

try {
  client.downloadFileHns(domain);
  // Or client.openFileHns(domain) to open it in a new browser tab.
} catch (error) {
  console.log(error);
}
# NOTE: this function has not yet been implemented for this SDK.

const { SkynetClient } = require('@nebulous/skynet');

const client = new SkynetClient();
const domain = "doesn";

(async () => {
    await client.downloadFileHns("./dst.html", domain);
    console.log('Handshake download successful');
})();
# NOTE: this function has not yet been implemented for this SDK.

import siaskynet as skynet

client = skynet.SkynetClient()
domain = "doesn"

client.download_file_hns("./dst.html", domain)
print("Handshake download successful")
// NOTE: this function has not yet been implemented for this SDK.

package main

import (
    "fmt"
    skynet "github.com/NebulousLabs/go-skynet/v2"
)

var client = skynet.New()

func main() {
  const domain = "doesn"

    err := client.DownloadFileHns("./dst.html", domain, skynet.DefaultDownloadHnsOptions)
    if err != nil {
        panic("Something went wrong, please try again.\nError: " + err.Error())
    }
    fmt.Println("Handshake download successful")
}

This function downloads a file from a given Handshake domain on the portal's /hns endpoint. To give an example, the full URL of the Sia-controlled Handshake domain doesn is https://siasky.net/hns/doesn.

Parameters

Field Description
path The local path where the file should be downloaded to.
domain The Handshake domain that should be downloaded.

Browser JS:

Field Description
domain The Handshake domain that should be downloaded.

Response

Empty on success.

Resolving Handshake Domains

curl -A "Sia-Agent" "https://siasky.net/hnsres/doesn"
# NOTE: this function has not yet been implemented for this SDK.

skynet hns resolve "doesn"
import { SkynetClient } from "skynet-js";

const client = new SkynetClient();
const domain = "doesn";

try {
  const data = client.resolveHns(domain);
} catch (error) {
  console.log(error);
}
# NOTE: this function has not yet been implemented for this SDK.

const { SkynetClient } = require('@nebulous/skynet');

const client = new SkynetClient();
const domain = "doesn";

(async () => {
    const data = await client.resolveHns(domain);
    console.log('Handshake resolve successful');
})();
# NOTE: this function has not yet been implemented for this SDK.

import siaskynet as skynet

client = skynet.SkynetClient()
domain = "doesn"

data = client.resolve_hns(domain)
print("Handshake resolve successful")
// NOTE: this function has not yet been implemented for this SDK.

package main

import (
    "fmt"
    skynet "github.com/NebulousLabs/go-skynet/v2"
)

const domain = "doesn"
var client = skynet.New()

func main() {
    err := client.ResolveHns(domain, skynet.DefaultResolveHnsOptions)
    if err != nil {
        panic("Something went wrong, please try again.\nError: " + err.Error())
    }
    fmt.Println("Handshake resolve successful")
}

This function resolves a given Handshake domain and returns its TXT record. In the context of Skynet, this should contain a skylink field. For example, a request to https://siasky.net/hnsres/doesn returns only the data {"skylink":"sia://IAC6CkhNYuWZqMVr1gob1B6tPg4MrBGRzTaDvAIAeu9A9w"}.

Parameters

Field Description
domain The Handshake domain that should be resolved.

Response

{"skylink":"sia://IAC6CkhNYuWZqMVr1gob1B6tPg4MrBGRzTaDvAIAeu9A9w"}
Coming Soon
{"skylink":"sia://IAC6CkhNYuWZqMVr1gob1B6tPg4MrBGRzTaDvAIAeu9A9w"}
{"skylink":"sia://IAC6CkhNYuWZqMVr1gob1B6tPg4MrBGRzTaDvAIAeu9A9w"}
{"skylink":"sia://IAC6CkhNYuWZqMVr1gob1B6tPg4MrBGRzTaDvAIAeu9A9w"}
{"skylink":"sia://IAC6CkhNYuWZqMVr1gob1B6tPg4MrBGRzTaDvAIAeu9A9w"}

The full TXT record containing the skylink is returned.

Browser JS API

The following are some methods and utilities that only make sense in the browser, and thus are only provided by the Browser JS SDK.

Opening A File

import { SkynetClient } from "skynet-js";

const client = new SkynetClient();
const skylink = "XABvi7JtJbQSMAcDwnUnmp2FKDPjg8_tTTFP4BwMSxVdEg";

try {
  client.openFile(skylink);
} catch (error) {
  console.log(error);
}

Use the client to open a skylink in a new browser tab. Browsers support opening natively only limited file extensions like .html or .jpg and will fallback to downloading the file.

Parameters

See Downloading A File.

Response

Empty on success.

Getting The Download URL

import { SkynetClient } from "skynet-js";

const client = new SkynetClient();
const skylink = "XABvi7JtJbQSMAcDwnUnmp2FKDPjg8_tTTFP4BwMSxVdEg";

try {
  const url = client.getSkylinkUrl(skylink);
} catch (error) {
  console.log(error);
}

Use the client to generate a direct skylink url.

Parameters

See Downloading A File.

Additional Options

Field Description Default
download Option to include download directive in the url that will force a download when used. false

Response

"https://siasky.net/XABvi7JtJbQSMAcDwnUnmp2FKDPjg8_tTTFP4BwMSxVdEg"
Field Description
url The URL for the given skylink on the client portal.

Getting A Handshake URL

import { SkynetClient } from "skynet-js";

const client = new SkynetClient();
const domain = "doesn";

try {
  const url = client.getHnsUrl(domain);
} catch (error) {
  console.log(error);
}

Use the client to generate a direct Handshake url from a Handshake domain.

Parameters

See Downloading Handshake Files.

Additional Options

Field Description Default
download Option to include download directive in the url that will force a download when used. false

Response

"https://siasky.net/hns/doesn"
Field Description
url The URL for the given Handshake domain on the client portal.

Getting A Handshake Resolver URL

import { SkynetClient } from "skynet-js";

const client = new SkynetClient();
const domain = "doesn";

try {
  const url = client.getHnsresUrl(domain);
} catch (error) {
  console.log(error);
}

Use the client to generate a direct Handshake Resolver url from a Handshake domain.

Parameters

See Resolving Handshake Domains.

Additional Options

Field Description Default
download Option to include download directive in the url that will force a download when used. false

Response

"https://siasky.net/hnsres/doesn"
Field Description
url The URL for the given Handshake Resolver domain on the client portal.
import { parseSkylink } from "skynet-js";

const client = new SkynetClient();
const uri = "sia://XABvi7JtJbQSMAcDwnUnmp2FKDPjg8_tTTFP4BwMSxVdEg";

try {
  const skylink = parseSkylink(uri);
} catch (error) {
  console.log(error);
}

Extract a skylink from a string.

Parameters

Field Description
string The string to extract a skylink from.

Currently supported string types are:

Response

"CABAB_1Dt0FJsxqsu_J4TodNCbCGvtFf1Uys_3EgzOlTcg"
Field Description
skylink See Uploading A File.

API Authentication

curl -X POST -A "Sia-Agent" --user "":"foobar" \
  "https://siasky.net/skynet/skyfile" -F file=@image.jpg
skynet upload "./image.jpg" --api-key "foobar" --custom-user-agent "Sia-Agent"
import { SkynetClient } from "skynet-js";

const client = new SkynetClient();

async function authenticationExample() {
  try {
    const { skylink } = await client.upload(
      file,
      { APIKey: "foobar", customUserAgent: "Sia-Agent" }
    );
  } catch (error) {
    console.log(error);
  }
}
const { SkynetClient } = require('@nebulous/skynet');

const client = new SkynetClient();

(async () => {
    const skylink = await client.uploadFile(
    "./image.jpg",
    { APIKey: "foobar", customUserAgent: "Sia-Agent" }
  );
    console.log(`Upload successful, skylink: ${skylink}`);
})();
import siaskynet as skynet

client = skynet.SkynetClient();

skylink = client.upload_file(
  "image.jpg",
  {"api_key": "foobar", "custom_user_agent": "Sia-Agent"}
)
print("Upload successful, skylink: " + skylink)
package main

import (
    "fmt"
    skynet "github.com/NebulousLabs/go-skynet/v2"
)

var client = skynet.New()

func main() {
    opts := skynet.DefaultUploadOptions
    opts.APIKey = "foobar"
  opts.CustomUserAgent = "Sia-Agent"
    skylink, err := client.UploadFile("./image.jpg", opts)
    if err != nil {
        panic("Unable to upload: " + err.Error())
    }
    fmt.Printf("Upload successful, skylink: %v\n", skylink)
}

Portals will likely require authentication on several of their endpoints. This is to prevent unwanted modifications to the blocklist, portal list, etc.

If you are authorized to use password-protected endpoints on a portal, you may authenticate yourself by setting the APIKey custom option when calling a function.

Setting The User Agent

The portal may also require that certain sensitive requests contain a custom user agent header, usually Sia-Agent. This is for security purposes, as otherwise a malicious website could make requests to your local portal on your behalf and steal coins.

We want this to be an opt-in for now, so Sia-Agent is not currently the default. You may change the user agent header by setting the customUserAgent custom option. See Setting Additional Options.

More Information

For more information about authentication on portals and local siad instances please see the Sia Docs.

Updating From v1

Users wishing to update their SDK from v1 to v2 should note the following:

  1. All SDKs have been updated to match Browser JS and require a client. You will first need to create a client and then make all API calls from this client.
  2. The defaultPortalUrl string has been renamed to defaultSkynetPortalUrl and defaultPortalUrl is not a function.
  3. Browser JS has had the following updates:
    1. download and open were renamed to downloadFile and openFile.
    2. upload was renamed to uploadFile and the response was changed to only include a skylink. To obtain the full response as in the old upload, use the new uploadFileRequest.
    3. uploadFile and uploadDirectory now return skylinks prefixed by sia:.
    4. getDownloadUrl has been renamed to getSkylinkUrl.