Skip to main content

Add melio as a page

Add one or multiple Melio products as pages inside your app.
Your users can make payments without leaving your APP and staying in context.

This guide will help you add a pay bills page to your application by following these steps:

  1. Configure Seamless OAuth flow
  2. Issue OAuth authorization code
  3. Implement onboarding backend endpoints
  4. Embed Melio in a pay bills page

Requirements:

  • Have a working OAuth/OIDC process already working in your app

Configure Seamless OAuth flow

First we'll configure the endpoints that Melio needs to call to get your user's information.

  • Log in to our Partner Portal using the credentials provided to you.
  • Go to the SSO configuration section and set the following:
    • a url to your token endpoint
    • any additional properties we should send (usually client_id, client_secret and scope) to the token endpoint
    • a url to your server to get account info for the authenticated user (we will dive into it later in step 3)
  • Go to the App setting section and retrieve your partnerName

Issue OAuth authorization code

For your users to seamlessly authenticate with melio, your server needs to generate an Authorization Code. You will then append that code to Melio's auth callback url and embed the combined url in an iframe in your app.

To get a better understanding of what needs to be done, we provide a few example codes for common frameworks:

// This snippet is not a fully working example, and would not work as is, you must adopt it
import * as oidc from "oidc-provider";
import express from "express";

const provider = new oidc.Provider("http://localhost:3000", {
// refer to the documentation for other available configuration
clients: [
{
client_id: "melio",
client_secret: "<secret>",
},
],
});

async function issueCode(userAccountId) {
const client = await provider.Client.find("melio");

const code = new provider.AuthorizationCode({
accountId: userAccountId,
client,
scope: "openid",
expiresWithSession: false,
});

const savedCode = await code.save();

return savedCode;
}
const app = express();
app.get("/issue-token-for-melio", async (req, res) => {
// in express it is common to put the authenticated user in req
const code = await issueCode(req.user);
res.send({
code,
});
});
app.listen(3000, () => {
console.log(`App listening on port ${port}`);
});
info

For additional information regarding the sso flow, and why we aren't doing a full oauth authentication, please refer to the seamless SSO section in resources.

Implement onboarding backend endpoints

Once authentication is complete, we will use the access_token provided by your oauth server to call an api to get user and company info.
The accountInfo url you provided in step 1 should return information about the user and company associated with the access_token, consult the accountInfo api to see what data is mandatory and what we can gather from the user for you during the melio experience.

Here's an example of a server returning a valid response:

import express from "express";

async function issueCode(userAccountId) {
const client = await provider.Client.find("melio");

const code = new provider.AuthorizationCode({
accountId: userAccountId,
client,
scope: "openid",
expiresWithSession: false,
});

const savedCode = await code.save();

return savedCode;
}
const app = express();
app.get("/account-info", async (req, res) => {
// you must be able to translate the access-token to a specific company,
// if a user can have more than one company, the access token must be for a single company
const { user, company } = await getUserAndCompanyFromAccessToken(
req.headers.Authorization,
);
const responsePayload = {
user: {
id: user.id, // the user's id on your system, needs to be unique and consistant
// the following details should be taken from user object, but are provided hardcoded as an example
email: "john.doe@example.com",
firstName: "John",
lastName: "Doe",
phone: "+1-555-123-4567",
dateOfBirth: "1985-03-15",
},
company: {
id: company.id, // the company's id on your system, needs to be unique and consistant
// the following details should be taken from user object, but are provided hardcoded as an example
name: "Acme Corporation",
legalName: "Acme Corporation LLC",
phoneNumber: "+1-555-987-6543",
businessType: "LLC",
address: {
state: "CA",
line1: "123 Main Street",
city: "San Francisco",
postalCode: "94105",
},
legalAddress: {
state: "CA",
line1: "123 Main Street",
city: "San Francisco",
postalCode: "94105",
},
taxInfo: {
identifier: "12-3456789",
type: "EIN",
},
industry: {
naicsCode: 722511,
name: "Full-Service Restaurants",
},
},
};
res.json(responsePayload);
});
app.listen(3000, () => {
console.log(`App listening on port ${port}`);
});
info

We also support and encourage sharing existing bank-account data. This is done using a different url endpoint - the funding source url

Embed Melio in a pay bills page

Finally just embed melio's iframe inside your app when a user clicks on the page in the navbar

<!DOCTYPE html>
<html>
<head>
<script src="https://partners-cdn.melio.com/sdk/embedding-sdk/latest.js" />
<script type="javascript">
async function onClickBillPay() {
const code = await fetch('/issue-token-for-melio');
const myPartnerName = 'partner name from configuration in step 1';
const iframe = document.createElement('iframe');
iframe.src = `https://sandbox.melio.com/${myPartnerName}/auth?token=${code}`;
iframe.style.border = 'none';
document.getElementById('main-content')?.appendChild(iframe);
}
</script>
<style>
body,
html {
height: 100vh;
width: 100vw;
}
#melio-iframe-container {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<header>...Your app's header and navigation</header>
<div id="main-content"></div>
</body>
</html>