curl --request POST \
--url https://api.novatrade24.com/v1/partners/{sellerId}/buyers/{buyerId}/contacts \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"firstName": "<string>",
"lastName": "<string>",
"email": "[email protected]",
"phone": "<string>"
}
'import requests
url = "https://api.novatrade24.com/v1/partners/{sellerId}/buyers/{buyerId}/contacts"
payload = {
"firstName": "<string>",
"lastName": "<string>",
"email": "[email protected]",
"phone": "<string>"
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
firstName: '<string>',
lastName: '<string>',
email: '[email protected]',
phone: '<string>'
})
};
fetch('https://api.novatrade24.com/v1/partners/{sellerId}/buyers/{buyerId}/contacts', 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.novatrade24.com/v1/partners/{sellerId}/buyers/{buyerId}/contacts",
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([
'firstName' => '<string>',
'lastName' => '<string>',
'email' => '[email protected]',
'phone' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"Idempotency-Key: <idempotency-key>"
],
]);
$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.novatrade24.com/v1/partners/{sellerId}/buyers/{buyerId}/contacts"
payload := strings.NewReader("{\n \"firstName\": \"<string>\",\n \"lastName\": \"<string>\",\n \"email\": \"[email protected]\",\n \"phone\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
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.novatrade24.com/v1/partners/{sellerId}/buyers/{buyerId}/contacts")
.header("Idempotency-Key", "<idempotency-key>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"firstName\": \"<string>\",\n \"lastName\": \"<string>\",\n \"email\": \"[email protected]\",\n \"phone\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.novatrade24.com/v1/partners/{sellerId}/buyers/{buyerId}/contacts")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"firstName\": \"<string>\",\n \"lastName\": \"<string>\",\n \"email\": \"[email protected]\",\n \"phone\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"firstName": "<string>",
"lastName": "<string>",
"email": "[email protected]",
"phone": "<string>",
"createdAt": "2023-11-07T05:31:56Z",
"notApplied": [
"lastName"
]
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>",
"traceId": "<string>"
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>",
"traceId": "<string>"
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>",
"traceId": "<string>"
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>",
"traceId": "<string>"
}Add a contact person to the buyer.
Personal data. Accepted for any buyer this seller can reach, including
one reached through a shared KYC result: the platform holds one KYC
record per buyer, and every party to it may add a contact person. The
contact is then visible to all of them. A {buyerId} this seller cannot
reach is 404 before the body is read.
Retry-safe without a replay cache: the contact is keyed on its email
address, compared trimmed and case-insensitively, so a repeated create
returns the same uuid rather than a second row.
The Integration API follows the same membership rules as the platform.
A person archived at this buyer and named again is reactivated, not
recorded a second time: the 201 carries the uuid they had, and the
contact returns to the status it had before it was archived. It keeps
the owner role only when the buyer has no owner and you may name one,
the same rule as for a new contact; otherwise it comes back as a
contact. One person holds one contact per company. A person with a
platform account
whom the company removed can only return through the company’s
re-invite, and naming them answers 409. A person whose removal is
pending is used as they are, and the pending request is left for the
company’s owners. Until 1.5.0-draft this recorded an archived person
again under a new uuid.
Where your body names a different person under an address already
recorded, the call resolves to the person on file and the 201 names
the differing fields in notApplied. Read it: a call that meant to
record a second director on a shared info@ and got
notApplied: ["firstName", "lastName"] recorded nobody, and the uuid
it got back belongs to somebody else.
Drift is reported rather than refused because the record is shared.
Every partner holding this buyer’s KYC result reads these people and may
add one, and Novatrade24 corrects a stored name or telephone number
after a marriage, a typo or a changed number — so your unchanged body
would otherwise be refused for good through no act of yours, and this
API has no PATCH to clear it with. notApplied describes your
request, not the resource.
Nothing is ever applied here: a stored contact person is never overwritten. To correct one, ask Novatrade24 support.
role asks for the person’s account permission on the platform:
OWNER (Admin) or CONTACT (Member). The rules are the platform’s.
OWNER is granted while the buyer has no Admin and this seller holds
the buyer’s KYC, its own request or an active shared KYC result; otherwise the person is recorded
or resolved as a Member, or left as they are, and notApplied names
role. CONTACT keeps the person a Member even where they would
otherwise become the Admin, and brings a removed person back as a
Member. A current Admin is never made a Member through this API; the company’s Admins or Novatrade24 do that on the platform.
Without role, the person becomes the Admin under the same rule as
OWNER, as before. The role is not the person the identity check is
about, which follows its own rule whatever you ask for.
curl --request POST \
--url https://api.novatrade24.com/v1/partners/{sellerId}/buyers/{buyerId}/contacts \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"firstName": "<string>",
"lastName": "<string>",
"email": "[email protected]",
"phone": "<string>"
}
'import requests
url = "https://api.novatrade24.com/v1/partners/{sellerId}/buyers/{buyerId}/contacts"
payload = {
"firstName": "<string>",
"lastName": "<string>",
"email": "[email protected]",
"phone": "<string>"
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
firstName: '<string>',
lastName: '<string>',
email: '[email protected]',
phone: '<string>'
})
};
fetch('https://api.novatrade24.com/v1/partners/{sellerId}/buyers/{buyerId}/contacts', 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.novatrade24.com/v1/partners/{sellerId}/buyers/{buyerId}/contacts",
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([
'firstName' => '<string>',
'lastName' => '<string>',
'email' => '[email protected]',
'phone' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"Idempotency-Key: <idempotency-key>"
],
]);
$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.novatrade24.com/v1/partners/{sellerId}/buyers/{buyerId}/contacts"
payload := strings.NewReader("{\n \"firstName\": \"<string>\",\n \"lastName\": \"<string>\",\n \"email\": \"[email protected]\",\n \"phone\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
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.novatrade24.com/v1/partners/{sellerId}/buyers/{buyerId}/contacts")
.header("Idempotency-Key", "<idempotency-key>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"firstName\": \"<string>\",\n \"lastName\": \"<string>\",\n \"email\": \"[email protected]\",\n \"phone\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.novatrade24.com/v1/partners/{sellerId}/buyers/{buyerId}/contacts")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"firstName\": \"<string>\",\n \"lastName\": \"<string>\",\n \"email\": \"[email protected]\",\n \"phone\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"firstName": "<string>",
"lastName": "<string>",
"email": "[email protected]",
"phone": "<string>",
"createdAt": "2023-11-07T05:31:56Z",
"notApplied": [
"lastName"
]
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>",
"traceId": "<string>"
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>",
"traceId": "<string>"
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>",
"traceId": "<string>"
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>",
"traceId": "<string>"
}Authorizations
OAuth 2.0 client_credentials grant via Keycloak service account.
Clients are provisioned per IntegrationOrganization in the
nt24-idp realm.
Headers
Client-generated unique key (UUID recommended) for this write operation.
Identical key + identical body within 24h returns the cached response.
Identical key + different body returns 422.
1 - 255Optional purpose justification for PII-bearing endpoints. May become mandatory for sensitive data in a future release.
Path Parameters
UUID of the seller trade partner (must be in caller's authorized list).
UUID of the buyer trade partner.
Body
The account permission asked for on the platform: OWNER (Admin)
or CONTACT (Member). Optional. Granted under the platform's rules,
and named in notApplied when the person does not end up with it —
see POST /partners/{sellerId}/buyers/{buyerId}/contacts. Any
other value is refused with 422.
OWNER, CONTACT Response
The contact person this body resolves to — newly recorded, or the
one already on file under that email address. notApplied names
the fields the body disagreed with, and is absent when there were
none.
Fields of the request that named something other than what the
person already recorded under this email address says, and were
therefore not written — firstName, lastName, phone — and
role when the person did not get the role asked for, whether
newly recorded or already on file. email is never listed: it is
the key the two were matched on.
Present only on POST /contacts, and only when there was something
to report. Absent on every read, on a newly recorded person who got
the role asked for, and on a replay that agreed with the record.
The rest of the body carries the person as this record holds them, so you can see who your call resolved to. Nothing here is applied: a stored contact person is never overwritten through this API.