NorthlightSDK
Concepts

Providers

A provider is a service the person's runtime calls for your app. Provider scopes, providers.tools, providers.call, and apps that require a provider.

A provider is a service that a person's runtime calls on your app's behalf: sending a text, searching the web, reading their connected accounts, or using their device. Northlight runs the first-party providers (sms, search, integrations, context and device). Your server asks the person's runtime to call one with providers.call.

Scopes

Each provider's tools are grouped, and each group is a scope named <provider>:<group>. The sms provider has one: sms:send. Your app can call a provider only if all three of these hold:

  1. The scope is on the app's What it asks for list (console → Add permissions).
  2. Your sign-in requested it (authorizeUrl({scopes: […]})).
  3. The person approved it on the consent page.

Take scope strings from the Add permissions list. Do not guess them. Providers lists the first-party providers.

Find the tools, then call one

providers.tools('<provider>') lists the tools the person has granted your app, with their descriptions and parameters. Tool names and arguments come from there, never from memory:

import type {ConnectedCrouter} from '@north-light/sdk';

/** List the tools a provider offers this person, then call one. Scope strings come from the console's
 *  "Add permissions" list; tool names and arguments come from `providers.tools`. Never invent either. */
export async function textMe(runtime: ConnectedCrouter, body: string) {
  const sms = await runtime.providers.tools('sms');
  console.log(JSON.stringify(sms.groups, null, 2)); // each leaf: tool, description, params

  return runtime.providers.call({provider: 'sms', tool: 'send', arguments: {body}});
}

providers.call({provider, tool, arguments}) makes the call and returns the tool's output. The quickstart sends a text this way:

// Texts the signed-in person's own verified phone through the sms provider (50 per person per UTC day).
const sent = await runtime.providers.call({provider: 'sms', tool: 'send', arguments: {body: 'Hello from my first Northlight app.'}});

send takes a required body and an optional file. It has no recipient argument: it texts the verified phone of the person who signed in to your app, from Northlight's number, at most 50 texts per person per UTC day. Calling providers.tools() with no provider lists every provider the person's runtime can reach.

A call is refused when the scope is missing from the grant. The refusal is an APIError whose code says why (scope_missing for a scope the run or grant lacks).

Providers your app requires

Some apps do not work until a provider is set up for the person. Name it under What your app requires on the What it asks for tab. The person is then taken through that provider's setup the first time they sign in. Context, for example, asks for a profile URL, and its state stays pending for a few minutes afterwards.

Read the state on each request that depends on it. runtime.grant.get() returns dependencies, one entry per required provider, keyed by provider id (or {} when the app requires none):

const {dependencies} = await runtime.grant.get();
const context = dependencies['context']; // {state, message?, next} or undefined
if (context?.state !== 'ready') {
  // Show context.message and link context.next; never hard-code either.
}
stateMeaning
not_startedThe person has not done their part.
pendingThe provider is working.
readyCalls that depend on it work.
failedSetup failed. message says why.

message is the provider's own sentence, present for pending and failed. next is the absolute URL of the setup page for this provider and your app; add a return_to query parameter with your app's registered origin so the person returns to you. An entry is missing when the runtime has not synced the grant since the app began requiring the provider: treat that as not_started. The runtime does not block your calls for you, so refuse the dependent operation yourself. To act the moment a state turns ready, follow it with oauth.watchGrants; see Grant changes.

Checked and not checked

From the SDK source (providers.tools, providers.call, grant.get) and the directory source. The sms limits come from the existing SDK guide. A real providers.call for sms on production is not yet checked.

On this page