OAuth Ecart Pay
Table of Contents
- 🚀 Getting Started
- 🔑 How the Flow Works
- 1️⃣ Create Your Application
- 2️⃣ Redirect the Merchant to Ecart Pay
- 3️⃣ Receive the Authorization Code
- 4️⃣ Exchange the Code for an Access Token
- 5️⃣ Get the Merchant Credentials
- 🔄 Refreshing Tokens
- 🔐 Scopes
- 🧪 Complete Example
- 🧪 Testing
- 🚀 Going to Production
- 🧰 Error Reference
- 🔎 Resources
🚀 Getting Started
Prerequisites
Before integrating OAuth with Ecart Pay, ensure:
| Requirement | Description |
|---|---|
| Ecart Pay Account | Active account that will own the OAuth application (the partner / platform account). |
| Dashboard Token | An authorization token with the write_oauth_applications scope to create the application. |
| HTTPS Redirect | A redirect URI served over HTTPS where Ecart Pay returns the authorization code. |
| Backend | A server able to keep your client_secret private and exchange the code for a token. |
Base URLs
- Production:
https://ecartpay.com- Sandbox:
https://sandbox.ecartpay.comUse the sandbox while developing. Switch to production only when you are ready to go live.
🔑 How the Flow Works
| Step | Description |
|---|---|
| 1 | You create an OAuth application and receive a client_id and client_secret. |
| 2 | You redirect the merchant to GET /oauth with your client_id and redirect_uri. |
| 3 | The merchant signs in, completes verification (KYC levels 0 → 1) if needed, and grants consent. |
| 4 | Ecart Pay redirects back to your redirect_uri with a single-use ?code=.... |
| 5 | Your backend exchanges the code (+ client_secret) for an access_token. |
| 6 | You call GET /api/oauth/credentials with the token to obtain the merchant public_id/private_id. |
One-Time VerificationA merchant only completes verification once. On later connections, an already verified
merchant sees a short confirmation screen and is returned to your app immediately.
1️⃣ Create Your Application
Create your OAuth application once. The response includes your client_id and
client_secret.
cURL
curl -X POST "https://ecartpay.com/api/oauth/applications" \
-H "Authorization: Bearer <DASHBOARD_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"name": "Your App",
"description": "Short description shown on the consent screen",
"logo_url": "https://cdn.yourapp.com/logo.png",
"redirect_url": "https://yourapp.com/oauth/callback",
"scopes": ["read_orders", "write_orders"],
"onboarding": {
"headline": "Connect Your App with Ecart Pay",
"permissions_summary": ["View and create orders"]
}
}'Response 201
{
"id": "665f2a...",
"name": "Your App",
"client_id": "oauth_live_0cba2d6ad48c3e2f451eaa5e3f93cd12",
"client_secret": "secret_4f1c...e9",
"redirect_url": "https://yourapp.com/oauth/callback",
"scopes": ["read_orders", "write_orders", "read_credentials"],
"status": "active"
}
Store Your SecretThe
client_secretis returned only once. Store it securely on your backend.
You can rotate it later withPOST /api/oauth/applications/:id/secret.
Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| name | string | yes | Application name shown on the consent screen. |
| redirect_url | string | yes | HTTPS callback URL. Must be matched exactly on redirect. |
| description | string | no | Short description shown on the consent screen. |
| logo_url | string | no | Logo shown on the consent screen. |
| scopes | array | no | Requested scopes (see Scopes). read_credentials is always added. |
| onboarding.headline | string | no | Custom consent screen title. |
| onboarding.permissions_summary | array | no | Bullet list of permissions shown to the merchant. |
2️⃣ Redirect the Merchant to Ecart Pay
Send the merchant's browser to the OAuth entry point:
https://ecartpay.com/oauth?client_id=<CLIENT_ID>&redirect_uri=<REDIRECT_URI>&state=<STATE>
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| client_id | string | yes | Your application's client id. |
| redirect_uri | string | yes | Must match a whitelisted redirect URI exactly. |
| state | string | recommended | Opaque value echoed back to you; use it for CSRF protection. |
What the Merchant SeesEcart Pay handles sign-in, runs verification (KYC levels 0 and 1) when required, and
shows a consent screen with your app's name, logo, and the permissions you requested.
3️⃣ Receive the Authorization Code
After the merchant grants consent, Ecart Pay redirects to your redirect_uri:
https://yourapp.com/oauth/callback?code=<CODE>&state=<STATE>
Validate and Be Quick
- Verify the returned
statematches the value you sent.- The
codeis single-use and expires in 5 minutes — exchange it promptly.
4️⃣ Exchange the Code for an Access Token
From your backend, exchange the code for an access token. The code goes in the
Authorization header and your secret in the x-secret header.
cURL
curl -X POST "https://ecartpay.com/api/oauth/token?client_id=<CLIENT_ID>" \
-H "Authorization: <CODE>" \
-H "x-secret: <CLIENT_SECRET>" \
-H "Content-Type: application/json" \
-d '{
"grant_type": "authorization_code",
"redirect_url": "https://yourapp.com/oauth/callback"
}'Response 200
{
"access_token": "eyJhbGciOi...",
"expires_in": "1h",
"refresh_token": "a1b2c3...",
"scope": "read_orders,write_orders,read_credentials"
}Request Reference
| Location | Field | Description |
|---|---|---|
| Query | client_id | Your application's client id. |
| Header | Authorization | The authorization code (or a refresh_token). |
| Header | x-secret | Your client_secret. |
| Body | grant_type | authorization_code or refresh_token. |
| Body | redirect_url | The same redirect URI used in the flow. |
5️⃣ Get the Merchant Credentials
Use the merchant access_token to fetch the merchant's API keys.
cURL
curl -X GET "https://ecartpay.com/api/oauth/credentials" \
-H "Authorization: Bearer <ACCESS_TOKEN>"Response 200
{
"account_id": "665f2a...",
"public_id": "pub_live_...",
"private_id": "prv_live_..."
}Use these keys to operate on the merchant's behalf with the standard Ecart Pay API
(for example, the Orders API).
Scope RequiredThis endpoint requires the
read_credentialsscope, which is granted to every
application by default.
🔄 Refreshing Tokens
When the access token expires, exchange your refresh token for a new one.
cURL
curl -X POST "https://ecartpay.com/api/oauth/token?client_id=<CLIENT_ID>" \
-H "Authorization: <REFRESH_TOKEN>" \
-H "x-secret: <CLIENT_SECRET>" \
-H "Content-Type: application/json" \
-d '{
"grant_type": "refresh_token",
"redirect_url": "https://yourapp.com/oauth/callback"
}'
Single-Use Refresh TokensRefresh tokens are valid for 30 days and are single-use. Always store the new
refresh_tokenreturned in the response.
🔐 Scopes
| Scope | Grants |
|---|---|
| read_credentials | Read the merchant public_id / private_id (always included). |
| read_orders | Read orders. |
| write_orders | Create / update orders. |
Request the scopes your integration needs at registration time. The merchant sees these
permissions on the consent screen and must approve them.
Getting the Private KeyThe webhook contains
public_idonly. To obtain theprivate_id, call
GET /api/oauth/credentialswith the merchant access token.
🧪 Complete Example
A minimal Node.js backend handling the callback and token exchange:
JavaScript
const express = require('express');
const axios = require('axios');
const app = express();
const BASE_URL = 'https://sandbox.ecartpay.com';
const CLIENT_ID = process.env.ECARTPAY_CLIENT_ID;
const CLIENT_SECRET = process.env.ECARTPAY_CLIENT_SECRET;
const REDIRECT_URI = 'https://yourapp.com/oauth/callback';
// 1. Start the flow: redirect the merchant to Ecart Pay
app.get('/connect', (req, res) => {
const state = crypto.randomUUID();
// persist `state` in the user session for verification
const url = `${BASE_URL}/oauth?client_id=${CLIENT_ID}` +
`&redirect_uri=${encodeURIComponent(REDIRECT_URI)}&state=${state}`;
res.redirect(url);
});
// 2. Handle the callback and exchange the code
app.get('/oauth/callback', async (req, res) => {
const { code, state } = req.query;
// verify `state` matches the value stored for this user
const token = await axios.post(
`${BASE_URL}/api/oauth/token?client_id=${CLIENT_ID}`,
{ grant_type: 'authorization_code', redirect_url: REDIRECT_URI },
{ headers: { Authorization: code, 'x-secret': CLIENT_SECRET } }
);
const { access_token } = token.data;
// 3. Fetch the merchant credentials
const creds = await axios.get(`${BASE_URL}/api/oauth/credentials`, {
headers: { Authorization: `Bearer ${access_token}` },
});
// Store creds.data.public_id / private_id against this merchant
res.json(creds.data);
});
app.listen(3000);🧪 Testing
Use the Sandbox environment during development:
https://sandbox.ecartpay.com/oauth?client_id=<CLIENT_ID>&redirect_uri=<REDIRECT_URI>
| Step | Action |
|---|---|
| 1 | Create your application against the sandbox base URL. |
| 2 | Use a sandbox merchant account to run the full connect flow. |
| 3 | Confirm you receive ?code=... on your redirect URI and can exchange it. |
| 4 | Confirm GET /api/oauth/credentials returns the merchant keys. |
🚀 Going to Production
| Step | Action |
|---|---|
| 1 | Create (or re-create) your application against https://ecartpay.com. |
| 2 | Whitelist your production redirect_url. |
| 3 | Store the production client_secret securely on your backend. |
| 4 | Switch the entry URL and API calls to the production base URL. |
| 5 | Run the complete flow end-to-end with a real merchant account. |
🧰 Error Reference
| Status / Message | Likely Cause |
|---|---|
403 The redirect_uri is not allowed | redirect_uri does not exactly match a whitelisted URI. |
401 The token is not valid | The code expired (>5 min), was already used, or wrong client_id. |
401 The secret is missing | Missing x-secret header on /api/oauth/token. |
401 The client credentials are not valid | Wrong client_secret for the client_id. |
code looks like a URL instead of a token | The merchant arrived through a broken redirect chain — always start the flow at GET /oauth. |
| Merchant not returned / stuck | Verification (KYC level 1) not completed; the merchant must finish before a code is issued. |
🔎 Resources
| Resource | Link |
|---|---|
| Orders API | docs.ecartpay.com/docs/orders |
| API Keys | docs.ecartpay.com/docs/api-keys |
| Webhooks | docs.ecartpay.com/docs/webhooks-in-ecart-pay |
Updated about 24 hours ago