Skip to main content

Install flow (OAuth 2.1 + PKCE)

Salesive apps authorize with the OAuth 2.1 authorization code flow and PKCE is mandatory (S256). This page walks through the full handshake: redirecting the merchant to consent, receiving an authorization code, and exchanging it for tokens.

Endpoints

Salesive publishes an OAuth 2.1 discovery document. Fetch it once and read the endpoints from it rather than hardcoding paths:
curl https://api.salesive.com/.well-known/oauth-authorization-server
{
  "issuer": "https://api.salesive.com",
  "authorization_endpoint": "https://app.salesive.com/apps/authorize",
  "token_endpoint": "https://api.salesive.com/api/v1/oauth/token",
  "revocation_endpoint": "https://api.salesive.com/api/v1/oauth/revoke",
  "registration_endpoint": "https://api.salesive.com/api/v1/oauth/clients",
  "scopes_supported": ["READ_ORDERS", "WRITE_ORDERS", "..."],
  "code_challenge_methods_supported": ["S256"],
  "grant_types_supported": ["authorization_code", "refresh_token"]
}
The authorization_endpoint is on the Salesive dashboard host (app.salesive.com) — that’s where the merchant approves. The token_endpoint and all API calls are on the API host (api.salesive.com). Always read these from the discovery document rather than hardcoding.
EndpointPurpose
authorization_endpointWhere you send the merchant to approve the install (consent screen).
token_endpointPOST to exchange a code for tokens, or to refresh.
revocation_endpointPOST to revoke a token (RFC 7009).
You’ll need your client_id and client_secret from the Developer console (Apps → Developer). See Build & publish.

Prerequisites

  • A registered app with a client_id, client_secret, and at least one redirect URI.
  • A server endpoint that can receive the OAuth callback and hold the client_secret.
  • The scopes your app needs — see Scopes & permissions.

Step 1 · Generate a PKCE pair

For each install attempt, generate a random code_verifier and derive its code_challenge. Keep the verifier server-side (or in the session) — you’ll need it at token exchange.
import crypto from "crypto";

const base64url = (buf) =>
  buf.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");

// 43–128 chars
const codeVerifier = base64url(crypto.randomBytes(32));
const codeChallenge = base64url(
  crypto.createHash("sha256").update(codeVerifier).digest()
);
PKCE is required. Requests without a valid code_challenge (method S256) are rejected.
Send the merchant’s browser to the authorization_endpoint with your request parameters. The merchant — who is signed in to Salesive — sees a consent screen listing the scopes you requested and the store they’re installing on, then approves.
GET {authorization_endpoint}
  ?response_type=code
  &client_id=app_xxxxxxxxxxxxxxxx
  &redirect_uri=https://yourapp.com/oauth/callback
  &scope=READ_ORDERS%20WRITE_ORDERS%20READ_INVENTORY
  &code_challenge=<code_challenge>
  &code_challenge_method=S256
  &state=<opaque-random-state>
ParameterRequiredNotes
response_typeYesAlways code.
client_idYesYour app’s client id (app_…).
redirect_uriYesMust exactly match one of your registered redirect URIs.
scopeYesSpace-separated list of scopes. Request only what you need.
code_challengeYesThe PKCE challenge from Step 1.
code_challenge_methodYesMust be S256.
stateRecommendedOpaque value you generate; verify it on callback to prevent CSRF.
On approval, Salesive creates the installation on the merchant’s active store and redirects back to your redirect_uri with a code (and your state). On denial, it redirects with ?error=access_denied.
https://yourapp.com/oauth/callback?code=<authorization_code>&state=<your-state>

Step 3 · Exchange the code for tokens

From your server, POST to the token_endpoint. Send your client_secret and the PKCE code_verifier you stored in Step 1.
curl -X POST https://api.salesive.com/api/v1/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "authorization_code",
    "code": "<authorization_code>",
    "redirect_uri": "https://yourapp.com/oauth/callback",
    "code_verifier": "<code_verifier>",
    "client_id": "app_xxxxxxxxxxxxxxxx",
    "client_secret": "sk_xxxxxxxxxxxxxxxx"
  }'
{
  "access_token": "app_4f3c...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "app_rt_9a21...",
  "scope": "READ_ORDERS WRITE_ORDERS READ_INVENTORY"
}
Store the refresh_token securely (encrypted at rest), keyed to the merchant/store. The access_token is short-lived (one hour).
Client credentials may also be sent as HTTP Basic auth (Authorization: Basic base64(client_id:client_secret)) instead of in the body.

Step 4 · Call the API

Send the access token as a bearer token. You do not need to specify the store — the token is already bound to the store it was installed on.
curl https://api.salesive.com/api/v1/orders \
  -H "Authorization: Bearer app_4f3c..."
See Scopes & permissions for the full list of endpoints your app can reach and the scope each one requires.

Step 5 · Refresh the access token

When the access token expires, exchange your refresh token for a new pair. Refresh tokens rotate — the old refresh token is invalidated and you receive a new one, so always persist the latest.
curl -X POST https://api.salesive.com/api/v1/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "refresh_token",
    "refresh_token": "app_rt_9a21...",
    "client_id": "app_xxxxxxxxxxxxxxxx",
    "client_secret": "sk_xxxxxxxxxxxxxxxx"
  }'

Handling uninstalls & revocation

A merchant can uninstall your app at any time from Apps → Installed apps in their dashboard. When they do, the installation is deactivated and all of your app’s tokens for that store stop working immediately — even an access token that hasn’t expired yet. Treat a 401 Unauthorized with a message like “This app is no longer installed on the store” as an uninstall signal: stop calling the API for that store and clean up your stored tokens. You can also proactively revoke a token:
curl -X POST https://api.salesive.com/api/v1/oauth/revoke \
  -H "Content-Type: application/json" \
  -d '{ "token": "app_rt_9a21..." }'

Common errors

StatusMeaningFix
400 invalid_grantCode expired/used, or code_verifier doesn’t match.Restart the flow; codes are single-use and expire in 10 minutes.
400 redirect_uri_mismatchThe redirect_uri isn’t registered.Add the exact URI in the Developer console.
401 invalid_clientWrong client_id/client_secret.Check credentials; regenerate the secret if needed.
401 on an API callToken expired or app uninstalled.Refresh the token, or treat as uninstalled.
403 on an API callMissing scope, or the endpoint isn’t available to apps.Request the scope at install; see Scopes.

Next steps

Scopes & permissions

Map each scope to the endpoints it unlocks.

Build & publish

Register, list, and submit your app for review.