Set up your account, test mode and an API key

An account, a wallet that accepts a token, a test key, and a client that proves it works.

Subscriptions are paid in tokens: your wallet must accept at least one, not only a chain's native coin (each chain's tokens), or a subscription checkout answers 409 merchant_not_ready.

Create your account

Sign up. Your account comes with an organization: where your products, payments, keys and webhook endpoints live. Nothing to deposit: payments go wallet to wallet (how the money moves).

Switch to test mode

Pick Test in the dashboard's mode switch. Test mode has its own networks, faucet tokens, keys, wallets, products and endpoints, and a test checkout is at most $5, fees included (test mode). Nothing carries over to live: the guide's last step redoes what matters.

Add a wallet

In Dashboard/Settings/Wallets, add a wallet you own and choose the currencies it accepts. Payments land there.

Watch out

Add it before your first checkout. A space (your organization's data in one mode: spaces) whose wallets accept nothing can't open one: the API answers 409 merchant_not_ready.

Create an API key

In Dashboard/Settings/API keys, choose Create an API key. It's shown once: store it as QBITFLOW_API_KEY, which every example reads. A test key (sk_test_…) only ever sees test data.

It acts as an admin of your organization: keep it on your server, in an environment variable, never in a browser, an app or a repository. Leaked? Revoke it on the same page: it stops working at once.

Install the SDK

Install the SDK

terminal

# Nothing to install: cURL comes with macOS, Linux and Windows.curl --version
Every request takes your key from QBITFLOW_API_KEY
npm install qbitflow
qbitflow-js-sdk 3.1.1 · Requires Node.js 20 or later.
pip install "qbitflow>=3,<4"
qbitflow-python-sdk 3.1.1 · Requires Python 3.10 or later.
go get github.com/QBitFlow/qbitflow-go-sdk/v3
qbitflow-go-sdk 3.1.1 · Requires Go 1.27 or later.
composer require qbitflow/qbitflow-php:^3.0
qbitflow-php-sdk 3.1.1 · Requires PHP 8.2.35, 8.3.36, 8.4.27, 8.5.12 or later in its branch.

Create a client

One client per key, shared by your whole program. Its first call asks what the key is: a good start-up check.

Create a client

client-init.sh

# Every request sends your API key. The start-up check: what is this key, and which mode is it in?curl https://api.qbitflow.app/v2/me \  -H "X-API-Key: $QBITFLOW_API_KEY"# 200: { "credential": "apiKey", "role": "admin", "space": { "test": true, … }, … }
// One client per API key, shared by the whole program. A blank key, one not starting with// sk_, or one with a space or a control character, throws a ValidationError (nothing is sent).const client = new QBitFlow(process.env.QBITFLOW_API_KEY ?? ''); // The recommended start-up check: what is this key, and which mode is it in? An// AuthenticationError for an unknown or revoked key.const me = await client.me();console.log(`${me.role} key, test mode: ${me.space?.test}`);
# One client per API key, shared by the whole program. ValidationError: not an sk_… key.client = qbitflow.QBitFlow(os.environ["QBITFLOW_API_KEY"]) # The recommended start-up check: what is this key, and which mode is it in?me = client.me()  # AuthenticationError for an unknown or revoked keyif me.space is not None:    print(f"{me.space.organization_name}, role {me.role}, test mode {me.space.test}")
// One client per API key, shared by the whole program: it is safe for concurrent use.client, err := qbitflow.NewClient(os.Getenv("QBITFLOW_API_KEY"))if err != nil {	log.Fatal(err) // a *qbitflow.ValidationError: no key, or not an sk_… key} // The recommended start-up check: what is this key, and which mode is it in?me, err := client.Me(ctx)if err != nil {	log.Fatal(err) // a *qbitflow.AuthenticationError for an unknown or revoked key}if me.Space != nil {	fmt.Printf("%s, role %s, test mode %v\n", me.Space.OrganizationName, me.Role, me.Space.Test)}
// One client per API key, shared by the whole application.$client = new \QBitFlow\QBitFlow(apiKey: (string) getenv('QBITFLOW_API_KEY')); // The recommended start-up check: which space and mode is this key in?$me = $client->me(); // an AuthenticationException for an unknown or revoked keyprintf("%s, role %s, %s mode\n", $me->space?->organizationName ?? '?', $me->role ?? '?', $me->space?->test ? 'test' : 'live');

Or read everything from the environment

The SDKs can build the client from QBITFLOW_API_KEY alone, plus the optional settings each one names below. Explicit options win.

Configure from the environment
// QBITFLOW_API_KEY (required), and QBITFLOW_BASE_URL and QBITFLOW_ON_BEHALF_OF when set.const client = QBitFlow.fromEnv(); // Explicit options override the environment and add the others.const patient = QBitFlow.fromEnv({ timeout: 60_000, maxRetries: 5 });
# QBITFLOW_API_KEY (required), QBITFLOW_BASE_URL and QBITFLOW_ON_BEHALF_OF when set.client = qbitflow.QBitFlow.from_env(timeout=10)  # explicit options override the environment
// QBITFLOW_API_KEY (required), QBITFLOW_BASE_URL and QBITFLOW_ON_BEHALF_OF (when set);// the options given here override them.client, err := qbitflow.NewClientFromEnv(qbitflow.WithTimeout(10 * time.Second))if err != nil {	log.Fatal(err) // a *qbitflow.ValidationError naming QBITFLOW_API_KEY when it is not set}
// QBITFLOW_API_KEY (required), and QBITFLOW_BASE_URL and QBITFLOW_ON_BEHALF_OF when set, read from// getenv(), $_ENV or $_SERVER (a .env loaded by phpdotenv works).$client = \QBitFlow\QBitFlow::fromEnv(); // Named arguments override the environment and set the other options.$client = \QBitFlow\QBitFlow::fromEnv(timeout: 10.0, maxRetries: 5);

Check it

The client's first call prints the key's role (admin for an organization key) and test mode (space.test is true). A 401 (AuthenticationError) means a mistyped, revoked or expired key.