Obtain an access token
curl -s -X POST "https://services.sandbox.payplug-elements.msem.tech/oauth/token" \ --data-urlencode "grant_type=client_credentials" \ --data-urlencode "client_id=ESF-MSEM" \ --data-urlencode "client_secret=your-merchant-secret"const response = await fetch("https://services.sandbox.payplug-elements.msem.tech/oauth/token", { method: "POST", headers: { "content-type": "application/x-www-form-urlencoded" }, body: new URLSearchParams({ grant_type: "client_credentials", client_id: "ESF-MSEM", client_secret: "your-merchant-secret", }),});var response = client.send( HttpRequest.newBuilder(URI.create("https://services.sandbox.payplug-elements.msem.tech/oauth/token")) .header("content-type", "application/x-www-form-urlencoded") .POST(HttpRequest.BodyPublishers.ofString("grant_type=" + URLEncoder.encode("client_credentials", UTF_8) + "&client_id=" + URLEncoder.encode("ESF-MSEM", UTF_8) + "&client_secret=" + URLEncoder.encode("your-merchant-secret", UTF_8))) .build(), HttpResponse.BodyHandlers.ofString());var request = new HttpRequestMessage(HttpMethod.Post, "https://services.sandbox.payplug-elements.msem.tech/oauth/token");request.Content = new FormUrlEncodedContent(new Dictionary<string, string>{ ["grant_type"] = "client_credentials", ["client_id"] = "ESF-MSEM", ["client_secret"] = "your-merchant-secret",});var response = await http.SendAsync(request);$request = curl_init("https://services.sandbox.payplug-elements.msem.tech/oauth/token");curl_setopt_array($request, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => http_build_query([ 'grant_type' => 'client_credentials', 'client_id' => 'ESF-MSEM', 'client_secret' => 'your-merchant-secret', ]),]);$response = curl_exec($request);response = requests.post( "https://services.sandbox.payplug-elements.msem.tech/oauth/token", data={ "grant_type": "client_credentials", "client_id": "ESF-MSEM", "client_secret": "your-merchant-secret", },)response = Net::HTTP.post_form( URI("https://services.sandbox.payplug-elements.msem.tech/oauth/token"), "grant_type" => "client_credentials", "client_id" => "ESF-MSEM", "client_secret" => "your-merchant-secret")resp, err := http.PostForm("https://services.sandbox.payplug-elements.msem.tech/oauth/token", url.Values{ "grant_type": {"client_credentials"}, "client_id": {"ESF-MSEM"}, "client_secret": {"your-merchant-secret"},})if err != nil { return err}defer resp.Body.Close()let response = http .post("https://services.sandbox.payplug-elements.msem.tech/oauth/token") .form(&[ ("grant_type", "client_credentials"), ("client_id", "ESF-MSEM"), ("client_secret", "your-merchant-secret"), ]) .send() .await?;curl -s -X POST "https://services.payplug-elements.msem.tech/oauth/token" \ --data-urlencode "grant_type=client_credentials" \ --data-urlencode "client_id=ESF-MSEM" \ --data-urlencode "client_secret=your-merchant-secret"const response = await fetch("https://services.payplug-elements.msem.tech/oauth/token", { method: "POST", headers: { "content-type": "application/x-www-form-urlencoded" }, body: new URLSearchParams({ grant_type: "client_credentials", client_id: "ESF-MSEM", client_secret: "your-merchant-secret", }),});var response = client.send( HttpRequest.newBuilder(URI.create("https://services.payplug-elements.msem.tech/oauth/token")) .header("content-type", "application/x-www-form-urlencoded") .POST(HttpRequest.BodyPublishers.ofString("grant_type=" + URLEncoder.encode("client_credentials", UTF_8) + "&client_id=" + URLEncoder.encode("ESF-MSEM", UTF_8) + "&client_secret=" + URLEncoder.encode("your-merchant-secret", UTF_8))) .build(), HttpResponse.BodyHandlers.ofString());var request = new HttpRequestMessage(HttpMethod.Post, "https://services.payplug-elements.msem.tech/oauth/token");request.Content = new FormUrlEncodedContent(new Dictionary<string, string>{ ["grant_type"] = "client_credentials", ["client_id"] = "ESF-MSEM", ["client_secret"] = "your-merchant-secret",});var response = await http.SendAsync(request);$request = curl_init("https://services.payplug-elements.msem.tech/oauth/token");curl_setopt_array($request, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => http_build_query([ 'grant_type' => 'client_credentials', 'client_id' => 'ESF-MSEM', 'client_secret' => 'your-merchant-secret', ]),]);$response = curl_exec($request);response = requests.post( "https://services.payplug-elements.msem.tech/oauth/token", data={ "grant_type": "client_credentials", "client_id": "ESF-MSEM", "client_secret": "your-merchant-secret", },)response = Net::HTTP.post_form( URI("https://services.payplug-elements.msem.tech/oauth/token"), "grant_type" => "client_credentials", "client_id" => "ESF-MSEM", "client_secret" => "your-merchant-secret")resp, err := http.PostForm("https://services.payplug-elements.msem.tech/oauth/token", url.Values{ "grant_type": {"client_credentials"}, "client_id": {"ESF-MSEM"}, "client_secret": {"your-merchant-secret"},})if err != nil { return err}defer resp.Body.Close()let response = http .post("https://services.payplug-elements.msem.tech/oauth/token") .form(&[ ("grant_type", "client_credentials"), ("client_id", "ESF-MSEM"), ("client_secret", "your-merchant-secret"), ]) .send() .await?;RFC 6749 token endpoint. For an integration: grant_type=client_credentials with your merchant credentials (body, or HTTP Basic) — the access token then opens every /api search and refund door for YOUR merchant, for expires_in seconds; re-authenticate when it lapses. The authorization_code/refresh_token grants serve the dashboard’s human login and are not for integrations. Errors speak the RFC’s dialect ({error}), and invalid_grant is deliberately uniform — it never says which hurdle fell.
Request Bodyrequired
Section titled “Request Bodyrequired”RFC 6749 — the body travels as application/x-www-form-urlencoded, never JSON.
RFC 6749 — the body travels as application/x-www-form-urlencoded, never JSON.
object
client_credentials is the INTEGRATION grant — your server authenticating as itself. The other two belong to the dashboard’s login flow and are not for integrations.
Client_credentials: your merchantId — or send both credentials as HTTP Basic (Authorization: Basic base64(merchantId:secret)), both shapes are standard.
Example
ESF-MSEMClient_credentials: your merchant secret — body or HTTP Basic.
Example
your-merchant-secretDashboard login flow (authorization_code) only.
Dashboard login flow (PKCE) only.
Dashboard login flow only.
Dashboard flow (refresh_token grant) only.
Responses
Section titled “ Responses ”The token, RFC 6749 §5.1.
object
The Bearer JWT for the /api surface — send it as Authorization: Bearer ….
Always Bearer — present the token as Authorization: Bearer <token>.
Seconds of validity. When it lapses, a machine simply re-authenticates: client_credentials issues NO refresh token.
Dashboard flow only — rotating, and the whole family burns on a replay.
Example
{ "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtMTEiLCJ0eXAiOiJtZXJjaGFudCJ9.9pQ2…", "token_type": "Bearer", "expires_in": 3600}invalid_request, unsupported_grant_type — or the uniform invalid_grant, which never says which hurdle fell.
object
RFC 6749 error code — invalid_client, unsupported_grant_type… Branch on this.
Human-readable detail, when there is one to give.
Example
{ "error": "unsupported_grant_type", "error_description": "grant_type must be client_credentials"}invalid_client — unknown or wrong credentials, one answer for both.
object
RFC 6749 error code — invalid_client, unsupported_grant_type… Branch on this.
Human-readable detail, when there is one to give.
Example
{ "error": "invalid_client", "error_description": "unknown client or wrong secret"}