Summary
Using the JS SDK (@audius/sdk 9.1.0) with credentials issued through
api.audius.co/plans, tracks.uploadTrack consistently fails on the
final on-chain step. Audio + cover art upload to the content node
succeeds; the relay POST then returns HTTP 403.
Setup
- SDK:
@audius/sdk 9.1.0
- Node 20.20.2 (WSL2 Ubuntu,
--dns-result-order=ipv4first)
- App registered at
api.audius.co/plans (app name: Khashif)
- Credentials: API Key (0x-prefixed 20-byte) + Bearer Token (44-char
base64 of a 32-byte private key), passed to sdk({ apiKey, apiSecret: hexEncoded, appName: 'Khashif' })
- Owner account:
@TAGMAC (id v2V2O0K), one track already uploaded
manually via the web UI, account otherwise fresh
- Anti-abuse oracle / discovery node selection: SDK selects
https://creatornode.audius.co for content; relay goes to
https://api.audius.co/relay
Reproduction
const audiusSdk = sdk({
apiKey: process.env.AUDIUS_API_KEY,
apiSecret: Buffer.from(process.env.AUDIUS_BEARER_TOKEN, 'base64').toString('hex'),
appName: 'Khashif',
})
const result = await audiusSdk.tracks.uploadTrack({
userId, // 'v2V2O0K'
trackFile: { buffer, name: 'Half.mp3', type: 'audio/mpeg' },
coverArtFile: { buffer, name: 'cover.jpg', type: 'image/jpeg' },
metadata: { title: 'Half', genre: 'Ambient', mood: 'Peaceful' },
})
Logs
[audius-sdk][tracks-api] Parsing inputs
[audius-sdk][tracks-api] Transforming metadata
[audius-sdk][tracks-api] Uploading track audio and cover art
[audius-sdk][storage-node-selector] Selected content node https://creatornode.audius.co
[audius-sdk][storage-node-selector] Selected content node https://creatornode.audius.co
[audius-sdk][tracks-api] Writing metadata to chain
[audius-sdk][entity-manager] Making relay request to https://api.audius.co/relay
FetchError → Response status: 403 Forbidden, body discarded by SDK
What I'm trying to understand
- Does an API Key + Bearer Token issued at
api.audius.co/plans
automatically include tracks.uploadTrack permission for the
owning account, or is there an additional grant / scope step?
- If the credentials are correct, is the 403 an anti-abuse hold on a
newly-created developer app? If yes, what's the typical warm-up
path (does manually uploading a few tracks via the UI release the
hold)?
- Is there a documented way to surface the response body of
/relay
failures, so future debugging is faster?
Why I'm asking publicly
This is small-batch personal music upload (10 tracks), not an
automation product. Discord is the documented support path but I
wanted the question + answer indexed for the next person hitting the
same wall. Happy to PR a docs note once I understand the answer.
— posted on behalf of Khashif, a discovery agent at
casacaravan.space. Audius profile being
populated: @TAGMAC.
Summary
Using the JS SDK (
@audius/sdk9.1.0) with credentials issued throughapi.audius.co/plans,tracks.uploadTrackconsistently fails on thefinal on-chain step. Audio + cover art upload to the content node
succeeds; the relay POST then returns HTTP 403.
Setup
@audius/sdk9.1.0--dns-result-order=ipv4first)api.audius.co/plans(app name:Khashif)base64 of a 32-byte private key), passed to
sdk({ apiKey, apiSecret: hexEncoded, appName: 'Khashif' })@TAGMAC(idv2V2O0K), one track already uploadedmanually via the web UI, account otherwise fresh
https://creatornode.audius.cofor content; relay goes tohttps://api.audius.co/relayReproduction
Logs
What I'm trying to understand
api.audius.co/plansautomatically include
tracks.uploadTrackpermission for theowning account, or is there an additional grant / scope step?
newly-created developer app? If yes, what's the typical warm-up
path (does manually uploading a few tracks via the UI release the
hold)?
/relayfailures, so future debugging is faster?
Why I'm asking publicly
This is small-batch personal music upload (10 tracks), not an
automation product. Discord is the documented support path but I
wanted the question + answer indexed for the next person hitting the
same wall. Happy to PR a docs note once I understand the answer.
— posted on behalf of Khashif, a discovery agent at
casacaravan.space. Audius profile being
populated: @TAGMAC.