curl --request POST \
--url https://api.nextlevelmca.com/v1/deals/{dealId}/portal-link \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"person_id": "<string>",
"send_via": "none",
"message": "<string>",
"expires_in_days": 15.5
}
'import requests
url = "https://api.nextlevelmca.com/v1/deals/{dealId}/portal-link"
payload = {
"person_id": "<string>",
"send_via": "none",
"message": "<string>",
"expires_in_days": 15.5
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
person_id: '<string>',
send_via: 'none',
message: '<string>',
expires_in_days: 15.5
})
};
fetch('https://api.nextlevelmca.com/v1/deals/{dealId}/portal-link', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.nextlevelmca.com/v1/deals/{dealId}/portal-link",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'person_id' => '<string>',
'send_via' => 'none',
'message' => '<string>',
'expires_in_days' => 15.5
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.nextlevelmca.com/v1/deals/{dealId}/portal-link"
payload := strings.NewReader("{\n \"person_id\": \"<string>\",\n \"send_via\": \"none\",\n \"message\": \"<string>\",\n \"expires_in_days\": 15.5\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.nextlevelmca.com/v1/deals/{dealId}/portal-link")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"person_id\": \"<string>\",\n \"send_via\": \"none\",\n \"message\": \"<string>\",\n \"expires_in_days\": 15.5\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.nextlevelmca.com/v1/deals/{dealId}/portal-link")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"person_id\": \"<string>\",\n \"send_via\": \"none\",\n \"message\": \"<string>\",\n \"expires_in_days\": 15.5\n}"
response = http.request(request)
puts response.read_body{
"data": {
"url": "<string>",
"expires_at": "<string>",
"sent": true,
"sent_via": "email",
"sent_to": "<string>",
"person_id": "<string>",
"business_id": "<string>",
"deal_id": "<string>"
},
"meta": {}
}{
"error": {
"type": "validation_error",
"message": "<string>",
"request_id": "<string>",
"code": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "validation_error",
"message": "<string>",
"request_id": "<string>",
"code": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "validation_error",
"message": "<string>",
"request_id": "<string>",
"code": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "validation_error",
"message": "<string>",
"request_id": "<string>",
"code": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "validation_error",
"message": "<string>",
"request_id": "<string>",
"code": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "validation_error",
"message": "<string>",
"request_id": "<string>",
"code": "<string>",
"param": "<string>"
}
}Create or send a merchant portal link
Issues the deal’s merchant-portal magic link (scoped to the business, so it covers all of its deals) and optionally sends it. Links last 24 hours — expires_in_days is accepted but ignored in v1; the portal lets the merchant request a fresh link, and calling this again before expiry returns the same link. send_via: "sms" needs a contact linked to the CRM; "email" falls back to the location’s connected mailbox. When the send step fails the link is still returned with sent: false and meta.warning. Anyone holding the link can view shared offers and upload documents, so treat it like a credential.
curl --request POST \
--url https://api.nextlevelmca.com/v1/deals/{dealId}/portal-link \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"person_id": "<string>",
"send_via": "none",
"message": "<string>",
"expires_in_days": 15.5
}
'import requests
url = "https://api.nextlevelmca.com/v1/deals/{dealId}/portal-link"
payload = {
"person_id": "<string>",
"send_via": "none",
"message": "<string>",
"expires_in_days": 15.5
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
person_id: '<string>',
send_via: 'none',
message: '<string>',
expires_in_days: 15.5
})
};
fetch('https://api.nextlevelmca.com/v1/deals/{dealId}/portal-link', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.nextlevelmca.com/v1/deals/{dealId}/portal-link",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'person_id' => '<string>',
'send_via' => 'none',
'message' => '<string>',
'expires_in_days' => 15.5
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.nextlevelmca.com/v1/deals/{dealId}/portal-link"
payload := strings.NewReader("{\n \"person_id\": \"<string>\",\n \"send_via\": \"none\",\n \"message\": \"<string>\",\n \"expires_in_days\": 15.5\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.nextlevelmca.com/v1/deals/{dealId}/portal-link")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"person_id\": \"<string>\",\n \"send_via\": \"none\",\n \"message\": \"<string>\",\n \"expires_in_days\": 15.5\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.nextlevelmca.com/v1/deals/{dealId}/portal-link")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"person_id\": \"<string>\",\n \"send_via\": \"none\",\n \"message\": \"<string>\",\n \"expires_in_days\": 15.5\n}"
response = http.request(request)
puts response.read_body{
"data": {
"url": "<string>",
"expires_at": "<string>",
"sent": true,
"sent_via": "email",
"sent_to": "<string>",
"person_id": "<string>",
"business_id": "<string>",
"deal_id": "<string>"
},
"meta": {}
}{
"error": {
"type": "validation_error",
"message": "<string>",
"request_id": "<string>",
"code": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "validation_error",
"message": "<string>",
"request_id": "<string>",
"code": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "validation_error",
"message": "<string>",
"request_id": "<string>",
"code": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "validation_error",
"message": "<string>",
"request_id": "<string>",
"code": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "validation_error",
"message": "<string>",
"request_id": "<string>",
"code": "<string>",
"param": "<string>"
}
}{
"error": {
"type": "validation_error",
"message": "<string>",
"request_id": "<string>",
"code": "<string>",
"param": "<string>"
}
}Authorizations
API key (nlmca_live_…) or OAuth access token
Path Parameters
Deal id
Body
Person to send the link to. Defaults to the deal’s primary owner, then the business’s primary contact. Ignored when send_via is none.
email sends through the CRM conversation when the contact is linked to the CRM, else through the location’s connected mailbox. sms texts through the CRM conversation (contact must be linked to the CRM). none only returns the link.
email, sms, none Message to send. {{link}} is replaced with the URL; when absent the link is appended. Defaults to a short note with the link.
2000Accepted for forward compatibility but ignored: portal links always last 24 hours and the portal lets the merchant request a fresh one.
1 <= x <= 30Was this page helpful?