Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 37 additions & 4 deletions docs/docs/developers/sdk/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,45 @@ Otherwise, include the SDK script tag in your web page. The Audius SDK will then

## Initialize the SDK

Initialize the SDK with your API key.
Initialize the SDK with a bearer token (recommended) or with API key and secret.

If you plan to write data to Audius (e.g. upload a track, favorite a playlist, etc.), then pass in
your API secret as well.
### Option 1: API Key + Bearer Token (Recommended)

### Node.js example
When you have a bearer token from a developer app access key, you can initialize with `bearerToken`
and `apiKey`. Works for reads plus write
operations that accept Bearer auth (e.g. favorites, reposts). OAuth is supported—pass `apiKey` (your
developer app address) and/or `appName` for Log in with Audius.

Obtain a bearer token via [audius.co/settings](https://audius.co/settings),
[api.audius.co/plans](https://api.audius.co/plans), or
[POST /developer-apps/{address}/access-keys](https://docs.audius.co/api/create-developer-app-access-key.api)
after creating a developer app. See the
[Create Developer App Access Key](/developers/api/create-developer-app-access-key.api) API for
details.

```js
import { sdk } from '@audius/sdk'

const audiusSdk = sdk({
apiKey: 'your-api-key',
bearerToken: 'your-bearer-token',
})

const track = await audiusSdk.tracks.getTrack({ trackId: 'D7KyD' })
await audiusSdk.tracks.favoriteTrack({ trackId: 'D7KyD', userId })
```

:::note

Bearer token auth excludes: entity manager (on-chain writes), track/playlist upload flows, chats,
grants, and albums. Use the SDK with `apiKey` and `apiSecret` (Option 2) when you need those features.

:::

### Option 2: API Key + Secret

If you plan to write data to Audius (e.g. upload a track, favorite a playlist, etc.), use your API
key and API secret.

```js title="In Node.js environment"
import { sdk } from '@audius/sdk'
Expand Down
8 changes: 5 additions & 3 deletions packages/sdk/src/sdk/scripts/manageRewardsLookupTable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import untildify from 'untildify'
import { developmentConfig } from '../config/development'
import { productionConfig } from '../config/production'
import type { SdkServicesConfig } from '../config/types'
import { sdk as audiusSdk } from '../sdk'
import { sdk as audiusSdk, type AudiusSdkWithSecret } from '../sdk'
import { Logger } from '../services'
import type { SdkConfig } from '../types'

Expand Down Expand Up @@ -162,11 +162,12 @@ const createLookupTable = async ({
)
const sdk = audiusSdk({
appName: 'generate-rewards-lookup-table',
apiKey: '0x0000000000000000000000000000000000000000',
environment,
services: {
logger: new Logger()
}
})
}) as AudiusSdkWithSecret
const config = getConfig(environment)
const connection = sdk.services.solanaClient.connection

Expand Down Expand Up @@ -280,11 +281,12 @@ const updateLookupTable = async ({
)
const sdk = audiusSdk({
appName: 'generate-rewards-lookup-table',
apiKey: '0x0000000000000000000000000000000000000000',
environment,
services: {
logger: new Logger()
}
})
}) as AudiusSdkWithSecret
const config = getConfig(environment)
const connection = sdk.services.solanaClient.connection

Expand Down
9 changes: 7 additions & 2 deletions packages/sdk/src/sdk/scripts/verifyUser.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { program } from 'commander'
import { privateKeyToAccount } from 'viem/accounts'

import { sdk as audiusSdk } from '../sdk'
import { sdk as audiusSdk, type AudiusSdkWithSecret } from '../sdk'
import { EntityManagerAction, EntityType } from '../services'
import { HashId } from '../types/HashId'

Expand Down Expand Up @@ -37,11 +38,15 @@ program
process.exit(1)
}

const account = privateKeyToAccount(
`0x${args.privateKey.replace(/^0x/, '')}` as `0x${string}`
)
const sdk = audiusSdk({
appName: 'verify-user',
apiKey: account.address,
apiSecret: args.privateKey,
environment: args.environment
})
}) as AudiusSdkWithSecret

try {
const user = await sdk.users.getUserByHandle({ handle: args.handle })
Expand Down
94 changes: 93 additions & 1 deletion packages/sdk/src/sdk/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,20 @@ import { EventsApi } from './api/events/EventsApi'
import {
ChallengesApi,
CoinsApi,
CommentsApi as GeneratedCommentsApi,
Configuration,
DashboardWalletUsersApi as GeneratedDashboardWalletUsersApi,
DeveloperAppsApi as GeneratedDeveloperAppsApi,
EventsApi as GeneratedEventsApi,
ExploreApi,
NotificationsApi as GeneratedNotificationsApi,
PlaylistsApi as GeneratedPlaylistsApi,
PrizesApi,
RewardsApi,
SearchApi,
TipsApi,
TracksApi as GeneratedTracksApi,
UsersApi as GeneratedUsersApi,
WalletApi
} from './api/generated/default'
import { GrantsApi } from './api/grants/GrantsApi'
Expand Down Expand Up @@ -90,10 +98,93 @@ import { SdkConfig, SdkConfigSchema, ServicesContainer } from './types'
import fetch from './utils/fetch'

/**
* The Audius SDK
* The Audius SDK. Bearer token auth is recommended.
*/
export const sdk = (config: SdkConfig) => {
SdkConfigSchema.parse(config)

const hasBearerToken =
typeof config.bearerToken === 'string' && config.bearerToken.length > 0

if (hasBearerToken) {
return initializeSdkWithBearerToken(config)
}
return initializeSdkFull(config)
}

const initializeSdkWithBearerToken = (config: SdkConfig) => {
const apiEndpoint =
config.environment === 'development'
? developmentConfig.network.apiEndpoint
: productionConfig.network.apiEndpoint
const basePath = `${apiEndpoint}/v1`

const defaultLogger = new Logger({
logLevel: config.environment !== 'production' ? 'debug' : undefined
})
const logger = config.services?.logger ?? defaultLogger

const apiClientConfig = new Configuration({
fetchApi: fetch,
accessToken: config.bearerToken,
basePath
})

const tracks = new GeneratedTracksApi(apiClientConfig)
const users = new GeneratedUsersApi(apiClientConfig)
const playlists = new GeneratedPlaylistsApi(apiClientConfig)
const comments = new GeneratedCommentsApi(apiClientConfig)
const tips = new TipsApi(apiClientConfig)
const developerApps = new GeneratedDeveloperAppsApi(apiClientConfig)
const dashboardWalletUsers = new GeneratedDashboardWalletUsersApi(
apiClientConfig
)
const rewards = new RewardsApi(apiClientConfig)
const notifications = new GeneratedNotificationsApi(apiClientConfig)
const events = new GeneratedEventsApi(apiClientConfig)
const explore = new ExploreApi(apiClientConfig)
const search = new SearchApi(apiClientConfig)
const coins = new CoinsApi(apiClientConfig)
const wallets = new WalletApi(apiClientConfig)
const challenges = new ChallengesApi(apiClientConfig)
const prizes = new PrizesApi(apiClientConfig)

const resolveApi = new ResolveApi(apiClientConfig)
const resolve = resolveApi.resolve.bind(resolveApi)

const oauth =
typeof window !== 'undefined'
? new OAuth({
appName: config.appName,
apiKey: config.apiKey,
usersApi: users,
logger
})
: undefined

return {
oauth,
tracks,
users,
playlists,
tips,
resolve,
developerApps,
dashboardWalletUsers,
rewards,
comments,
notifications,
events,
explore,
search,
coins,
wallets,
challenges,
prizes
}
}

const initializeSdkFull = (config: SdkConfig) => {
const { appName, apiKey } = config

// Initialize services
Expand Down Expand Up @@ -537,3 +628,4 @@ const initializeApis = ({
}

export type AudiusSdk = ReturnType<typeof sdk>
export type AudiusSdkWithSecret = ReturnType<typeof initializeSdkFull>
121 changes: 73 additions & 48 deletions packages/sdk/src/sdk/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,56 +168,81 @@ export type ServicesContainer = {
archiverService?: ArchiverService
}

const credentialRefine = (data: {
apiKey?: string
apiSecret?: string
bearerToken?: string
}) =>
(data.bearerToken?.length ?? 0) > 0 ||
(data.apiKey?.length ?? 0) > 0 ||
(data.apiSecret?.length ?? 0) > 0

/**
* SDK configuration schema that requires API keypairs
* SDK configuration schema. Either apiKey or bearerToken must be provided.
*/
const DevAppSchema = z.object({
/**
* Your app name
*/
appName: z.optional(z.string()),
/**
* Services injection
*/
services: z.optional(z.custom<Partial<ServicesContainer>>()),
/**
* API key, required for writes
*/
apiKey: z.string().min(1),
/**
* API secret, required for writes
*/
apiSecret: z.optional(z.string().min(1)),
/**
* Target environment
* @internal
*/
environment: z.enum(['development', 'production']).optional()
})

const CustomAppSchema = z.object({
/**
* Your app name
*/
appName: z.string().min(1),
/**
* Services injection
*/
services: z.optional(z.custom<Partial<ServicesContainer>>()),
/**
* API key, required for writes
*/
apiKey: z.optional(z.string().min(1)),
/**
* API secret, required for writes
*/
apiSecret: z.optional(z.string().min(1)),
/**
* Target environment
* @internal
*/
environment: z.enum(['development', 'production']).optional()
})
const DevAppSchema = z
.object({
/**
* Your app name
*/
appName: z.optional(z.string()),
/**
* Services injection
*/
services: z.optional(z.custom<Partial<ServicesContainer>>()),
/**
* API key, required when bearerToken is not set
*/
apiKey: z.string().min(1).optional(),
/**
* API secret, required for writes (full SDK only)
*/
apiSecret: z.optional(z.string().min(1)),
/**
* Bearer token auth is recommended.
*/
bearerToken: z.optional(z.string().min(1)),
/**
* Target environment
* @internal
*/
environment: z.enum(['development', 'production']).optional()
})
.refine(credentialRefine, {
message: 'Either apiKey, apiSecret, or bearerToken must be provided'
})

const CustomAppSchema = z
.object({
/**
* Your app name
*/
appName: z.string().min(1),
/**
* Services injection
*/
services: z.optional(z.custom<Partial<ServicesContainer>>()),
/**
* API key, required when bearerToken is not set
*/
apiKey: z.optional(z.string().min(1)),
/**
* API secret, required for writes (full SDK only)
*/
apiSecret: z.optional(z.string().min(1)),
/**
* Bearer token auth is recommended.
*/
bearerToken: z.optional(z.string().min(1)),
/**
* Target environment
* @internal
*/
environment: z.enum(['development', 'production']).optional()
})
.refine(credentialRefine, {
message: 'Either apiKey, apiSecret, or bearerToken must be provided'
})

export const SdkConfigSchema = z.union([DevAppSchema, CustomAppSchema])

Expand Down
10 changes: 5 additions & 5 deletions packages/web/public/skill.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,16 +93,16 @@ SDK is assigned to `window.audiusSdk` when using the CDN.
## Initialize SDK

```js
import { sdk } from '@audius/sdk'

const audiusSdk = sdk({
apiKey: 'Your API Key goes here',
apiSecret: 'Your API Secret goes here' // Required for writes; omit for frontend
apiKey: 'your-api-key',
bearerToken: 'your-bearer-token',
environment: 'production'
})
```

- **Bearer tokens**: From `POST /developer-apps/{address}/access-keys`. Supports reads + Bearer-authenticated writes (favorites, reposts, etc.). OAuth supported (pass apiKey/appName). Excludes entity manager, uploads.
- **Read-only**: Use `apiKey` only. Safe for frontend.
- **Writes** (upload, favorite, repost): Add `apiSecret`. Use only on the server—never in browser.
- **Writes** (upload, favorite, repost): Add `bearerToken` (recommended), or use `apiSecret` for access-key auth.

## First API Calls

Expand Down
Loading