API Reference
Create Widget Session
Creates an SSO session and returns a widgetUrl ready to embed in an <iframe>
on the partner frontend.
Endpoint
POST {BASE_URL}/api/v2/partner/{partnerId}/sessions| Environment | Base URL |
|---|---|
| Development / Staging | https://dev-app.psikologiehub.com |
| Production | https://app.psikologiehub.com |
Path Parameters
| Field | Type | Required | Description |
|---|---|---|---|
partnerId | string | Yes | Active Partner ID issued by PsikologieHub |
Headers
{ "Content-Type": "application/json" }Request Body
| Field | Type | Required | Description |
|---|---|---|---|
user.user_id | string | Yes | External HR/recruiter ID in the partner system |
user.email | string | Yes | HR/recruiter email |
user.name | string | Yes | HR/recruiter full name |
user.username | string | No | HR/recruiter username (not part of signature) |
user.company.company_id | string | No | External company ID |
user.company.name | string | No | Company name (not part of signature) |
user.company.email | string | No | Company email (not part of signature) |
user.candidates[].candidate_id | string | Yes | External candidate ID |
user.candidates[].nama | string | Yes | Candidate name (Bahasa Indonesia field name) |
user.candidates[].email | string | Yes | Candidate email |
signature | string | Yes | HMAC-SHA256 signature (lowercase hex) |
⚠️
The candidate name field is nama (Bahasa Indonesia), not name. This is a
common source of integration errors.
Example Request Body
{
"user": {
"user_id": "USR-001",
"email": "[email protected]",
"name": "John Doe",
"username": "johndoe",
"company": {
"company_id": "COMP-001",
"name": "Acme Corp",
"email": "[email protected]"
},
"candidates": [
{ "candidate_id": "CND-001", "nama": "Jane Doe", "email": "[email protected]" },
{ "candidate_id": "CND-002", "nama": "Bob Doe", "email": "[email protected]" }
]
},
"signature": "ac689886217ce7c1002102d1327dfe741ecfeb3912426eac1777e80db427a1c2"
}Success Response (200)
{
"success": true,
"sessionToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"widgetUrl": "https://dev-app.psikologiehub.com/api/v2/partner/widget?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"partnerId": "psikologihub",
"expiresIn": 1778760077
}| Field | Type | Description |
|---|---|---|
success | boolean | Always true on a successful response |
sessionToken | string | JWT session token (used internally by the widget) |
widgetUrl | string | URL to embed in the iframe (?token= already appended) |
partnerId | string | Partner ID that owns this session |
expiresIn | integer | UNIX timestamp (seconds) when the session expires |
Error Responses
401 Invalid signature
{
"success": false,
"message": "Invalid signature",
"errors": null
}404 Partner not found or inactive
{
"success": false,
"message": "Partner not found or inactive",
"errors": null
}422 Validation failed
{
"success": false,
"message": "Validation failed",
"errors": {
"signature": ["Signature is required."]
}
}See Error Handling for a complete list of status codes and the recommended retry strategy.
End-to-End Implementation Examples
The examples below cover both generating the signature and calling the endpoint.
<?php
function generateSignature(
string $partnerId, string $userId, string $userEmail, string $userName,
string $companyId, string $candidateIdsCsv, string $secretKey
): string {
$canonical = implode('|', [
$partnerId, $userId, $userEmail, $userName, $companyId, $candidateIdsCsv,
]);
return hash_hmac('sha256', $canonical, $secretKey);
}
$baseUrl = 'https://dev-app.psikologiehub.com';
$partnerId = 'psikologihub-1024';
$secretKey = getenv('PSIKOLOGIE_SECRET_KEY');
$signature = generateSignature(
$partnerId, 'USR-001', '[email protected]', 'John Doe',
'COMP-001', 'CND-001,CND-002', $secretKey
);
$payload = [
'user' => [
'user_id' => 'USR-001',
'email' => '[email protected]',
'name' => 'John Doe',
'username' => 'johndoe',
'company' => [
'company_id' => 'COMP-001',
'name' => 'Acme Corp',
'email' => '[email protected]',
],
'candidates' => [
['candidate_id' => 'CND-001', 'nama' => 'Jane Doe', 'email' => '[email protected]'],
['candidate_id' => 'CND-002', 'nama' => 'Bob Doe', 'email' => '[email protected]'],
],
],
'signature' => $signature,
];
$ch = curl_init("$baseUrl/api/v2/partner/$partnerId/sessions");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode($payload),
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo "status: $status\n";
echo "response: $response\n";