In FirstPromoter, you can embed the entire promoter dashboard inside your website and automatically log your promoters in without requiring them to enter an email or password.
*Please note:
The set-up requires a developer to assist.
This requires you to set up a custom domain on FirstPromoter and also be on the Business plan or above. The instructions can be found here.
To log the promoter in, you need to make an API request to get an access token and use that in logging your promoter in via the iframe. Below are the steps to follow:
Steps to implement
1. Get your API credentials
Grab your Account ID and API Key from your "Settings" > "Integrations" page > "Manage API Keys". You'll need both for authentication.
Please do not use the legacy v1 keys. Click on Manage API Keys and create a new key
2. Make the API request
To avoid exposing your API credentials, make a POST request on the backend of your application to https://v2.firstpromoter.com/api/v2/promoters/iframe_login?promoter_id=xxxxx
where xxxxx is the promoter_id.
URL:
https://v2.firstpromoter.com/api/v2/promoters/iframe_login?promoter_id=xxxxx
Method: POST
Headers:
Authorization: Bearer {your_api_key}
Account-Id: {your_account_id}
Body: Empty (promoter_id is passed in the URL)
1. Grab your API key from your "Settings" > "Integrations" page and set it in the header asX-API-KEY
.
How do I get the promoter id?
You can get the promoter id
:
a) When you create the Promoter via the API you'll get in the JSON response the id
value in the response. Save the "id" to the corresponding user object on your system.
b) When you create the promoter via the API you can pass the user id from your system as the cust_id
parameter. This will be saved as a field and can be used to query FirstPromoter to get the promoter details as shown here. In the response you can grab the ID of the promoter and use in making your request.
c) From the promoter_accepted
webhook. If you don't handle the Promoter creation using the API, you can still get the id
from the webhook notification we send you when a promoter signs up from our sign up form. You will need to save the "id" somewhere in your system.
3. Handle the API response
The POST request will return a response with the access token and an expiration time:
{
"access_token": "xxxxxxxxxxxxxxx",
"expires_in": 86400
}
4. Create the iframe
Create an iframe on your page and grab the "access_token" from the response, return it to your Frontend and set iframe src as https://<yourcustom.domain.com>/iframe?tk={{access_token}}
.
Your full iframe code should look like this:
<iframe allow="clipboard-write" height="850px" width="100%" frameborder="0" src="https://<yourcustom.domain.com>/iframe?tk={{access_token}}"></iframe>
IMPORTANT: Make sure the iframe is added inside a protected area of your website that is not accessible to search engines or the public. The token expires after 24 hours, so it is best to fetch the token on every page refresh.
Code Examples
Below are some examples of how your code will look like:
BACKEND
BACKEND
Node
//node backend
var express = require("express");
var axios = require("axios");
var app = express();
var bodyParser = require("body-parser");
var cors = require('cors');
app.use(bodyParser.json());
app.use(cors());
app.post("/fp-iframe-login", function (req, res) {
var promoter_id = req.body.promoter_id;
var accountId = "your_account_id"; // Replace with your account ID
var apiKey = "your_api_key"; // Replace with your API key
console.log("Requesting iframe login for promoter:", promoter_id);
axios
.post(
`https://v2.firstpromoter.com/api/v2/promoters/iframe_login?promoter_id=${promoter_id}`,
{},
{
headers: {
"Authorization": `Bearer ${apiKey}`,
"Account-Id": accountId
}
}
)
.then(function (response) {
res.send(response.data.access_token);
})
.catch(function (error) {
console.log("Error occurred:", error.response?.data || error.message);
res.status(500).send("Authentication failed");
});
});
PHP
// php backend
<?php
$apiKey = "your_api_key"; // Replace with your API key
$accountId = "your_account_id"; // Replace with your account ID
// Create a new HTTP client
$client = new GuzzleHttp\Client();
// Handle POST request on /fp-iframe-login route
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $_SERVER['REQUEST_URI'] === '/fp-iframe-login') {
$input = json_decode(file_get_contents('php://input'), true);
$promoterID = $input['promoter_id'];
$url = 'https://v2.firstpromoter.com/api/v2/promoters/iframe_login?promoter_id=' . $promoterID;
$headers = [
'Authorization' => 'Bearer ' . $apiKey,
'Account-Id' => $accountId
];
try {
$response = $client->post($url, ['headers' => $headers]);
$data = json_decode($response->getBody()->getContents(), true);
echo $data['access_token'];
} catch (Exception $e) {
http_response_code(500);
echo "Authentication failed";
}
exit;
}
?>
FRONTEND
FRONTEND
React
//react frontend
import React, { useState, useEffect } from 'react';
import axios from 'axios';
function MyIframeComponent() {
const [loading, setLoading] = useState(true);
const [loadingError, setLoadingError] = useState(false);
const [accessToken, setAccessToken] = useState(null);
useEffect(() => {
axios.post('http://localhost:3000/fp-iframe-login', { promoter_id: 7497107 })
.then((response) => {
setAccessToken(response.data);
})
.catch((error) => {
console.log(error);
setLoadingError(true);
})
.finally(() => {
setLoading(false);
});
}, []);
return (
<div>
{loading || loadingError ? (
<div>
{loading ? <div>Loading the iframe</div> : null}
{loadingError ? <div>Oops, there seems to have been a problem</div> : null}
</div>
) : (
<iframe
height="850px"
width="100%"
frameBorder="0"
allow="clipboard-write"
src={`https://mycustom.domain.com/iframe?tk=${accessToken}`}
/>
)}
</div>
);
}
export default MyIframeComponent;
Vue
\\ vue frontend
<template>
<div>
<div v-if="loadingError || loading">
<div v-if="loading">Loading the iframe</div>
<div v-if="loadingError">Oops there seems to have been a problem</div>
</div>
<iframe
v-else
height="850px"
width="100%"
frameborder="0"
allow="clipboard-write"
:src="`https://mycustom.domain.com/iframe?tk=${accessToken}`"
/>
</div>
</template>
<script setup>
import { onBeforeMount, ref } from 'vue'
import axios from 'axios'
const loading = ref(true)
const loadingError = ref(false)
const accessToken = ref(null)
onBeforeMount(() => {
axios
.post('http://localhost:3000/fp-iframe-login', { promoter_id: 7497107 })
.then((response) => {
accessToken.value = response.data
})
.catch((error) => {
console.log(error)
loadingError.value = true
})
.finally(() => {
loading.value = false
})
})
</script>
Angular
//angular
import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-my-component',
template: `
<div>
<div *ngIf="loadingError || loading">
<div *ngIf="loading">Loading the iframe</div>
<div *ngIf="loadingError">Oops, there seems to have been a problem</div>
</div>
<iframe
*ngIf="!loading && !loadingError"
height="850px"
width="100%"
frameborder="0"
allow="clipboard-write"
[src]="iframeSrc"
>
</iframe>
</div>
`,
})
export class MyIframeComponent implements OnInit {
loading = true;
loadingError = false;
accessToken: string | null = null;
iframeSrc = '';
constructor(private http: HttpClient) {}
ngOnInit(): void {
this.http
.post<string>('http://localhost:3000/fp-iframe-login', { promoter_id: 7497107 })
.subscribe({
next: (response) => {
this.accessToken = response;
this.iframeSrc = `https://mycustom.domain.com/iframe?tk=${this.accessToken}`;
},
error: (error) => {
console.log(error);
this.loadingError = true;
},
complete: () => {
this.loading = false;
}
});
}
}
JavaScript
<!DOCTYPE html>
<html>
<head>
<title>FirstPromoter Dashboard Embed</title>
</head>
<body>
<div id="container">
<!-- iframe will be rendered here -->
</div>
<script>
const container = document.getElementById('container');
let loading = true;
let loadingError = false;
let accessToken = null;
// Show loading state
renderLoading();
fetch('http://backend/fp-iframe-login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ promoter_id: 7497107 })
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.text();
})
.then(data => {
accessToken = data;
renderIframe();
})
.catch(error => {
console.log(error);
loadingError = true;
renderError();
})
.finally(() => {
loading = false;
});
function renderIframe() {
container.innerHTML = '';
const iframe = document.createElement('iframe');
iframe.height = '850px';
iframe.width = '100%';
iframe.frameBorder = '0';
iframe.allow = 'clipboard-write';
iframe.src = `https://mycustom.domain.com/iframe?tk=${accessToken}`;
container.appendChild(iframe);
}
function renderError() {
container.innerHTML = '';
const errorDiv = document.createElement('div');
errorDiv.textContent = 'Oops, there seems to have been a problem';
container.appendChild(errorDiv);
}
function renderLoading() {
container.innerHTML = '';
const loadingDiv = document.createElement('div');
loadingDiv.textContent = 'Loading the iframe';
container.appendChild(loadingDiv);
}
</script>
</body>
</html>