Guides

Official SDKs and extensions

Install an official SellApp SDK, read your first product, and find community integrations.

An SDK is a library that handles API requests and responses for your application. You can also use the cURL quickstart or your language's HTTP client.

Official SDKs

Use an official SDK to work with products, orders, customers, and subscriptions from your server. The SDKs include typed requests and responses, pagination, and structured errors. They use API keys to connect to your store.

Node.js and TypeScript

Install

Use Node.js 20 or newer, preferably a currently supported release. In your server-side application's directory, run:

npm install @sell.app/sdk

The package supports ES modules and CommonJS, with TypeScript declarations for both. For CommonJS, import it with const { SellApp } = require('@sell.app/sdk').

Read your first product

This request reads at most one product. It does not create data or charge anyone. Create a server-side key in API keys. Enable its listing ability and allow access to your target store. Keep the key out of browser code and source control. See authentication for setup and permissions.

In a Bash-compatible terminal, replace the key and store slug:

export SELLAPP_API_KEY='replace-with-your-key'
export SELLAPP_STORE='launch-lab'
export SELLAPP_API_BASE_URL='https://sell.app/api'

For launch-lab.sell.app, the store slug is launch-lab. Save the following as first-request.mjs, then run node first-request.mjs in your application:

import { SellApp } from '@sell.app/sdk';// Explicit endpoint selection keeps examples from accidentally calling a live store.const baseUrl = process.env.SELLAPP_API_BASE_URL;if (!baseUrl) throw new Error('Set SELLAPP_API_BASE_URL before running this example');const client = new SellApp({ baseUrl }); // Reads SELLAPP_API_KEY and SELLAPP_STORE.const page = await client.products.list({ limit: 1 });for (const product of page.data) {  console.log(product.id, product.title);}if (page.data.length === 0) console.log('No products yet. The request worked!');

The program prints the product's ID and title. If your store has no products, No products yet. The request worked! confirms the request succeeded. The SDK reads your key and store from the environment; this example passes SELLAPP_API_BASE_URL explicitly to choose the API address.

If the request fails, check your key for 401, the key's listing ability and store permissions for 403, or the store slug and resource ID for 404. Follow the response's retry guidance for 429. Keep the request ID when asking for help, and never share your API key. See errors and the SDK's error example.

Next, use the method reference to find an operation, or read the pagination and configuration guide. Prefer terminal commands? Use the official CLI, which connects with browser login.

Python

Use synchronous or asynchronous clients in your server-side Python application. Keep your API key on your server and out of source control.

Install Python

Use Python 3.10 or newer, preferably a currently supported release. In your application's directory, create a virtual environment to keep its packages separate:

python -m venv .venv

Activate it with . .venv/bin/activate on macOS or Linux, or .venv\Scripts\Activate.ps1 in Windows PowerShell. Then install the SDK:

python -m pip install sellapp-sdk

The package name is sellapp-sdk; Python code imports it as sellapp_sdk.

Read your first product with Python

This request reads at most one product. It does not create data or charge anyone. Create a server-side key in API keys. Enable its listing ability and allow access to your target store. See authentication for setup and permissions.

In a Bash-compatible terminal, replace the key and store slug:

export SELLAPP_API_KEY='replace-with-your-key'
export SELLAPP_STORE='launch-lab'
export SELLAPP_API_BASE_URL='https://sell.app/api'

For launch-lab.sell.app, the store slug is launch-lab. In PowerShell, set these with $env:SELLAPP_API_KEY = 'replace-with-your-key', $env:SELLAPP_STORE = 'launch-lab', and $env:SELLAPP_API_BASE_URL = 'https://sell.app/api' instead.

Save the following as first_request.py, then run python first_request.py with your virtual environment active:

import osfrom sellapp_sdk import SellAppClientbase_url = os.environ["SELLAPP_API_BASE_URL"]if not base_url.strip():    raise ValueError("Set a nonempty SELLAPP_API_BASE_URL before running this example")with SellAppClient(base_url=base_url) as client:    page = client.products.list(limit=1)    for product in page.data:        print(product.id, product.title)    if not page.data:        print("No products yet. Your connection is ready.")

The program prints the product's ID and title. If your store has no products, No products yet. Your connection is ready. confirms the request succeeded. The products are in page.data, and the with block closes the HTTP client after use. The SDK reads your key and store from the environment; this example passes SELLAPP_API_BASE_URL explicitly to choose the API address.

If the request fails, check your key for 401, the key's listing ability and store permissions for 403, or the store slug and resource ID for 404. Follow the response's retry guidance for 429. If the error includes a request ID, keep it when asking for help, and never share your API key. See errors and the SDK's error example.

Next, use the method reference to find an operation, read the pagination and configuration guide, or try the asynchronous first request.

C# and .NET

Use asynchronous methods and typed responses in your server-side .NET application. Keep your API key on your server and out of source control.

Install .NET

Use the .NET 8 SDK or later. In an existing application, run:

dotnet add package SellApp --version 0.1.1

For a new console application, create the project first:

dotnet new console --name SellAppExample --framework net8.0
cd SellAppExample
dotnet add package SellApp --version 0.1.1

Read your first product with C#

This request reads at most one product. It does not create data or charge anyone. Create a server-side key in API keys. Enable its listing ability and allow access to your target store. See authentication for setup and permissions.

In PowerShell, replace the key and store slug:

$env:SELLAPP_API_KEY = 'replace-with-your-key'
$env:SELLAPP_STORE = 'launch-lab'
$env:SELLAPP_API_BASE_URL = 'https://sell.app/api'

In a Bash-compatible terminal, use export SELLAPP_API_KEY='replace-with-your-key', export SELLAPP_STORE='launch-lab', and export SELLAPP_API_BASE_URL='https://sell.app/api' instead. For launch-lab.sell.app, the store slug is launch-lab.

Replace your application's Program.cs with the following program, then run dotnet run from the application directory:

using SellApp;using Newtonsoft.Json.Linq;namespace SellAppExamples;public static class Onboarding{    public static async Task FirstRequestAsync(SellAppClient client, TextWriter output, CancellationToken ct)    {        var page = await client.Products.ListAsync(new ProductsListOptions { Limit = 1 }, cancellationToken: ct);        foreach (var product in page.Data)            await output.WriteLineAsync($"{product.Id}: {product.Title}");        if (page.Data.Count == 0)            await output.WriteLineAsync("No products yet. Your connection is ready.");    }    public static async Task PaginateAsync(SellAppClient client, TextWriter output, CancellationToken ct)    {        // Bound this example to three pages; ask for each page explicitly.        for (var number = 1; number <= 3; number++)        {            var page = await client.Products.ListAsync(                new ProductsListOptions { Limit = 15, Page = number }, cancellationToken: ct);            foreach (var product in page.Data)                await output.WriteLineAsync($"{product.Id}: {product.Title}");            if (page.Meta?["current_page"]?.Value<int>() >= page.Meta?["last_page"]?.Value<int>())                break;        }    }    public static async Task<long> CatalogWorkflowAsync(SellAppClient client, CancellationToken ct)    {        // Creates and updates real catalog data when used outside the fixture tests.        var created = await client.Products.CreateAsync(new ProductsCreateOptions {            Title = "Design kit", Description = "Templates for your next project.", Visibility = new CatalogVisibility("HIDDEN")        }, cancellationToken: ct);        var product = await client.Products.GetAsync(created.Data.Id.ToString(), cancellationToken: ct);        var updated = await client.Products.UpdateAsync(product.Data.Id.ToString(), new ProductsUpdateOptions {            Title = "Design kit revised"        }, cancellationToken: ct);        return updated.Data.Id;    }    public static async Task<long> CheckoutAsync(SellAppClient client, string orderId, CancellationToken ct)    {        // Starts a real payment-provider checkout. Inspect current order state before retrying.        var order = await client.Orders.GetAsync(orderId, cancellationToken: ct);        var checkout = await client.Orders.CreateCheckoutAsync(order.Data.Id.ToString(), new OrdersCreateCheckoutOptions {}, cancellationToken: ct);        return checkout.Data.Id;    }    public static async Task<long> UploadAsync(SellAppClient client, string productId, string variantId, byte[] file, CancellationToken ct)    {        var uploaded = await client.VariantDeliverableFiles.UploadAsync(productId, variantId, new VariantDeliverableFilesUploadOptions { File = file }, cancellationToken: ct);        var saved = await client.VariantDeliverableFiles.GetAsync(productId, variantId, uploaded.Data.Id.ToString(), cancellationToken: ct);        return saved.Data.Id;    }    public static string DescribeError(Exception error) => error switch    {        AuthenticationException e => $"Check your API key and store: {e.Message}",        ApiException e => $"API status {e.Status}: {e.Message} (request {e.RequestId ?? "unavailable"})",        SellAppTimeoutException e => $"Request timed out: {e.Message}",        OperationCanceledException => "Request canceled.",        _ => $"Request failed: {error.Message}",    };    public static async Task<int> Main(string[] args)    {        try        {            string Required(string name) => Environment.GetEnvironmentVariable(name) is { Length: > 0 } value                ? value : throw new InvalidOperationException($"Set {name} before running this example.");            using var client = new SellAppClient(new SellAppOptions            {                ApiKey = Required("SELLAPP_API_KEY"),                Store = Required("SELLAPP_STORE"),                BaseUrl = Required("SELLAPP_API_BASE_URL"),                MaxRetries = 0,            });            using var cancellation = new CancellationTokenSource(TimeSpan.FromSeconds(30));            if (args.Contains("pagination"))                await PaginateAsync(client, Console.Out, cancellation.Token);            else                await FirstRequestAsync(client, Console.Out, cancellation.Token);            return 0;        }        catch (Exception exception)        {            Console.Error.WriteLine(DescribeError(exception));            return 1;        }    }}

The program prints the product's ID and title. If your store has no products, No products yet. Your connection is ready. confirms the request succeeded. Products are in page.Data. The using statement closes the client after use, and the cancellation token limits the request to 30 seconds. The example requires all three environment variables before sending a request.

If the request fails, check your key for 401, its listing ability and your store permissions for 403, or the store slug and resource ID for 404. Follow the response's retry guidance for 429. Keep any request ID when asking for help, and never share your API key. See errors.

Next, use the method reference to find an operation, or read the pagination and configuration guide.

PHP

Use typed requests and responses in your server-side PHP application. Keep your API key on your server and out of source control.

Install PHP

Use PHP 8.2 or newer within PHP 8 and Composer 2. From your application's directory, install the SDK:

composer require 'sellapp/sellapp:^0.1.1'

Composer installs Guzzle, the HTTP client used by the SDK, and checks the required PHP extensions.

Read your first product with PHP

This request reads at most one product. It does not create data or charge anyone. Create a server-side key in API keys. Enable its listing ability and allow access to your target store. See authentication for setup and permissions.

Create an examples/ directory beside your application's vendor/ directory. Save this complete program as examples/first-request.php:

<?phpdeclare(strict_types=1);require __DIR__ . '/../vendor/autoload.php';use SellApp\Client;$baseUrl = getenv('SELLAPP_API_BASE_URL');if (!$baseUrl) {    throw new RuntimeException('Set SELLAPP_API_BASE_URL before running this example');}$client = new Client(baseUrl: $baseUrl); // Reads SELLAPP_API_KEY and SELLAPP_STORE.$page = $client->products()->list(limit: 1);foreach ($page->data as $product) {    echo $product->id . ' ' . $product->title . PHP_EOL;}if ($page->data === []) {    echo 'No products yet. The request worked!' . PHP_EOL;}

In a Bash-compatible terminal, replace the key and store slug, then run the program from your application's root directory:

export SELLAPP_API_KEY='replace-with-your-key'
export SELLAPP_STORE='launch-lab'
export SELLAPP_API_BASE_URL='https://sell.app/api'
php examples/first-request.php

For launch-lab.sell.app, the store slug is launch-lab. In PowerShell, set the environment variables with $env:SELLAPP_API_KEY = 'replace-with-your-key', $env:SELLAPP_STORE = 'launch-lab', and $env:SELLAPP_API_BASE_URL = 'https://sell.app/api' instead.

The program prints the product's ID and title. If your store has no products, No products yet. The request worked! confirms the request succeeded. Products are in $page->data. The SDK reads your key and store from the environment; the example passes SELLAPP_API_BASE_URL explicitly to choose the API address.

If the request fails, check your key for 401, its listing ability and your store permissions for 403, or the store slug and resource ID for 404. Follow the response's retry guidance for 429. Keep any request ID when asking for help, and never share your API key. See errors and the SDK's error example.

Next, use the method reference to find an operation, or read the pagination and configuration guide.

Go

Use typed responses and cancellable requests in your server-side Go application.

Install Go

Use Go 1.23 or newer. In an existing Go module, install this SDK version:

go get github.com/sellapp/sellapp-go@v0.1.1

For a new application, create the directory and module first:

mkdir sellapp-example
cd sellapp-example
go mod init example.com/sellapp-example
go get github.com/sellapp/sellapp-go@v0.1.1

Go records the module and its checksum in go.mod and go.sum.

Read your first product with Go

This request reads at most one product. It does not create data or charge anyone. Create a server-side key in API keys. Enable its listing ability and allow access to the store you want to read. Keep the key on your server and out of source control. See authentication for setup and permissions.

In a Bash-compatible terminal, replace the key and store slug:

export SELLAPP_API_KEY='replace-with-your-key'
export SELLAPP_STORE='launch-lab'
export SELLAPP_API_BASE_URL='https://sell.app/api'

For launch-lab.sell.app, the store slug is launch-lab. In PowerShell, set these with $env:SELLAPP_API_KEY = 'replace-with-your-key', $env:SELLAPP_STORE = 'launch-lab', and $env:SELLAPP_API_BASE_URL = 'https://sell.app/api' instead.

Save this complete program as main.go in your application directory, then run go run .:

package mainimport (	"context"	"errors"	"fmt"	"io"	"os"	"time"	"github.com/sellapp/sellapp-go")func firstRequest(ctx context.Context, client *sellapp.Client, out io.Writer) error {	limit := 1	products := client.Products().List(ctx, &sellapp.ProductsListParams{Limit: &limit})	if products.Next() {		product := products.Current()		fmt.Fprintf(out, "%d: %s\n", product.ID, product.Title)	} else if products.Err() == nil {		fmt.Fprintln(out, "No products yet. Your connection is ready.")	}	return products.Err()}func paginate(ctx context.Context, client *sellapp.Client, out io.Writer) error {	limit := 15	products := client.Products().List(ctx, &sellapp.ProductsListParams{Limit: &limit})	// Keep this example bounded: inspect at most 30 products.	for count := 0; count < 30 && products.Next(); count++ {		fmt.Fprintf(out, "%d: %s\n", products.Current().ID, products.Current().Title)	}	return products.Err()}func reportError(err error, out io.Writer) {	var authentication *sellapp.AuthenticationError	var rateLimit *sellapp.RateLimitExceededError	var timeout *sellapp.TimeoutError	switch {	case errors.As(err, &authentication):		fmt.Fprintf(out, "Check the API key and store: %s (request %s)\n", authentication.Message, authentication.RequestID)	case errors.As(err, &rateLimit):		fmt.Fprintf(out, "Rate limited: %s (request %s)\n", rateLimit.Message, rateLimit.RequestID)	case errors.As(err, &timeout):		fmt.Fprintln(out, "Request timed out:", timeout)	default:		fmt.Fprintln(out, "Request failed:", err)	}}func run(out io.Writer) error {	// An explicit URL keeps accidental example runs from reaching production.	baseURL := os.Getenv("SELLAPP_API_BASE_URL")	if baseURL == "" || os.Getenv("SELLAPP_API_KEY") == "" || os.Getenv("SELLAPP_STORE") == "" {		return fmt.Errorf("set SELLAPP_API_BASE_URL, SELLAPP_API_KEY, and SELLAPP_STORE")	}	client := sellapp.NewClient("", "", sellapp.WithBaseURL(baseURL), sellapp.WithMaxRetries(0))	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)	defer cancel()	if os.Getenv("SELLAPP_EXAMPLE_MODE") == "pagination" {		return paginate(ctx, client, out)	}	return firstRequest(ctx, client, out)}func main() {	if err := run(os.Stdout); err != nil {		reportError(err, os.Stderr)		os.Exit(1)	}}

The program prints a product's ID and title. If your store has no products, No products yet. Your connection is ready. confirms the request succeeded. The client reads your API key and store from the environment. The example passes SELLAPP_API_BASE_URL explicitly and limits the operation to 30 seconds.

products.Next() advances the iterator, products.Current() returns the product, and products.Err() distinguishes an empty result from a failed request. The program's default mode reads one product; its separate pagination mode reads at most 30.

If the request fails, check your key for 401. For 403, check its listing ability, allowed stores, and your current store permissions. For 404, check the store slug. Follow the response's retry guidance for 429. Keep any request ID when asking for help, and never share your API key. See errors.

Next, browse the Go package reference or the method reference. See the pagination and configuration guide for retries and bounded iteration.

Kotlin and JVM

Use blocking methods or Kotlin coroutines in your server-side JVM application.

Install Kotlin

Install JDK 17 and Gradle 8.9 for the example below. The Gradle project selects and downloads Kotlin 2.1.20; a separate Kotlin compiler installation is not required. In an existing Gradle project, add Maven Central and the SDK dependency:

repositories { mavenCentral() }

dependencies {
    implementation("app.sell:sellapp:0.1.1")
}

For a complete runnable example, create an empty project directory. Save this as settings.gradle.kts:

rootProject.name = "sellapp-example"

Save this as build.gradle.kts. The additional dependencies are used directly by the example's HTTP client and coroutine mode:

plugins {
    kotlin("jvm") version "2.1.20"
    application
}
repositories { mavenCentral() }
dependencies {
    implementation("app.sell:sellapp:0.1.1")
    implementation("com.squareup.okhttp3:okhttp:4.12.0")
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.1")
}
kotlin { jvmToolchain(17) }
application { mainClass.set("sellapp.examples.OnboardingKt") }

Read your first product with Kotlin

This request reads at most one product. It does not create data or charge anyone. Create a server-side key in API keys. Enable its listing ability and allow access to the store you want to read. Keep the key on your server and out of source control. See authentication for setup and permissions.

In a Bash-compatible terminal, replace the key and store slug:

export SELLAPP_API_KEY='replace-with-your-key'
export SELLAPP_STORE='launch-lab'
export SELLAPP_API_BASE_URL='https://sell.app/api'

For launch-lab.sell.app, the store slug is launch-lab. In PowerShell, set these with $env:SELLAPP_API_KEY = 'replace-with-your-key', $env:SELLAPP_STORE = 'launch-lab', and $env:SELLAPP_API_BASE_URL = 'https://sell.app/api' instead.

Create src/main/kotlin/ in the example project. Save this complete program as src/main/kotlin/Onboarding.kt, then run gradle run from the project directory:

package sellapp.examplesimport app.sell.sellapp.SellAppimport app.sell.sellapp.common.exceptions.SellAppApiExceptionimport app.sell.sellapp.common.exceptions.SellAppSerializationExceptionimport app.sell.sellapp.common.exceptions.SellAppTimeoutExceptionimport kotlinx.coroutines.runBlockingimport okhttp3.OkHttpClientimport app.sell.sellapp.types.CatalogVisibilityimport app.sell.sellapp.common.http.PatchFieldfun firstRequest(client: SellApp): String {    val product = client.products.list(limit = 1).data.firstOrNull()        ?: return "No products yet. Your connection is ready."    return "${product.id}: ${product.title}"}suspend fun firstRequestSuspend(client: SellApp): String {    val product = client.products.listSuspend(limit = 1).data.firstOrNull()        ?: return "No products yet. Your connection is ready."    return "${product.id}: ${product.title}"}fun inspectProducts(client: SellApp): String {    return try {        client.products.list(limit = 1).take(30).joinToString("\n") { "${it.id}: ${it.title}" }.ifEmpty { "No products yet." }    } catch (error: SellAppSerializationException) {        "Product pages could not be decoded safely: ${error.message}."    }}fun catalogWorkflow(client: SellApp): Long {    // This changes real catalog data outside the local fixture test.    val created = client.products.create(title = "Design kit", description = "Templates for your next project.", visibility = CatalogVisibility.Hidden)    val product = client.products.get(created.data.id.toString())    return client.products.update(product.data.id.toString(), title = PatchField.Present("Design kit revised")).data.id}suspend fun catalogWorkflowSuspend(client: SellApp): Long {    val created = client.products.createSuspend(title = "Design kit", description = "Templates for your next project.", visibility = CatalogVisibility.Hidden)    val product = client.products.getSuspend(created.data.id.toString())    return client.products.updateSuspend(product.data.id.toString(), title = PatchField.Present("Design kit revised")).data.id}fun checkout(client: SellApp, orderId: String): Long {    // Creates a provider checkout; inspect the order before retrying a lost response.    val order = client.orders.get(orderId)    return client.orders.createCheckout(order.data.id.toString()).data.id}fun upload(client: SellApp, productId: String, variantId: String, file: ByteArray): Long {    val uploaded = client.variantDeliverableFiles.upload(productId, variantId, file)    return client.variantDeliverableFiles.get(productId, variantId, uploaded.data.id.toString()).data.id}suspend fun checkoutSuspend(client: SellApp, orderId: String): Long {    val order = client.orders.getSuspend(orderId)    return client.orders.createCheckoutSuspend(order.data.id.toString()).data.id}suspend fun uploadSuspend(client: SellApp, productId: String, variantId: String, file: ByteArray): Long {    val uploaded = client.variantDeliverableFiles.uploadSuspend(productId, variantId, file)    return client.variantDeliverableFiles.getSuspend(productId, variantId, uploaded.data.id.toString()).data.id}fun describeError(error: Exception): String = when (error) {    is SellAppApiException -> "API status ${error.status}: ${error.message} (request ${error.requestId ?: "unavailable"})"    is SellAppTimeoutException -> "Request timed out: ${error.message}"    else -> "Request failed: ${error.message}"}fun main(args: Array<String>) {    fun required(name: String): String = System.getenv(name)?.takeIf { it.isNotBlank() }        ?: error("Set $name before running this example.")    val http = OkHttpClient()    try {        val client = SellApp(            apiKey = required("SELLAPP_API_KEY"),            store = required("SELLAPP_STORE"),            baseUrl = required("SELLAPP_API_BASE_URL"),            maxRetries = 0,            httpClient = http,        )        val result = when (args.firstOrNull()) {            "suspend" -> runBlocking { firstRequestSuspend(client) }            "pagination" -> inspectProducts(client)            else -> firstRequest(client)        }        println(result)    } catch (error: Exception) {        System.err.println(describeError(error))        throw error    } finally {        http.dispatcher.executorService.shutdown()        http.connectionPool.evictAll()        http.cache?.close()    }}

Running the program without arguments reads one product and prints its ID and title. No products yet. Your connection is ready. means an empty store was read successfully. Products are in page.data. The program requires all three environment variables and closes its HTTP client after use.

The complete example also contains catalog, checkout, and upload helper functions. Those helpers can change real data if you call them; gradle run does not call them. Use gradle run --args=suspend to perform the same read with a coroutine.

If the request fails, check your key for 401. For 403, check its listing ability, allowed stores, and your current store permissions. For 404, check the store slug. Follow the response's retry guidance for 429. Keep any request ID when asking for help, and never share your API key. See errors.

Next, use the method reference to find an operation, or read the pagination and configuration guide. The example project also includes a Gradle launcher.

Ruby

Use Ruby objects, pagination, and typed errors in your server-side application.

Install Ruby

Use Ruby 3.1.7 or newer and Bundler. Add these lines to your application's Gemfile:

source "https://rubygems.org"
gem "sellapp", "~> 0.1.1"

Run bundle install from the application directory. For a new application, create an empty directory and save the two lines above as Gemfile first. Bundler records the selected versions in Gemfile.lock.

Read your first product with Ruby

This request reads at most one product. It does not create data or charge anyone. Create a server-side key in API keys. Enable its listing ability and allow access to the store you want to read. Keep the key on your server and out of source control. See authentication for setup and permissions.

In a Bash-compatible terminal, replace the key and store slug:

export SELLAPP_API_KEY='replace-with-your-key'
export SELLAPP_STORE='launch-lab'
export SELLAPP_API_BASE_URL='https://sell.app/api'

For launch-lab.sell.app, the store slug is launch-lab. In PowerShell, set these with $env:SELLAPP_API_KEY = 'replace-with-your-key', $env:SELLAPP_STORE = 'launch-lab', and $env:SELLAPP_API_BASE_URL = 'https://sell.app/api' instead.

Save this complete program as first-request.rb in your application directory, then run bundle exec ruby first-request.rb:

# frozen_string_literal: truerequire "sellapp"base_url = ENV.fetch("SELLAPP_API_BASE_URL")raise "Set SELLAPP_API_BASE_URL before running this example" if base_url.empty?client = SellApp::Client.new(base_url: base_url) # Reads SELLAPP_API_KEY and SELLAPP_STORE.page = client.products.list(limit: 1)page.data.each { |product| puts "#{product.id} #{product.title}" }puts "No products yet. The request worked!" if page.data.empty?

The program prints the product's ID and title. If your store has no products, No products yet. The request worked! confirms the request succeeded. Products are in page.data. The client reads your API key and store from the environment; this example passes SELLAPP_API_BASE_URL explicitly.

The first program stops if the request fails. The error example shows how to catch API, timeout, and transport errors.

If the request fails, check your key for 401. For 403, check its listing ability, allowed stores, and your current store permissions. For 404, check the store slug. Follow the response's retry guidance for 429. Keep any request ID when asking for help, and never share your API key. See errors.

Next, use the method reference to find an operation, or read the pagination and configuration guide.

Rust

Use asynchronous requests and typed responses in your server-side Rust application.

Install Rust

Use a current stable Rust toolchain. The SDK uses Rust edition 2024; a minimum supported Rust version for the complete dependency graph has not been established.

On Linux, the SDK's HTTPS dependency also needs OpenSSL development headers and pkg-config. On Debian or Ubuntu, install them before building:

sudo apt-get install pkg-config libssl-dev

For other Linux distributions, see the OpenSSL build requirements.

Create a new application, then add the SDK and Tokio, the runtime that executes the asynchronous example:

cargo new sellapp-example
cd sellapp-example
cargo add sellapp-sdk@0.1.1 --rename sellapp
cargo add tokio@1 --features macros,rt-multi-thread

The published crate is sellapp-sdk. The dependency is named sellapp in your application, matching the code's imports. Your Cargo.toml dependencies will include:

[dependencies]
sellapp = { package = "sellapp-sdk", version = "0.1.1" }
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }

Read your first product with Rust

This request reads at most one product. It does not create data or charge anyone. Create a server-side key in API keys. Enable its listing ability and allow access to the store you want to read. Keep the key on your server and out of source control. See authentication for setup and permissions.

In a Bash-compatible terminal, replace the key and store slug:

export SELLAPP_API_KEY='replace-with-your-key'
export SELLAPP_STORE='launch-lab'
export SELLAPP_API_BASE_URL='https://sell.app/api'

For launch-lab.sell.app, the store slug is launch-lab. In PowerShell, set these with $env:SELLAPP_API_KEY = 'replace-with-your-key', $env:SELLAPP_STORE = 'launch-lab', and $env:SELLAPP_API_BASE_URL = 'https://sell.app/api' instead.

Replace src/main.rs with this complete program, then run cargo run from your application directory:

use sellapp::{Client, Error};use sellapp::resources::products::ListParams;pub async fn first_request(client: &Client) -> Result<Vec<(i64, String)>, Error> {    let page = client.products().list(ListParams {        limit: Some(1),        ..Default::default()    }).await?;    let products: Vec<_> = page.data.into_iter().map(|p| (p.id, p.title)).collect();    for (id, title) in &products {        println!("{id}: {title}");    }    if products.is_empty() {        println!("No products yet. Your connection is ready.");    }    Ok(products)}#[tokio::main]async fn main() -> Result<(), Box<dyn std::error::Error>> {    // Require a deliberate destination for this runnable example.    let base_url = std::env::var("SELLAPP_API_BASE_URL")?;    let client = Client::from_env()?.with_base_url(base_url).with_max_retries(0);    first_request(&client).await?;    Ok(())}

The program prints the product's ID and title. If your store has no products, No products yet. Your connection is ready. confirms the request succeeded. Products are in page.data. Client::from_env() reads your API key and store; the example passes SELLAPP_API_BASE_URL explicitly and disables retries.

.await waits for the response, and ? returns a failure to the caller. The error example shows how to inspect typed failures and request IDs.

If the request fails, check your key for 401. For 403, check its listing ability, allowed stores, and your current store permissions. For 404, check the store slug. Follow the response's retry guidance for 429. Keep any request ID when asking for help, and never share your API key. See errors.

Next, use the method reference to find an operation, or read the pagination and configuration guide.

Elixir

Use Elixir structs and explicit success or error results in your server-side application.

Install Elixir

These instructions use Elixir 1.20.4 with Erlang/OTP 28.4 and Mix, Elixir's build tool.

In an existing Mix application, add the SDK to the deps/0 list in mix.exs:

defp deps do
  [
    {:sellapp, "~> 0.1.1"}
  ]
end

Keep your application's existing dependencies in that list. Run mix deps.get to download the SDK from Hex.

For a new application, run these commands first, then add the dependency above:

mix new sellapp_example
cd sellapp_example

Read your first product with Elixir

This request reads at most one product. It does not create data or charge anyone. Create a server-side key in API keys. Enable its listing ability and allow access to the store you want to read. Keep the key on your server and out of source control. See authentication for setup and permissions.

In a Bash-compatible terminal, replace the key and store slug:

export SELLAPP_API_KEY='replace-with-your-key'
export SELLAPP_STORE='launch-lab'
export SELLAPP_API_BASE_URL='https://sell.app/api'

For launch-lab.sell.app, the store slug is launch-lab. In PowerShell, set these with $env:SELLAPP_API_KEY = 'replace-with-your-key', $env:SELLAPP_STORE = 'launch-lab', and $env:SELLAPP_API_BASE_URL = 'https://sell.app/api' instead.

Save this complete program as first-request.exs in your application directory, then run mix run first-request.exs:

base_url = System.fetch_env!("SELLAPP_API_BASE_URL")if base_url == "", do: raise("Set SELLAPP_API_BASE_URL before running this example")client = SellApp.client(base_url: base_url)# Credentials come from SELLAPP_API_KEY and SELLAPP_STORE.{:ok, page} = SellApp.Products.list(client, %{limit: 1})Enum.each(page.data, fn product -> IO.puts("#{product.id} #{product.title}") end)if page.data == [], do: IO.puts("No products yet. The request worked!")

The program prints the product's ID and title. If your store has no products, No products yet. The request worked! confirms the request succeeded. SellApp.client/1 reads your API key and store from the environment; the example passes SELLAPP_API_BASE_URL explicitly.

The {:ok, page} match unwraps a successful response, and page.data is the list of product structs. This first program stops if the request fails. The error example uses case to handle {:error, error} results.

If the request fails, check your key for 401. For 403, check its listing ability, allowed stores, and your current store permissions. For 404, check the store slug. Follow the response's retry guidance for 429. Keep any request ID when asking for help, and never share your API key. See errors.

Next, use the HexDocs reference or the method reference to find an operation, or read the pagination and configuration guide.

Community SDKs & extensions

Before choosing a community package, check which API versions and endpoints it supports, how it sends X-STORE, and how it handles errors and retries. Compare its requests with this reference; a convenient wrapper may not cover every endpoint.

Note

These community packages are not officially endorsed. Review their maintenance status and compatibility before adding one to your project. Never expose a secret API key in a browser-based integration.


Embedding SellApp products

SellApp offers an official embed solution that lets you place product purchase flows directly on your own website. Once embedded, customers can complete purchases without being redirected to your storefront.

For setup instructions, see the Embedding products guide in the main help documentation.

On this page