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:

RequirementDescription
Ecart Pay AccountActive account that will own the OAuth application (the partner / platform account).
Dashboard TokenAn authorization token with the write_oauth_applications scope to create the application.
HTTPS RedirectA redirect URI served over HTTPS where Ecart Pay returns the authorization code.
BackendA 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.com

Use the sandbox while developing. Switch to production only when you are ready to go live.


🔑 How the Flow Works

StepDescription
1You create an OAuth application and receive a client_id and client_secret.
2You redirect the merchant to GET /oauth with your client_id and redirect_uri.
3The merchant signs in, completes verification (KYC levels 0 → 1) if needed, and grants consent.
4Ecart Pay redirects back to your redirect_uri with a single-use ?code=....
5Your backend exchanges the code (+ client_secret) for an access_token.
6You call GET /api/oauth/credentials with the token to obtain the merchant public_id/private_id.
👍

One-Time Verification

A 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 Secret

The client_secret is returned only once. Store it securely on your backend.
You can rotate it later with POST /api/oauth/applications/:id/secret.

Body Parameters

ParameterTypeRequiredDescription
namestringyesApplication name shown on the consent screen.
redirect_urlstringyesHTTPS callback URL. Must be matched exactly on redirect.
descriptionstringnoShort description shown on the consent screen.
logo_urlstringnoLogo shown on the consent screen.
scopesarraynoRequested scopes (see Scopes). read_credentials is always added.
onboarding.headlinestringnoCustom consent screen title.
onboarding.permissions_summaryarraynoBullet 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

ParameterTypeRequiredDescription
client_idstringyesYour application's client id.
redirect_uristringyesMust match a whitelisted redirect URI exactly.
statestringrecommendedOpaque value echoed back to you; use it for CSRF protection.
📘

What the Merchant Sees

Ecart 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 state matches the value you sent.
  • The code is 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

LocationFieldDescription
Queryclient_idYour application's client id.
HeaderAuthorizationThe authorization code (or a refresh_token).
Headerx-secretYour client_secret.
Bodygrant_typeauthorization_code or refresh_token.
Bodyredirect_urlThe 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 Required

This endpoint requires the read_credentials scope, 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 Tokens

Refresh tokens are valid for 30 days and are single-use. Always store the new
refresh_token returned in the response.


🔐 Scopes

ScopeGrants
read_credentialsRead the merchant public_id / private_id (always included).
read_ordersRead orders.
write_ordersCreate / 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 Key

The webhook contains public_id only. To obtain the private_id, call
GET /api/oauth/credentials with 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>
StepAction
1Create your application against the sandbox base URL.
2Use a sandbox merchant account to run the full connect flow.
3Confirm you receive ?code=... on your redirect URI and can exchange it.
4Confirm GET /api/oauth/credentials returns the merchant keys.

🚀 Going to Production

StepAction
1Create (or re-create) your application against https://ecartpay.com.
2Whitelist your production redirect_url.
3Store the production client_secret securely on your backend.
4Switch the entry URL and API calls to the production base URL.
5Run the complete flow end-to-end with a real merchant account.

🧰 Error Reference

Status / MessageLikely Cause
403 The redirect_uri is not allowedredirect_uri does not exactly match a whitelisted URI.
401 The token is not validThe code expired (>5 min), was already used, or wrong client_id.
401 The secret is missingMissing x-secret header on /api/oauth/token.
401 The client credentials are not validWrong client_secret for the client_id.
code looks like a URL instead of a tokenThe merchant arrived through a broken redirect chain — always start the flow at GET /oauth.
Merchant not returned / stuckVerification (KYC level 1) not completed; the merchant must finish before a code is issued.

🔎 Resources