The Account Behind the Key
The five endpoints giving the profile, choices and security state of the key's owner.
Overview
On the client API the account is always resolved from the key. There is no customer parameter: these five endpoints read and write the record of whoever owns the key.
What may be changed on a profile is the operator's decision. The read endpoint returns that decision alongside the data: which fields are open and which cannot be emptied.
Account security is deliberately left out. The password, the e-mail, two-step sign-in and ending a session stay in the panel. The API shows their state alone.
Reference
Reading the Profile
Returns the profile of the customer the key belongs to.
curl 'https://panel.example.com/api/v1/client/me' \
-H "Authorization: Bearer $CLIENT_KEY"const res = await fetch('https://panel.example.com/api/v1/client/me', {
headers: { Authorization: `Bearer ${clientKey}` },
});
const { data, meta } = await res.json();
renderForm(data, meta.editable, meta.required);$ch = curl_init('https://panel.example.com/api/v1/client/me');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $clientKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// Build the form from meta.editable: a field the operator closed gives 422 rather than passing quietly.
$r = Kernel::internal('client:Account/GetMe', ['owner_id' => $uid]);
$form = array_intersect_key($r['data'], array_flip($r['meta']['editable']));Updating the Profile
Changes the profile fields you send.
curl -X PATCH 'https://panel.example.com/api/v1/client/me' \
-H "Authorization: Bearer $CLIENT_KEY" \
-H 'Content-Type: application/json' \
-d '{"timezone":"Europe/Istanbul","date_format":"d/m/Y"}'const res = await fetch('https://panel.example.com/api/v1/client/me', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${clientKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ timezone: 'Europe/Istanbul' }),
});
const { meta } = await res.json();
console.log(meta.changed);$ch = curl_init('https://panel.example.com/api/v1/client/me');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $clientKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode(['timezone' => 'Europe/Istanbul']),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// The E-MAIL and PASSWORD do not change here: both want a verification flow and stay in the panel.
$r = Kernel::internal('client:Account/UpdateMe', ['owner_id' => $uid, 'timezone' => $tz]);
$written = $r['meta']['changed'];Reading the Notification Choices
Returns which notifications the account takes and by which channel.
curl 'https://panel.example.com/api/v1/client/me/notifications' \
-H "Authorization: Bearer $CLIENT_KEY"const res = await fetch('https://panel.example.com/api/v1/client/me/notifications', {
headers: { Authorization: `Bearer ${clientKey}` },
});
const { data } = await res.json();
const editable = data.categories.filter((c) => ! c.locked);$ch = curl_init('https://panel.example.com/api/v1/client/me/notifications');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $clientKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// Read BEFORE writing: the write is a FULL REPLACE and a category left out closes on both channels.
$cur = Kernel::internal('client:Account/GetNotifications', ['owner_id' => $uid])['data'];Writing the Notification Choices
Rewrites the notification choices in full.
curl -X PUT 'https://panel.example.com/api/v1/client/me/notifications' \
-H "Authorization: Bearer $CLIENT_KEY" \
-H 'Content-Type: application/json' \
-d '{"invoices":{"email":true,"sms":false},"support":{"email":true,"sms":true}}'const cur = await fetch('https://panel.example.com/api/v1/client/me/notifications', {
headers: { Authorization: `Bearer ${clientKey}` },
}).then((r) => r.json());
const body = {};
for (const c of cur.data.categories)
if (! c.locked) body[c.category] = { email: c.email, sms: c.sms };
body.marketing = { email: false, sms: false };
await fetch('https://panel.example.com/api/v1/client/me/notifications', {
method: 'PUT',
headers: {
Authorization: `Bearer ${clientKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
});$ch = curl_init('https://panel.example.com/api/v1/client/me/notifications');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $clientKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode($prefs),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// A category you leave out CLOSES: send the full set even to change one choice.
$cur = Kernel::internal('client:Account/GetNotifications', ['owner_id' => $uid])['data'];
$body = [];
foreach ($cur['categories'] as $c)
if (! $c['locked']) $body[$c['category']] = ['email' => $c['email'], 'sms' => $c['sms']];
$body['marketing'] = ['email' => false, 'sms' => false];
Kernel::internal('client:Account/UpdateNotifications', ['owner_id' => $uid] + $body);Reading the Security Summary
Returns the verification state, the two-step sign-in and the recent sessions.
curl 'https://panel.example.com/api/v1/client/me/security' \
-H "Authorization: Bearer $CLIENT_KEY"const res = await fetch('https://panel.example.com/api/v1/client/me/security', {
headers: { Authorization: `Bearer ${clientKey}` },
});
const { data } = await res.json();
if (! data.two_factor.enabled) nudgeToEnable();$ch = curl_init('https://panel.example.com/api/v1/client/me/security');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $clientKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// It is READ ONLY: signing a session out, the password and setting two-step up are ABSENT here and stay in the panel.
$sec = Kernel::internal('client:Account/GetSecurity', ['owner_id' => $uid])['data'];
$stale = array_filter($sec['sessions'], fn ($s) => $s['country_code'] !== $home);Pitfalls
The notification write reads the body as the whole set of choices. A category you leave out closes on both the e-mail and the message channel. Read the current list first and write over it to change one. The general category is locked and stays as it is even when sent.
Sending a field the operator closed for editing is refused with 422. Building a form from a fixed field list makes the whole save fail the day one of them is closed. Always build the list from the editable set the read endpoint returns.
The currency field on the profile says how amounts are shown, while the wallet's own currency comes separately inside the balance object. The two can differ, and reading the balance in the display currency gives a wrong figure. Read the balance in its own currency.
The picture field takes no address. The server never fetches one you give, because the outgoing request would give away its real address. Send the image as encoded content, and send it empty to remove the picture.
The verified mark is cleared when the number changes. The flows resting on the phone stop until the new one is verified. The same holds for the e-mail, which cannot be changed here at all. Send the customer to verification after a number change.
The security summary lists the sessions and cannot end them, and no session token is ever returned. The password, two-step sign-in and identity documents stay in the panel for the same reason: each wants an unbroken human step.
Related Articles
Thanks for your feedback!
Our support team is here around the clock for anything you can't find above.