[![npm](https://github.com/credify-pte-ltd/credify-nodejs/actions/workflows/npm.yml/badge.svg)](https://github.com/credify-pte-ltd/credify-nodejs/actions/workflows/npm.yml)

# Credify NodeJS

## How to install

```shell script
# yarn
$ yarn add @credify/nodejs

# npm
$ npm install @credify/nodejs
```

## How to use

### Initialization

```javascript
const { Credify } = require("@credify/nodejs");
const signingPrivateKey = "";
const apiKey = "";
const config = {
  mode: "sandbox",
};
const credify = await Credify.create(signingPrivateKey, apiKey, config);
```

### Auth

#### `introspectToken`

This function validates an access token passed from Credify.
You need to pass the token and a specific scope to test its validity.

```javascript
const token =
  "eyJhbGciOiJSUzI1NiIsImtpZCI6InB1YmxpYzo4ZDA1NjJmNS0zMjI0LTQ1OGYtODBkZS01YjczNTdkMWUwMjIiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOltdLCJjbGllbnRfaWQiOiI4ZjUzMGRmNi05OGFhLTQ4NDktYmNhZi1kNjI3MDU0MzUyNjYiLCJleHAiOjE2MTcxOTA4MDUsImV4dCI6eyJlY29zeXN0ZW1faWQiOiI2MmZjNTcyNC0zNzUxLTQ3OTctYmU3OS02MDU2MzVmYTZjOTMifSwiaWF0IjoxNjE2NTg2MDA1LCJpc3MiOiJodHRwczovL2Rldi1vaWRjLWNvcmUuY3JlZGlmeS5vbmUvIiwianRpIjoiNzM5ZjY0MTQtY2I1MS00YmM5LTg5NzUtYjQ3Nzc0MWNiODBjIiwibmJmIjoxNjE2NTg2MDA1LCJzY3AiOlsib3JnYW5pemF0aW9uIiwib2lkY19jbGllbnQiLCJjbGFpbV9wcm92aWRlciJdLCJzdWIiOiI4ZjUzMGRmNi05OGFhLTQ4NDktYmNhZi1kNjI3MDU0MzUyNjYifQ.PODoedbtpiZ2Uwe5XNRbQTdMY6C4cSQVXqxlt0yaLJqNkjo6dYLPp6GvcbJmCfMCJAkTXK13_Il7Ojl4jkY9K2fJwsqdTpsKbw5A4HPl4snhBMBkUGBMud2DmAYRo7N_DLUX0YEAaQ91OKxlM7ddAcANbkx8M9MTgXNxN3UDBZKL8KaGiN7Szm1gKXqaaRxM0_pl96xxktpsbLO5uYKIlpzPp_4h5N-TAkChK9BLnXUjQRccphmtMFeUTf9br7kVyFKgewDWsyF_UAv7gegf7qY4TPYJb3WNmllnrVGglhSVug2xCczn90a_EyLscG2b7KwHobRrgxowtb-jcHfHuu7OHQG6LU75YyoXiiNzg6qVh4VDQJpiC3Z7rkQQaL9_JHXtq5sHPh7Y7TmozeIQhvaG93vXJXePEfGyqS2wXs_XYlSAtjZJ3ALo7qdbfbWO94EUyPg_hGIU3t3LYn1r8VUbVTNpjkfYbQnfnoZMBhuZ2lPcyNuXtdO73470RX2vKbU_eKo_jEPIVScOtnYlGOLnLyymTLVKgd_PrKckOycjqB-2yQ0o4fX3puSNvpHw4mrcPDOb0G7g35JL2tDyRCU7Arh22VEE6XclkPkQbbdvRImxXplH9grBhxN4t7DVM-LtYDNMW_RJWlOKcdDQJQgNbHPJCsZBby2FUp84Pvw";
const scope = "organization";
credify.auth
  .introspectToken(token, scope)
  .then((isValid) => console.log(isValid));
```

#### `verifyWebhook`

This function verifies Credify's webhook requests.

```javascript
const signature =
  "6UMc28mLwcYEQ_hhJABHhJxBcnWKHF-JP5FtqMa-LAVv59PlhxyyhTmeGgweFGSeB4c6z9yFdmZy-5YQKZYeDQ"; // You can find it in webhook HTTP request header.
const body = {
  transaction_id: "982c69c3-68d3-4804-99aa-2a3d0e28fd15",
  type: "OFFER_TRANSACTION_STATUS_UPDATED",
  transaction_status: "COMPLETED",
  credify_id: "e429d009-e2f5-4715-a051-d728e2876160",
  offer_code:
    "b-o-hi-m-tai-n-n-365---an-t-m-t-n-h--ng-s--b-o-v--to-n-di-n-housecare-1640095306",
};
const endpoint = "YOUR WEBHOOK ENDPOINT";
const eventId = "YOU CAN FIND IT IN WEBHOOK HTTP REQUEST HEADER";
const timestamp = "YOU CAN FIND IT IN WEBHOOK HTTP REQUEST HEADER";
```


### [Deprecated] Entity

#### `create`

This function generates a new user with a provided profile and password on the Credify system. The output is a new user's ID.

```javascript
const profile = {
  name: {
    first_name: "John",
    last_name: "Kane",
  },
  emails: [
    {
      email: "john.kane@credify.one",
    },
  ],
  phones: [
    {
      phone_number: "38123456789",
      country_code: "+84",
    },
  ],
};
const password = "Aa12345678!";
credify.entity.create(profile, password).then((id) => {
  console.log(id);
});
```


### Claims

#### `push`

This function records claim tokens into a blockchain. The claim tokens will be generated out of provided claim values.

```javascript
const organizationId = "";
const entityId = "";
const claims = {
  "your-scope-name-1": {
    "your-claim-name-1": "this-entity-claim-value",
    "your-claim-name-2": "this-entity-claim-value",
  },
  "your-scope-name-2": {
    "your-claim-name-3": "this-entity-claim-value",
    "your-claim-name-4": "this-entity-claim-value",
  },
};
credify.claims.push(organizationId, entityId, claims).then((res) => {
  console.log(res);
});
```

#### `pushDisbursementDocuments`

This records disbursement requirement's claim tokens into a blockchain. The claim tokens will be generated out of provided claim values. The disbursement claim object format is:

```javascript
const organizationId = "";
const entityId = "";
const claims = {
  "bnpl_order:[order-id]:invoice": {
    "bnpl_order:[order-id]:invoice": {
      content_type: "pdf",
      content: "base64",
    },
    "bnpl_order:[order-id]:invoice:commitment": "commitment",
  },
  "bnpl_order:[order-id]:delivery": {
    "bnpl_order:[order-id]:delivery": {
      content_type: "pdf",
      content: "base64",
    },
    "bnpl_order:[order-id]:delivery:commitment": "commitment",
  },
};
credify.claims.pushDisbursementDocuments(organizationId, entityId, claims).then((res) => {
  console.log(res);
});
```

#### `validateRequest`

This function validates `access token`, `request token`, and `approval token` to make sure the incoming request is legitimate. 

It returns a public key for encryption and scopes that a user has granted access for. 

```javascript
const accesstoken = "";
const requestToken = "";
const approvalToken = "";
credify.claims.validateRequest(accesstoken, requestToken, approvalToken).then((res) => {
  console.log(res.publicKey)
  console.log(res.scopes)
})
```

#### `encrypt`

This encrypts claim values with a passed encryption public key.

```javascript
const claims = {
  "your-scope-name-1": {
    "your-claim-name-1": "this-entity-claim-value",
    "your-claim-name-2": "this-entity-claim-value",
  },
  "your-scope-name-2": {
    "your-claim-name-3": "this-entity-claim-value",
    "your-claim-name-4": "this-entity-claim-value",
  },
};
const encryptionPublicKey = "";
credify.claims.encrypt(claims, encryptionPublicKey).then((res) => {
  console.log(res);
});
```


### Offer

#### `getList`

This function retrieves filtered offers list.

```javascript
const request: GetOfferRequest = {}
credify.offer.getList(request).then((res) => {
  console.log(res);
});
```

#### `updateStatus`

This updates status of a specified offer transaction.

```javascript
const id = "xxxx";
const request: OfferTransactionStatusUpdateRequest = {
  status: OnboardingStatus.complete
}
credify.offer.updateStatus(id, request).then((res) => {
  console.log(res);
});
```

If the `transactionAmount` is dynamic, you may pass `transactionAmount` to this function.

```javascript
const id = "xxxx";
const transactionAmount = { 
  currency: FiatCurrencyCurrencyEnum.JPY, 
  value: "100000" 
} as FiatCurrency;

const request: OfferTransactionStatusUpdateRequest = {
  onboardingStatus: OnboardingStatus.completed,
  transactionAmount: transactionAmount,
}
credify.offer.updateStatus(id, request).then((res) => {
  console.log(res);
});
```

If you have `referenceId`, you may pass `referenceId` to this function.

```javascript
const id = "xxxx";
const referenceId = "referenceId";
const request: OfferTransactionStatusUpdateRequest = {
  onboardingStatus: OnboardingStatus.completed,
  referenceId: referenceId,
}
credify.offer.updateStatus(id, request).then((res) => {
  console.log(res);
});
```

If the `vat` is dynamic, you may pass `vat` to this function.

```javascript
const id = "xxxx";
const status = "COMPLETED";
const vat = { 
  currency: FiatCurrencyCurrencyEnum.JPY, 
  value: "ABC" 
} as FiatCurrency;

const request: OfferTransactionStatusUpdateRequest = {
  onboardingStatus: OnboardingStatus.completed,
  vat: vat,
}
credify.offer.updateStatus(id, request).then((res) => {
  console.log(res);
});
```

#### [Deprecated] `getCampaigns`

This returns a list of campaign list.

```javascript
const offerStatus = "APPROVED"; // APPROVED || REJECTED || IN_REVIEW
const campaignStatus: "APPROVED"; // APPROVED || REJECTED || IN_REVIEW || ARCHIVED || DRAFT
credify.offer.getCampaigns(offerStatus, campaignStatus).then((res) => {
  console.log(res);
});
```

#### `getOfferDetail`

This function returns detail information of a specified offer.

```javascript
const offerCode = "";
credify.offer.getOfferDetail(offerCode).then((res) => {
  console.log(res);
});
```

#### [Deprecated] `evaluateOffer`

This function evaluates an offer based on conditions and required scopes.

```javascript
// prepare claims for the user, could be read from database for example
const claims: Claims = {
  scope1: {
    claim1: 2.0,
  },
};

// offer data if from payload of offer filtering API or offer evaluation API
const condition: OfferCondition = {
  kind: OfferConditionKind.InRangeCondition,
  claim: {
    name: "claim1",
    valueType: "FLOAT",
    scope: {
      name: "scope1",
    },
  },
  value: 1.0,
  upper: 3.0,
};

const requiredScopes = [["scope1"], ["scope2"]];
// evaluate the offer based on conditions and required scopes
const result = credify.offer.evaluateOffer([condition], requiredScopes, claims);
```

#### [Deprecated] `getBNPLInfo`

This function loads BNPL information.

```javascript
const orgId = ""
const options = {
  phoneNumber: "0381231234",
  countryCode: "+84",
}
credify.offer.getBNPLInfo(orgId, options).then((res) => {
  console.log(res.isAvailable)
  console.log(res.offers)
  console.log(res.providers)
})
```

#### `simulate`

This simulates a loan offer based on inputs.

```javascript
const productType = "insurance:health-insurance:for-individual";
const providerIds = [];
const inputs = {
  marketId: "7add92a8-dfa5-4a41-9ce0-b08d4e8bae51",
  transactionAmount: {
    value: "25689000",
    currency: "VND",
  },
  loanTenor: {
    value: 100000,
    unit: 1,
  },
  downPayment: {
    value: "100000",
    currency: "VND",
  },
  disbursementDate: "2022-09-12",
  product: {
    manufacturer: "DTGK",
    category: "PHONE",
    name: "Phone",
  },
};
const request: SimulationRequest = {
  providerIds: providerIds,
  inputs: inputs
}

credify.offer.simulate(productType, request).then((response) => {
  console.log(response);
});
```

#### `queryProducts`

This function help to query products by provided conditions.

```javascript
const productType = "insurance:health-insurance:for-individual";
const productCodes = [];
const providerIds = [];
const bnpl = {
  itemCategory: "BNPL",
  itemCount: 100,
  totalAmount: {
    value: "1000000",
    currency: "VND",
  },
};
const phone = {
  countryCode: "+84",
  phoneNumber: "332522944"
}
const payload = {
  productType,
  productCodes,
  providerIds,
  bnpl,
  phone
}

credify.offer.queryProducts(payload).then((response) => {
  console.log(response);
});
```


### OIDC

#### `initiateOIDC`

This function generates OIDC auth URL. If you enable a flag `useEphemeralKey`, this function also generates a temporary encryption key. Otherwise, this function uses your static encryption key.

```javascript
const organizationId = "";
const redirectUrl = "";
const scopes = ["openid", "phone", "email"];
const options = {
  userId: "",
  offerCode: "",
  phoneNumber: "+84381234567"
};
credify.oidc
  .initiateOIDC(organizationId, redirectUrl, scopes, options)
  .then((res) => {
    console.log(`OIDC URL >>> ${res.oidcUrl}`);
    // This should be empty in this option configuration.
    // If you set `options.useEphemeralKey = true`, this private key will be returned.
    console.log(`Private key >>> ${res.privateKey}`);
  });
```

#### `generateAccessToken`

This manages OpenID Connect token API, generating a new access token from an authorization code. This is a helper function when you use an authorization flow.

```javascript
const id = "YOUR ID";
const code = "AUTHORIZATION CODE";
const redirectUrl = "YOUR REDIRECTION URL";
credify.oidc.generateAccessToken(id, code, redirectUrl).then((response) => {
  console.log(response);
});
```

#### `userinfo`

This manages OpenID Connect userinfo API. This needs either a static key or an ephemeral private key that is generated in the above step, and returns decrypted user information. Note that `private key` needs to be base64 URL encoded string value.

```javascript
const accessToken = "";
const privateKeyInBase64Url = "";
credify.oidc.userinfo(accessToken, privateKeyInBase64Url).then((userinfo) => {
  console.log(userinfo);
});
```


### BNPL

#### `lodgeNewIntent`

This creates a new intent.

```javascript
const payload: LodgingRequest = {
  type: "BNPL",
  user: {
    id: "123",
    phone: {
      countryCode: "+84",
      phoneNumber: "987443948"
    }
  },
  bnplOrder: {
    referenceId: "1112",
    totalAmount: {
      value: 10.2,
      currency: "VND",
    },
    orderLines: [
      {
        name: "orderLineName",
        referenceId: "2222",
        imageUrl: "string",
        productUrl: "string",
        quantity: "10",
        unitPrice: {
          value: 2.3,
          currency: "VND",
        },
        subtotal: {
          value: 4.2,
          currency: "VND",
        },
        measurementUnit: "EA",
        category: "MOBILE_DEVICE"
      },
    ],
    paymentRecipient: {
      type: "BANK_ACCOUNT",
      name: "bank_name",
      number: "213232323",
      branch: "bank_branch",
      bank: "bank_bank",
    }
  },
  service: {
    availableOfferCodes: [
      "qa-qc-bnpl-consumer-1669110282",
      "test--bnpl-consumer-1664968896"
    ],
    availableProductCodes: [
      "product-for-demo1"
    ],
    packageCode: "3",
    offerCode: "qa-qc-bnpl-consumer-1669110282",
  }
}

const result = await c.intent.lodgeNewIntent(payload);
```

#### [Deprecated]`createOrder`

This creates a BNPL order

```javascript
const referenceId = "1112";
const totalAmount = { value: 1000000, currency: "VND" };
const orderLines = [
  {
    name: "orderLineName",
    referenceId: "2222",
    imageUrl: "string",
    productUrl: "string",
    quantity: "10",
    unitPrice: {
      value: 200000,
      currency: "VND", // "VND" || "USD" || "JPY"
    },
    subtotal: {
      value: 800000,
      currency: "VND", // "VND" || "USD" || "JPY"
    },
    measurementUnit: "EA",
  },
];
const paymentRecipient = {
  type: "BANK_ACCOUNT",
  name: "bank_name",
  number: "213232323",
  branch: "bank_branch",
  bank: "bank_bank",
};

const result = await c.bnpl.createOrder(
  referenceId,
  totalAmount,
  orderLines,
  paymentRecipient
);
```

#### `getOrders`

This retrieves a list of BNPL orders

```javascript
const credifyId = "6eab7d5b-1d47-451c-91d7-d2a26713ef14";
const data = await c.bnpl.getOrders(credifyId);
```

#### `getOrder`

This retrieves a BNPL order's information

```javascript
const orderId = "6eab7d5b-1d47-451c-91d7-d2a26713ef14";
const data = await c.bnpl.getOrder(orderId);
```

#### `acknowledgeOrder`

This acknowledges a BNPL order is received at the lender side

```javascript
const transactionId = "6eab7d5b-1d47-451c-91d7-d2a26713ef14";
const orderId = "6eab7d5b-1d47-451c-91d7-d2a26713ef14";
const data = await c.bnpl.acknowledgeOrder(transactionId, orderId);
```

#### `approveOrder`

This approves a BNPL order's information

```javascript
const orderId = "6eab7d5b-1d47-451c-91d7-d2a26713ef14";
const messageInfo = {
  name: "John Doe",
  email: "john.doe@gmail.com",
  phone: {
    phoneNumber: "0381234123",
    countryCode: "+84"
  }
};
const data = await c.bnpl.approveOrder(orderId, messageInfo);
```

#### `completeSigning`

This is called when signing a BNPL contract is done

```javascript
const orderId = "6eab7d5b-1d47-451c-91d7-d2a26713ef14";
const terms = {
  contractNumber: "1234567",
  repaymentDuration: {
    value: 20,
    unit: "DAY", // "UNKNOWN" || "DAY" || "MONTH" || "YEAR"
  },
  repaymentInterval: {
    value: 20,
    unit: "DAY", // "UNKNOWN" || "DAY" || "MONTH" || "YEAR"
  },
  principalAmount: {
    value: "1000000",
    currency: "VND", // "VND" || "USD" || "JPY"
  },
  downPayment: {
    value: "100000",
    currency: "VND", // "VND" || "USD" || "JPY"
  },
  fee: {
    value: "10000",
    currency: "VND", // "VND" || "USD" || "JPY"
  },
  apr: "5.6",
  overduePenaltyRate: "0.2",
  accountNumber: "1234567",
  creditLimit: {
    value: "105000",
    currency: "VND", // "VND" || "USD" || "JPY"
  },
  availableCredit: {
    value: "105000",
    currency: "VND", // "VND" || "USD" || "JPY"
  }
}
const data = await c.bnpl.completeOrder(orderId, terms);
```

#### `completeOrder`

This completes a BNPL order

```javascript
const orderId = "6eab7d5b-1d47-451c-91d7-d2a26713ef14";
const valueDate = "2019-08-24T14:15:22Z"

const data = await c.bnpl.completeOrder(
  orderId,
  valueDate
);
```

#### `revertPayment`

This reverts a BNPL payment

```javascript
const orderId = "6eab7d5b-1d47-451c-91d7-d2a26713ef14";
const failedReason = "User doesn't satisfy requirements"

const data = await c.bnpl.revertPayment(orderId, failedReason);
```

#### `disbursement`

When all disbursement requirements are fulfilled (the fulfilled notification will be sent via the disbursement status's webhook). We will call this API for making a disburse request

```javascript
const orderId = "6eab7d5b-1d47-451c-91d7-d2a26713ef14";

const data = await c.bnpl.disbursement(orderId);
```
