sertropipay

1.3.8 • Public • Published

NodeTropipaySDK

NodeJS JavaScript Next JS JWT Heroku Vercel NPM Postman React React_Router React_Query Redux strapi Tailwind_CSS Webpack Yarn vs vscode WebStorm eslint prettier GitHub

Node Library SDK for Tropipay Integration by SerproTeam

It is a library for an advanced integration of the tropipay API It provides initial authorization of the module at application startup which creates an instance to be used exclusively in the Server Side

It also adds creation of payment links, mediated payments, registration of events on the Hook

Author


Fidel Remedios Rosado
@fiderosado

Repository

https://github.com/fiderosado/NodeTropipaySDK

https://github.com/fiderosado/NodeTropipaySDK.git

Dependencies

  • Axios
  • Json Web Token
  • CryptoJS

Module Exports

  • Tropipay
  • TropipayConfig
  • TropipayRequireAuth
  • TropipayModels

Integration NPM Package

https://www.npmjs.com/package/sertropipay


First you have to install the library using the various standards to import the dependency and export the functionalities for example:

NPM

  npm install sertropipay
  npm i sertropipay

YARN

  yarn add sertropipay

UPGRADE

  yarn upgrade sertropipay

Enviroment keys


You need to configure this keys

NODE_ENV=development or production
TROPIPAY_SERVER=https://tropipay-dev.herokuapp.com
TROPIPAY_CLIENT_ID="you client id"
TROPIPAY_CLIENT_SECRET="you client secret key"
TROPIPAY_SCOPE="ALLOW_GET_PROFILE_DATA ALLOW_GET_BALANCE ALLOW_GET_MOVEMENT_LIST ALLOW_PAYMENT_IN ALLOW_EXTERNAL_CHARGE KYC3_FULL_ALLOW ALLOW_PAYMENT_OUT ALLOW_MARKET_PURCHASES ALLOW_GET_CREDENTIAL"

If you dont have the scope params follow this link: https://tpp.stoplight.io/docs/tropipay-api-doc/ZG9jOjI3NDE0MjMw-integration-with-client-credentials

Start On

To use the library at the start of the app there are several approaches, I will show them to you and you can choose the one that is most useful for you.

You don't necessarily have to use this approach, you can make one directly in your routes by implementing use-on-bakend

next.config.js

In this case we will use the start focused on file next.config.js which allows us to create an instance to be authorized on Tropipay of and propagate it in the project, Add this code to next.config.js File.

const Tropipay = require("sertropipay").Tropipay.getInstance();

const nextConfig = {
  /* use the serverRuntimeConfig function to start the process on bakend */
  serverRuntimeConfig: {
    initializeTpp: Tropipay.Authorize(),
  },
  /* */
}

tropipayInstance.js

In this case we will use the start focused file in the root directory called tropipayInstance.js which will have a global variable with the existing instance

  import { Tropipay } from "sertropipay";
let tropipayInstance;
export async function getTropipayInstance() {
  if (!tropipayInstance) {
    tropipayInstance = await Tropipay.getInstance().Authorize();
  }
  return tropipayInstance;
}

When the project start you can see an recive messages on bakend logs like this:

- ready started server on 0.0.0.0:6006, url: http://localhost:6006 (on my case)
- info Loaded env from ***\.env
- wait compiling...
$ next build
- info Loaded env from *\.env
- Tropipay: starting...
- Error: Tropipay: Authorize: Validating token error, autorizing...
- Error: Tropipay: Axios: Instance not exist, creating...
- Success: Tropipay: Axios: Instance is ready...
- Success: Tropipay: Authorize is ready...

This is the response of the first call to the tropipay api requesting authorization.

{
  access_token: 'eyJhbGciOiJIUzI*****',
          refresh_token: 'MTY4ODY1OTE******',
          token_type: 'Bearer',
          expires_in: 1688666372,
          scope: 'ALLOW_EXTERNAL_CHARGE ALLOW_CREATE_BENEFICIARY *******'
}

Use on Bakend

In this case we will use an api route which we will use the resource: /api/*

import { NextResponse } from "next/server";
import { Tropipay } from "sertropipay";

export async function GET() {
  const TropipayInstance = await Tropipay.getInstance().Authorize();

  return NextResponse.json({
    rendered: "ok",
    data: `${JSON.stringify(TropipayInstance.getData())}`,
  });
}

Create a FirstPayment Card

In this example, the payment attempt is created statically from a get request to the server, but the correct thing to do is to implement your corresponding business logic.

In this case we will create a direct payment link between the client and the provider account, it can be personal or company type, which requires two models, the first for the client and the second for the payment card, which includes the Client model, You can access these models implementing TropipayModels in the import, but if you want you can use an object with the required properties in the model, as long as the data model is fulfilled the payment attempt is successful, delivering an object with the necessary data to continue the pay.

CientModel

  {
  name: string  The name of the client.
          lastName: string  The last name of the client.
          address: string  The address of the client.
          phone: string  The phone number of the client.
          email: string  The email of the client.
          termsAndConditions: string  The terms and conditions accepted by the client.
          countryId: number  The ID of the country. (Optional if countryIso has a value)
  countryIso: string  The ISO code of the country. (Optional if countryId has a value)
}

PaymentCardModel

  {
  reference: string  The reference for the payment card.
          concept: string  The concept of the payment card.
          description: string  The description of the payment card.
          favorite: boolean  Indicates if the payment card is marked as favorite.
          amount: number  The amount for the payment card.
          currency: string  The currency for the payment card.
          singleUse: boolean  Indicates if the payment card is for single use.
          reasonId: number  The reason ID for the payment card.
          expirationDays: number  The expiration days for the payment card.
          lang: string  The language for the payment card.
          urlSuccess: string  The URL for the successful payment.
          urlFailed: string  The URL for the failed payment.
          urlNotification: string  The URL for the payment notification.
          serviceDate: string  The service date for the payment card.
          directPayment: boolean  Indicates if the payment is a direct payment.
          paymentMethods: Array  The payment methods available for the payment card.
          saveToken: boolean  Indicates if the payment token should be saved.
          cient: CientModel  The client data for the payment card.
}

import { NextResponse } from "next/server";
import { Tropipay, TropipayModels } from "sertropipay";

export async function GET() {
  const TropipayInstance = await Tropipay.getInstance().Authorize();

  const clientForCart = new TropipayModels.CientPayload(
          "Nombre",
          "Apellidos",
          "Address",
          "+cell",
          "email@gmail.com",
          "1",
          null,
          "true"
  );
  const previusCart = new TropipayModels.PaymentCardPayload(
          "s87e8h213h132d13h13r12h13",
          "Bicycle",
          "Two wheels",
          false,
          3000,
          "EUR",
          true,
          4,
          1,
          "es",
          "https://requestinspector.com/inspect/01h5kkczp74gceza3bp2a9mc54",
          "https://requestinspector.com/inspect/01h5kkczp74gceza3bp2a9mc54",
          "https://requestinspector.com/inspect/01h5kkczp74gceza3bp2a9mc54",
          "2023-07-17",
          true,
          ["EXT", "TPP"],
          false,
          clientForCart.toObject()
  );

  const intentCart = await TropipayInstance.CreatePaymentCard(
          previusCart.toObject()
  );

  return NextResponse.json({
    rendered: "ok",
    data: `${JSON.stringify(intentCart)}`,
  });
}

Creating a Mediation Payment Card

Only for Business accounts, This endpoint allows you to generate an escrow payment link. This allows a payment to be made to persons belonging or not to the TropiPay platform with the particularity that the payment will be held in custody or retained until it is released with the approval of the payer.

https://tpp.stoplight.io/docs/tropipay-api-doc/12a128ff971e4-creating-a-mediation-payment-card

Subscribe to events through hook

You can subscribe to events through hooks, and receive notifications for each action related to mediated paymentcards, there are three events for this:

https://tpp.stoplight.io/docs/tropipay-api-doc/0b7235bfedb66-subscribe-to-new-event-with-a-hook

  • transaction_guarded: triggered when a paymentcard is paid
  • transaction_charged: Triggered when a paymentcard is released
  • transaction_cancelled: Triggered when a paymentcard is canceled

Mediation Payment Card Payload

    {
  "amount": 5000,
          "currency": "EUR",
          "concept": "Celular",
          "description": "Celular nuevo",
          "reference": "458424548",
          "singleUse": false,
          "lang": "es",
          "productUrl": "https://www.google.es",
          "buyer": null,
          "seller": {
    "sellerId": null,
            "type": 1,
            "email": "user@gmail.com"
  },
  "feePercent": 600,
          "feeFixed": 0,
          "sendMail": false
}

Create Mediation Payment Card Implementation

import { NextResponse } from "next/server";
import { Tropipay } from "sertropipay";

export async function GET() {
  const TropipayInstance = await Tropipay.getInstance().Authorize();
  const mediation_card = await TropipayInstance.CreateMediationPaymentCard( Mediation Payment Card Payload );

  return NextResponse.json({
    rendered: "ok",
    data: `${JSON.stringify(mediation_card)}`,
  });
}

/** 200 OK Response **/

{
  "reference": "458424548",
        "concept": "Celular",
        "description": "Celular nuevo",
        "amount": 5000,
        "currency": "EUR",
        "singleUse": false,
        "favorite": false,
        "reasonId": 6,
        "expirationDays": 0,
        "userId": "d48f0800-25a0-11ea-9773-1315b442db0a",
        "lang": "es",
        "state": 1,
        "hasClient": false,
        "credentialId": 129283,
        "urlSuccess": null,
        "urlFailed": null,
        "saveToken": false,
        "paymentcardType": 2,
        "updatedAt": "2023-07-18T06:57:33.887Z",
        "createdAt": "2023-07-18T06:57:33.505Z",
        "qrImage": null,
        "shortUrl": null,
        "urlNotification": null,
        "expirationDate": null,
        "serviceDate": null,
        "paymentUrl": "https://tppay.me/lk7xzsze",
        "reasonDes": null,
        "seller": {
  "paymentcardId": "5eddbb10-2538-11ee-8322-5fbd993ebf9a",
          "sendMail": false,
          "merchantFeePercent": 600,
          "merchantFeeFixed": 0,
          "feeToSeller": false,
          "productUrl": "https://www.google.es",
          "updatedAt": "2023-07-18T06:57:33.528Z",
          "createdAt": "2023-07-18T06:57:33.528Z",
          "sellerId": 59174
},
  "flowId": "5eddbb10-2538-11ee-8322-5fbd993ebf9a"
}

Deposit Accounts

Returns the list of beneficiaries (depositAccounts) of logged user. Beneficiaries can be active (status: 0) or inactive (status: 1) https://tpp.stoplight.io/docs/tropipay-api-doc/e232d0427f703-get-deposit-accounts-list

import { NextResponse } from "next/server";
import { Tropipay } from "sertropipay";

export async function GET() {
  const TropipayInstance = await Tropipay.getInstance().Authorize();

  const listadeposit = await TropipayInstance.GetDepositAccountsList();
  return NextResponse.json({
    rendered: "ok",
    data: `${JSON.stringify(listadeposit)}`,
  });
}

Hooks


Subscribe to new event with a hook

Endpoint allows a merchant to subscribe to an event, specifying the options to receive information at the time it is trigger. https://tpp.stoplight.io/docs/tropipay-api-doc/0b7235bfedb66-subscribe-to-new-event-with-a-hook

POST: https://tropipay-dev.herokuapp.com/api/v2/hooks , Authorization required Bearer {token}

Event : Events are made up of an object with three fundamental properties (event, target, value)

  • event: String that represents the name of the event, you must select from the list of available events, otherwise it will not produce an error but it will not be executed. For get full list of available events see endpoint GET /api/v2/hook/events.

  • target: String representing the type of event supported. It is currently available: 'web' (allows to receive information in a url), 'email' (allows to receive information in an email address).

  • value: String that represents the value depending on the type of selected event determined by the 'target' property, for example if the selected 'target' is email the value would be an email address, likewise if the selected 'target' is 'web' the expected value corresponds to a url that receives information through the HTTP POST method.

Use SubscribeNewEventHook

import { NextResponse } from "next/server";
import { Tropipay } from "sertropipay";

export async function GET() {
  const TropipayInstance = await Tropipay.getInstance().Authorize();

  const NewEvent = {
    "event": "user_signup",
    "target": "web",
    "value": "https://www.merchant_domain.com/api/user/signup/listen"
  }
  /** OR **/
  const NewEvent = {
    "event": "user_signup",
    "target": "email",
    "value": "user@mail.com"
  }

  const hook_response = await TropipayInstance.SubscribeNewEventHook(NewEvent);

  return NextResponse.json({
    rendered: "ok",
    data: `${JSON.stringify(hook_response)}`,
  });
}
/** Response Example **/
{
    "action": "update",
    "status": "success",
    "details": "user_signup"
}

{
    "action": "subscribe",
    "status": "success",
    "details": "transaction_guarded"
}

Get a list of all events subscribed with Hooks

Endpoint for getting event hooks list by merchant.

GET: https://tropipay-dev.herokuapp.com/api/v2/hooks , Authorization required Bearer {token}

Event : Events are made up of an object with three fundamental properties (event, target, value)

  • event: String that represents the name of the event, you must select from the list of available events, otherwise it will not produce an error but it will not be executed. For get full list of available events see endpoint GET /api/v2/hook/events.

  • target: String representing the type of event supported. It is currently available: 'web' (allows to receive information in a url), 'email' (allows to receive information in an email address).

  • value: String that represents the value depending on the type of selected event determined by the 'target' property, for example if the selected 'target' is email the value would be an email address, likewise if the selected 'target' is 'web' the expected value corresponds to a url that receives information through the HTTP POST method.

Use GetEventsSubscribedHooksList

import { NextResponse } from "next/server";
import { Tropipay } from "sertropipay";

export async function GET() {
  const TropipayInstance = await Tropipay.getInstance().Authorize();

  const hooks_list = await TropipayInstance.GetEventsSubscribedHooksList();
  return NextResponse.json({
    rendered: "ok",
    data: `${JSON.stringify(hooks_list)}`,
  });
}

/** 200 OK Response */
[
    {
        "event": "transaction_guarded",
        "target": "web",
        "value": "https://site.onrender.com/api/hooks/payment",
        "createdAt": "2023-07-20T05:32:25.946Z",
        "updatedAt": "2023-07-20T05:32:25.946Z"
    },
    {
        "event": "transaction_charged",
        "target": "web",
        "value": "https://site.onrender.com/api/hooks/payment",
        "createdAt": "2023-07-20T05:34:22.728Z",
        "updatedAt": "2023-07-20T05:34:22.728Z"
    },
    {
        "event": "transaction_cancelled",
        "target": "web",
        "value": "https://site.onrender.com/api/hooks/payment",
        "createdAt": "2023-07-20T05:34:35.528Z",
        "updatedAt": "2023-07-20T05:34:35.528Z"
    }
]

Get a list with all events that allow a subscription

Endpoint for get full list of available events. Events are made up of an object with two fundamental properties (name, description)

GET: https://tropipay-dev.herokuapp.com/api/v2/hooks/events

  • user_signup: Event launched once an user complete registration on the TropiPay platform.
  • user_login: Event launched once an user complete login on the TropiPay platform.
  • user_kyc: Event launched once an user complete KYC process, indicated in each case the process status. Payload of response:
  • payment_in_state_change: The event is fired once a user changes their status payment in entry method.
  • payment_out_state_change: The event is fired once a user changes their status payment out entry method.

Use GetEventsAllowSubscriptionList

import { NextResponse } from "next/server";
import { Tropipay } from "sertropipay";

export async function GET() {
  const TropipayInstance = await Tropipay.getInstance().Authorize();

  const hooks_list = await TropipayInstance.GetEventsAllowSubscriptionList();
  return NextResponse.json({
    rendered: "ok",
    data: `${JSON.stringify(hooks_list)}`,
  });
}

/** 200 OK Response */

[
  {
    "name": "user_signup",
    "description": "Event launched once an user completes registration on the TropiPay platform."
  },
  {
    "name": "user_login",
    "description": "Event launched once an user completes login on the TropiPay platform."
  },
  {
    "name": "user_kyc",
    "description": "Event launched once an user completes kyc process."
  },
  {
    "name": "payment_in_state_change",
    "description": "The event is fired once a user changes their status payment in entry method."
  },
  {
    "name": "payment_out_state_change",
    "description": "The event is fired once a user changes their status payment out entry method."
  },
  {
    "name": "beneficiary_added",
    "description": "Launched after new beneficiary is created."
  },
  {
    "name": "beneficiary_updated",
    "description": "Launched after a beneficiary is modified."
  },
  {
    "name": "beneficiary_deleted",
    "description": "Launched after a beneficiary is deleted."
  },
  {
    "name": "transaction_new",
    "description": "Create a new transaction"
  },
  {
    "name": "transaction_preauthorized",
    "description": "Pre-authorized and blocked transaction awaiting review"
  },
  {
    "name": "transaction_pendingin",
    "description": "Pending transaction to settle in the payment entity"
  },
  {
    "name": "transaction_processing",
    "description": "Transaction in process"
  },
  {
    "name": "transaction_error",
    "description": "Transaction in error"
  },
  {
    "name": "transaction_bloqued",
    "description": "Transaction bloqued"
  },
  {
    "name": "transaction_charged",
    "description": "Transaction waiting to be sent"
  },
  {
    "name": "transaction_paid",
    "description": "Transaction sent"
  },
  {
    "name": "transaction_cancelled",
    "description": "Transaction cancelled"
  },
  {
    "name": "transaction_guarded",
    "description": "Transaction guarded"
  },
  {
    "name": "transaction_guarded_send",
    "description": "Transaction guarded and send"
  },
  {
    "name": "transaction_guarded_mediation",
    "description": "Transaction guarded with mediation"
  },
  {
    "name": "user_after_update",
    "description": "Event launched after a user is updated."
  },
  {
    "name": "user_after_create",
    "description": "Event launched after a user is created."
  },
  {
    "name": "userDetail_after_create",
    "description": "Event launched after a userDetails is created."
  },
  {
    "name": "userDetail_after_update",
    "description": "Event launched after a userDetails is updated."
  },
  {
    "name": "transaction_completed",
    "description": "Event launched after transaction is completed."
  },
  {
    "name": "tpv_callback_ok",
    "description": "Event launched after tpv callback ok."
  }
]

Tropipay Auth

The TropipayAuth Module allows you to access functions like GetAuthorizationToken to get a tropipay access token and follow an OAUTH flow, then use the GetProfile method to access information about the authenticating user.

Implement TropipayAuth on Bakend to Redirect to Tropipay Login

To start implement TropipayAuth from the "sertropipay" library you must create a redirect url using params object to fusion on URL and go: app/api/auth/tpp/route.js

import { NextResponse } from "next/server";
import { TropipayAuth } from "sertropipay";
export async function GET(request) {

/* this is the params to fusion on url , has be the same */
const originUrl = request.nextUrl.searchParams.get("origin");
const originMode = request.nextUrl.searchParams.get("mode");

/* i tell the instance, get me the url sending param object , has be the same  */
const urlRedirect = new TropipayAuth().Login({
  origin: originUrl,
  mode: originMode,
});

/* asing the redirect url to a NextResponse redirect method */
const redirect = NextResponse.redirect(urlRedirect.url);

/* validate the url previusly */
if (urlRedirect?.code_verifier && urlRedirect?.state) {
  const config = {
    path: "/",
    httpOnly: true,
    maxAge: 60, // 1 min
  };

  /* adding , code_verifier and state params to the cookie */
  redirect.cookies.set("code_verifier", urlRedirect?.code_verifier, config);
  redirect.cookies.set("state", urlRedirect?.state, config);

  /* go to url */
  return redirect;
}
/* if the url is not valid redirect to custom error page */
NextResponse.redirect("/error/500?the-redirect-url-from-tpp-is-not-valid");
}

Implement TropipayAuth on Bakend Callback to capture the params i nedd to get the session

When implementing TropipayAuth from the "sertropipay" library you must create a callback in your api project folder like this: app/api/auth/callback/route.js

import { NextResponse } from "next/server";
import { cookies } from "next/headers";
import { TropipayAuth } from "sertropipay";

const AppUrl = process.env.APP_URL;

export async function GET(request) {
  const nextCookies = cookies();
  const authorizationStateCookie = nextCookies.get("state");
  const codeVerifierCookie = nextCookies.get("code_verifier");

  const authorizationState = request.nextUrl.searchParams.get("state");
  const authorizationCode = request.nextUrl.searchParams.get("code");

  /* the same params on redirect enpoint */
  const originUrl = request.nextUrl.searchParams.get("origin");
  const originMode = request.nextUrl.searchParams.get("mode");

  const TropipayAuthInstance = new TropipayAuth();

  if (authorizationStateCookie === undefined) {
    console.warn("- NOT secure, the state value expired");
    return NextResponse.redirect(`${AppUrl}/login`);
  }

  if (
    authorizationState !== authorizationStateCookie.value &&
    codeVerifierCookie.value
  ) {
    console.warn("- NOT secure, the state value not found");
    return NextResponse.redirect(`${AppUrl}/login`);
  }

  const authorizationToken = await TropipayAuthInstance.GetAuthorizationToken(
    authorizationCode,
    codeVerifierCookie.value
  );
  
  const userProfile = await TropipayAuthInstance.GetProfile(
    authorizationToken.access_token,
    authorizationToken.token_type
  );

  console.log("userProfile-->", userProfile);

  /** IMPLEMENTAR LOGICA DE INICIO SESION **/

  if (authorizationToken && userProfile && originMode === "login") {
    const user = await getUserLoginByTropipay({
      email: userProfile.email,
      provider: "tropipay",
    });

    if (user && user.meta.length === 1) {
      const config = {
        path: "/",
        //httpOnly: true,
        maxAge: 7200, // 2 horas
      };
      // si el usuario no esta activo o cuenta blokeada
      if (!user.data[0].attributes.active || user.data[0].attributes.bloked) {
        return NextResponse.redirect(
          `${AppUrl}/error/403?message=account-blocked-contact-with-support`
        );
      }

      const payload = preparePayload(user.data[0].attributes);
      /* si la cuenta no se registro con tropipay no puede acceder hasta registrar o conectar con tropipay */
      if (!checkProvider(payload, "tropipay")) {
        return NextResponse.redirect(
          `${AppUrl}/error/403?message=you-nedd-use-a-valid-provider&provider=tropipay`
        );
      }

      const token = createAuthorizationToken(payload);

      const urltoToRedirect = `${AppUrl}${
        originUrl ? base64URLDecode(originUrl) : ""
      }`;

      const response = NextResponse.redirect(
        deleteWhiteSpaces(urltoToRedirect)
      );
      response.cookies.set("accessToken", token, config);
      return response;
    }
    if (user && user.meta.length === 0) {
      return NextResponse.redirect(`${AppUrl}/register?provider=tropipay`);
    }
  }

  /** IMPLEMENTAR LOGICA DE REGISTRO **/

  return NextResponse.redirect(AppUrl);
}

Tropipay Endpoints

const TropipayEndpoints = {
    tppServerUrl: process.env.TROPIPAY_SERVER,
    beneficiary: {
        create: "/api/v2/deposit_accounts",
        getAll: "/api/v2/deposit_accounts",
    },
    payment: {
        create: "/api/v2/paymentcards",
        mediation: {
            create: "/api/v2/paymentcards/mediation"
        },
    },
    movements: {
        list: "/api/v2/movements",
        get_rate: "/api/v2/movements/get_rate"
    },
    countries: {
        list: "/api/v2/countries",
        destinations: "/api/v2/countries/destinations"
    },
    users: {
        profile: "/api/users/profile",
    },
    hooks: {
        add: "/api/v2/hooks",
        list: "/api/v2/hooks",
        allow: {
            list: "/api/v2/hooks/events"
        }
    },
    access: {
        authorize: "/api/v2/access/authorize",
        token: "/api/v2/access/token"
    }
}
module.exports = TropipayEndpoints;

When Recive Error


Create a new Deposit Account https://tpp.stoplight.io/docs/tropipay-api-doc/6bc05a0be7e81-create-a-new-deposit-account 400 - THE SAME BENEFICIARY CANNOT BE THE MEDIATOR

    POST: https://tropipay-dev.herokuapp.com/api/v2/deposit_accounts
{
  "error": {
  "type": "VALIDATION_ERROR",
          "code": "VALIDATION_ERROR",
          "message": "The source and destination accounts cannot be the same",
          "details": [],
          "i18n": "Parámetros inválidos"
}
}

503 - When the vars is nor real or accepted tropipay send an error line this:

  - ready started server on 0.0.0.0:6006, url: http://localhost:6006 (on my case)
        - info Loaded env from *****\.env
- Tropipay Instance Created...
- event compiled client and server successfully
- wait compiling...
- Tropipay Instance Created...
- event compiled client and server successfully
- Error: Tropipay SDK has an error:  AxiosError: Request failed with status code 503
- Error: Could not obtain the access token from credentials  AxiosError: Request failed with status code 503
at Tropipay.Authorize function

{
  statusCode: 503,
          statusMessage: 'Service Unavailable',
        data: ''
}

Package Sidebar

Install

npm i sertropipay

Weekly Downloads

7

Version

1.3.8

License

ISC

Unpacked Size

73.9 kB

Total Files

14

Last publish

Collaborators

  • fiderosado