Documentation Index Fetch the complete documentation index at: https://docs.launchmystore.io/llms.txt
Use this file to discover all available pages before exploring further.
API Authentication
The LaunchMyStore API uses OAuth 2.0 for authentication. This page covers the authentication methods available and how to use them in your API requests.
Authentication Methods
Access Tokens OAuth 2.0 access tokens for server-to-server API calls
Session Tokens JWTs for embedded app API calls
Access Tokens
Access tokens are obtained through the OAuth 2.0 flow and used for server-to-server API calls.
Obtaining Access Tokens
Complete the OAuth authorization flow to get an access token:
// 1. Redirect merchant to authorization URL
const authUrl = new URL ( 'https://api.launchmystore.io/oauth/authorize' );
authUrl . searchParams . set ( 'client_id' , CLIENT_ID );
authUrl . searchParams . set ( 'scope' , 'read_products,write_products,read_orders' );
authUrl . searchParams . set ( 'redirect_uri' , 'https://your-app.com/callback' );
authUrl . searchParams . set ( 'state' , generateRandomState ());
res . redirect ( authUrl . toString ());
// 2. Exchange authorization code for tokens
const tokenResponse = await fetch ( 'https://api.launchmystore.io/oauth/token' , {
method: 'POST' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({
client_id: CLIENT_ID ,
client_secret: CLIENT_SECRET ,
code: authorizationCode ,
grant_type: 'authorization_code' ,
redirect_uri: 'https://your-app.com/callback'
})
});
const { access_token , refresh_token , expires_in } = await tokenResponse . json ();
Using Access Tokens
Include the access token in the Authorization header:
curl -X GET "https://api.launchmystore.io/api/v1/products" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json"
const response = await fetch ( 'https://api.launchmystore.io/api/v1/products' , {
headers: {
'Authorization' : `Bearer ${ accessToken } ` ,
'Content-Type' : 'application/json'
}
});
Token Expiration
Access tokens expire after 24 hours . Use the refresh token to get a new access token:
async function refreshAccessToken ( refreshToken ) {
const response = await fetch ( 'https://api.launchmystore.io/oauth/token' , {
method: 'POST' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({
client_id: CLIENT_ID ,
client_secret: CLIENT_SECRET ,
refresh_token: refreshToken ,
grant_type: 'refresh_token'
})
});
const data = await response . json ();
// Store new tokens
await storeTokens ( data . access_token , data . refresh_token );
return data . access_token ;
}
Refresh tokens expire after 30 days . If a refresh token expires, the merchant must re-authorize your app.
Token Management
Implement a token manager for automatic refresh:
class TokenManager {
constructor ( shopId ) {
this . shopId = shopId ;
}
async getAccessToken () {
const tokens = await this . loadTokens ();
// Check if access token is expired (with 5 min buffer)
if ( tokens . expiresAt < Date . now () + 300000 ) {
return this . refreshToken ( tokens . refreshToken );
}
return tokens . accessToken ;
}
async refreshToken ( refreshToken ) {
try {
const response = await fetch ( 'https://api.launchmystore.io/oauth/token' , {
method: 'POST' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({
client_id: process . env . APP_CLIENT_ID ,
client_secret: process . env . APP_CLIENT_SECRET ,
refresh_token: refreshToken ,
grant_type: 'refresh_token'
})
});
if ( ! response . ok ) {
throw new Error ( 'Token refresh failed' );
}
const data = await response . json ();
await this . storeTokens ({
accessToken: data . access_token ,
refreshToken: data . refresh_token ,
expiresAt: Date . now () + ( data . expires_in * 1000 )
});
return data . access_token ;
} catch ( error ) {
// Refresh token may be expired - need re-authorization
await this . markNeedsReauth ();
throw error ;
}
}
async loadTokens () {
// Load from database
return db . tokens . findOne ({ shopId: this . shopId });
}
async storeTokens ( tokens ) {
await db . tokens . updateOne (
{ shopId: this . shopId },
{ $set: tokens },
{ upsert: true }
);
}
async markNeedsReauth () {
await db . shops . updateOne (
{ id: this . shopId },
{ $set: { needsReauth: true } }
);
}
}
Session Tokens
Session tokens are JWTs used for embedded app API calls. They’re obtained through App Bridge.
Getting Session Tokens
import { createApp } from '@launchmystore/app-bridge' ;
const app = createApp ({
apiKey: 'your-client-id' ,
host: new URLSearchParams ( location . search ). get ( 'host' )
});
const token = await app . getSessionToken ();
Using Session Tokens
Include in the Authorization header:
const token = await app . getSessionToken ();
const response = await fetch ( 'https://your-app.com/api/data' , {
headers: {
'Authorization' : `Bearer ${ token } `
}
});
Verifying Session Tokens
Verify session tokens on your backend:
import jwt from 'jsonwebtoken' ;
function verifySessionToken ( token ) {
try {
const decoded = jwt . verify ( token , process . env . APP_CLIENT_SECRET , {
algorithms: [ 'HS256' ],
audience: process . env . APP_CLIENT_ID ,
issuer: 'launchmystore'
});
return {
valid: true ,
shopId: decoded . sub ,
shopDomain: decoded . dest
};
} catch ( error ) {
return { valid: false , error: error . message };
}
}
See Session Tokens for detailed documentation.
Scopes
Request only the scopes your app needs:
Store Data Scopes
Scope Access read_shopView store information write_shopModify store settings read_productsView products and variants write_productsCreate, update, delete products read_collectionsView collections write_collectionsManage collections read_inventoryView inventory levels write_inventoryAdjust inventory
Order Scopes
Scope Access read_ordersView orders and transactions write_ordersCreate, update, fulfill orders read_fulfillmentsView fulfillment data write_fulfillmentsCreate, update fulfillments read_draft_ordersView draft orders write_draft_ordersManage draft orders
Customer Scopes
Scope Access read_customersView customer data write_customersCreate, update customers read_customer_groupsView customer groups write_customer_groupsManage customer groups
Content Scopes
Scope Access read_contentView pages, blogs, articles write_contentManage pages, blogs, articles read_themesView theme files write_themesModify theme files read_metafieldsView metafield data write_metafieldsCreate, update metafields
Admin Scopes
Scope Access read_discountsView discount codes write_discountsManage discounts read_analyticsView store analytics read_gift_cardsView gift cards write_gift_cardsManage gift cards read_shippingView shipping settings write_shippingManage shipping settings
Rate Limits
API requests are rate limited based on your app’s billing tier:
Tier Requests/Second Burst Free 20 40 Basic 40 80 Pro 100 200 Enterprise 500 1000
Every response includes rate limit information:
X-RateLimit-Limit : 40
X-RateLimit-Remaining : 38
X-RateLimit-Reset : 1705312800
Handling Rate Limits
async function apiCall ( url , options , retries = 3 ) {
const response = await fetch ( url , options );
if ( response . status === 429 ) {
if ( retries > 0 ) {
const resetTime = response . headers . get ( 'X-RateLimit-Reset' );
const waitMs = ( resetTime * 1000 ) - Date . now () + 100 ;
await sleep ( Math . min ( waitMs , 60000 ));
return apiCall ( url , options , retries - 1 );
}
throw new Error ( 'Rate limit exceeded' );
}
return response ;
}
Error Responses
Authentication Errors
Status Code Description 401 UNAUTHORIZEDMissing or invalid token 401 TOKEN_EXPIREDAccess token has expired 403 FORBIDDENInsufficient scopes 403 APP_UNINSTALLEDApp has been uninstalled
{
"success" : false ,
"error" : {
"code" : "UNAUTHORIZED" ,
"message" : "Invalid or expired access token" ,
"details" : {
"reason" : "token_expired"
}
}
}
Handling Errors
async function makeApiRequest ( endpoint , options = {}) {
const response = await fetch (
`https://api.launchmystore.io/api/v1 ${ endpoint } ` ,
{
... options ,
headers: {
... options . headers ,
'Authorization' : `Bearer ${ await tokenManager . getAccessToken () } ` ,
'Content-Type' : 'application/json'
}
}
);
if ( ! response . ok ) {
const error = await response . json ();
switch ( error . error . code ) {
case 'UNAUTHORIZED' :
case 'TOKEN_EXPIRED' :
// Try to refresh token
await tokenManager . refreshToken ();
return makeApiRequest ( endpoint , options );
case 'FORBIDDEN' :
throw new Error ( 'Insufficient permissions' );
case 'APP_UNINSTALLED' :
await handleAppUninstalled ();
throw new Error ( 'App has been uninstalled' );
default :
throw new Error ( error . error . message );
}
}
return response . json ();
}
Security Best Practices
Never include your client secret in client-side code. Keep it on your backend only.
Always use HTTPS for API calls and webhook endpoints.
Validate the state parameter
Always validate the state parameter in OAuth callbacks to prevent CSRF attacks.
Encrypt access and refresh tokens in your database. Never log them.
Only request the scopes your app actually needs. Merchants trust apps with fewer permissions.
Tokens can be revoked if a merchant uninstalls your app. Handle this gracefully.
Testing Authentication
Test Mode
Use test credentials for development:
const config = {
clientId: process . env . NODE_ENV === 'production'
? process . env . APP_CLIENT_ID
: process . env . APP_TEST_CLIENT_ID ,
clientSecret: process . env . NODE_ENV === 'production'
? process . env . APP_CLIENT_SECRET
: process . env . APP_TEST_CLIENT_SECRET
};
Mock Tokens
For unit testing, create mock tokens:
import jwt from 'jsonwebtoken' ;
function createMockSessionToken ( payload = {}) {
return jwt . sign (
{
iss: 'launchmystore' ,
aud: 'test-client-id' ,
sub: 'test-shop-id' ,
dest: 'https://test-store.launchmystore.io' ,
exp: Math . floor ( Date . now () / 1000 ) + 3600 ,
iat: Math . floor ( Date . now () / 1000 ),
... payload
},
'test-client-secret' ,
{ algorithm: 'HS256' }
);
}
See Also