Documentation Index
Fetch the complete documentation index at: https://docs.fluveo.com/llms.txt
Use this file to discover all available pages before exploring further.
Fluveo apps use the OAuth 2.0 authorization code flow to obtain access tokens on behalf of merchants. This guide covers every step with detailed curl examples.
Flow overview
1. Your app redirects the merchant to the Fluveo authorization page
2. The merchant reviews scopes and approves (or denies)
3. Fluveo redirects back to your app with an authorization code
4. Your app exchanges the code for an access token and refresh token
5. Your app uses the access token to call the API
6. When the access token expires, use the refresh token to get a new one
Step 1: Redirect to authorization
Build the authorization URL and redirect the merchant’s browser to it. The Fluveo dashboard renders a consent screen showing your app’s name and requested scopes.
The authorization URL format is:
https://dashboard.leanrails.com/marketplace/authorize
?client_id=ca_live_abc123def456
&redirect_uri=https://yourapp.example.com/oauth/callback
&scope=read_products,read_inventory,write_inventory
&state=random_csrf_token_123
| Parameter | Required | Description |
|---|
client_id | Yes | Your app’s OAuth client ID |
redirect_uri | Yes | Must match one of your registered redirect URIs |
scope | Yes | Comma-separated list of requested scopes |
state | Recommended | An opaque value to prevent CSRF attacks. Returned unchanged in the callback. |
Step 2: Merchant grants or denies
When the merchant clicks “Approve”, the Fluveo API creates an authorization code and returns a redirect URL.
Grant (server-side call from the dashboard)
curl -X POST https://api.leanrails.com/v1/oauth/authorize/grant \
-H "Content-Type: application/json" \
-H "X-Merchant-ID: merch_abc123" \
-d '{
"client_id": "ca_live_abc123def456",
"scopes": ["read_products", "read_inventory", "write_inventory"],
"redirect_uri": "https://yourapp.example.com/oauth/callback",
"state": "random_csrf_token_123"
}'
Response:
{
"redirect_url": "https://yourapp.example.com/oauth/callback?code=authcode_abc123def456&state=random_csrf_token_123",
"code": "authcode_abc123def456"
}
The merchant’s browser is redirected to your redirect_uri with the code and state parameters.
Deny
If the merchant clicks “Deny”:
curl -X POST https://api.leanrails.com/v1/oauth/authorize/deny \
-H "Content-Type: application/json" \
-H "X-Merchant-ID: merch_abc123" \
-d '{
"redirect_uri": "https://yourapp.example.com/oauth/callback",
"state": "random_csrf_token_123"
}'
Response:
{
"redirect_url": "https://yourapp.example.com/oauth/callback?error=access_denied&error_description=The+merchant+denied+the+authorization+request.&state=random_csrf_token_123"
}
Your app should handle the error=access_denied case gracefully and show an appropriate message.
Step 3: Exchange the authorization code for tokens
When your callback URL receives the code parameter, exchange it for an access token and refresh token. Authenticate with your client_id and client_secret via HTTP Basic Auth.
curl -X POST https://api.leanrails.com/v1/oauth/token \
-u "ca_live_abc123def456:cs_live_secret_value" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code&code=authcode_abc123def456&redirect_uri=https://yourapp.example.com/oauth/callback"
Response:
{
"access_token": "at_live_abc123def456ghi789",
"token_type": "bearer",
"expires_in": 3600,
"refresh_token": "rt_live_xyz789abc123def456",
"scope": "read_products read_inventory write_inventory",
"merchant_id": "merch_abc123"
}
Authorization codes are single-use and expire after 10 minutes. Exchange them immediately.
You can also pass client credentials in the request body instead of Basic Auth:
curl -X POST https://api.leanrails.com/v1/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code&code=authcode_abc123def456&redirect_uri=https://yourapp.example.com/oauth/callback&client_id=ca_live_abc123def456&client_secret=cs_live_secret_value"
Step 4: Use the access token
Make API calls on behalf of the merchant using the access token as a Bearer token:
curl https://api.leanrails.com/v1/products?limit=10 \
-H "Authorization: Bearer at_live_abc123def456ghi789"
The token’s scopes limit which endpoints are accessible. Attempting to access an endpoint outside the granted scopes returns a 403 error.
Step 5: Refresh the access token
Access tokens expire after the duration specified in expires_in (typically 1 hour). Use the refresh token to obtain a new access token without requiring the merchant to re-authorize.
curl -X POST https://api.leanrails.com/v1/oauth/token \
-u "ca_live_abc123def456:cs_live_secret_value" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token&refresh_token=rt_live_xyz789abc123def456"
Response:
{
"access_token": "at_live_new_token_abc123",
"token_type": "bearer",
"expires_in": 3600,
"refresh_token": "rt_live_new_refresh_xyz789",
"scope": "read_products read_inventory write_inventory",
"merchant_id": "merch_abc123"
}
Each refresh returns a new refresh token. Always store the latest refresh token and discard the old one.
Step 6: Revoke a token
When a merchant uninstalls your app or you need to invalidate tokens, call the revoke endpoint:
curl -X POST https://api.leanrails.com/v1/oauth/revoke \
-u "ca_live_abc123def456:cs_live_secret_value" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "token=at_live_abc123def456ghi789"
Response:
Error handling
Token exchange errors return standard OAuth error responses:
| Error | Description |
|---|
invalid_client | The client_id or client_secret is incorrect. |
invalid_request | Missing required parameters like code or redirect_uri. |
invalid_grant | The authorization code is expired, already used, or invalid. |
unsupported_grant_type | Only authorization_code and refresh_token are supported. |
invalid_scope | One or more requested scopes are not declared by the app. |
Example error response:
{
"error": "invalid_client",
"error_description": "Client credentials required."
}
Security best practices
- Always validate the
state parameter in the callback to prevent CSRF attacks.
- Store
client_secret and refresh tokens in a secure secrets manager, never in client-side code.
- Exchange authorization codes immediately — they expire in 10 minutes.
- Implement token refresh proactively before the access token expires.
- Use HTTPS for all redirect URIs.
Next steps