Jobs that reach Saplic through a feed receive their applications on Saplic: the candidate never leaves the site. Each application is forwarded to the source:
https:// URL.Both carry the same data. Only candidates who applied to a job from that source are sent.
A POST to the registered URL, with Content-Type: application/json; charset=utf-8.
| Header | Content |
|---|---|
X-Saplic-Event |
application.created (an application) or test.ping (a test). |
X-Saplic-Delivery |
Delivery identifier. It is the same on every retry of an application. |
X-Saplic-Timestamp |
Time of sending, in Unix seconds. |
X-Saplic-Signature |
HMAC-SHA256(secret, timestamp + "." + body), in lowercase hexadecimal. |
https only. Saplic does not follow redirects: a 3xx response counts as a failure.application.created{
"event": "application.created",
"delivery_id": "4f6c1d0a9b7e4c2f8a1d3e5b7c9f0a2b",
"created_at": "2026-10-07T15:04:05+00:00",
"source": "saplic",
"job": {
"reference": "ACME-2026-0412",
"title": "Marketing Coordinator",
"url": "https://acmefoods.example/careers/marketing-coordinator",
"saplic_url": "https://saplic.com/oferta.php?id=41234"
},
"application": {
"applied_at": "2026-10-07T15:03:58+00:00",
"answers": [
{ "question": "Do you have a valid work permit?", "answer": "Yes" }
]
},
"candidate": {
"name": "Ana López",
"email": "[email protected]",
"phone": "+503 70001234",
"country": "El Salvador",
"city": "San Salvador",
"experience": [
{ "title": "Marketing Analyst", "company": "Globex", "from": "2022-03", "to": "", "current": true }
],
"education": [
{ "title": "Marketing", "school": "Universidad Centroamericana", "level": "Universitario" }
],
"cv_url": "https://saplic.com/feed-cv.php?t=…",
"cv_url_expires_in_hours": 72
}
}
job.reference is the referencenumber the source sent in its feed. cv_url is null if the candidate did not upload a CV file.
test.ping{
"event": "test.ping",
"delivery_id": "…",
"created_at": "2026-10-07T15:04:05+00:00",
"source": "saplic",
"message": "Evento de prueba de Saplic. No corresponde a ninguna postulación."
}
It is sent from the dashboard to check the connection and the signature. It carries no candidate data.
The secret is a string of 64 hexadecimal characters that Saplic gives the source. It is used as is, as text (do not convert it to bytes).
HMAC-SHA256(secret, X-Saplic-Timestamp + "." + body) in hexadecimal.X-Saplic-Signature using a constant-time comparison.X-Saplic-Timestamp differs from the server time by more than 5 minutes.200 without processing) if X-Saplic-Delivery was already received: it is a retry of something already processed.Steps 4 and 5 are what prevent someone who captures a delivery from sending it again.
PHP:
$body = file_get_contents('php://input');
$ts = $_SERVER['HTTP_X_SAPLIC_TIMESTAMP'] ?? '';
$signature = $_SERVER['HTTP_X_SAPLIC_SIGNATURE'] ?? '';
$ok = ctype_digit($ts)
&& abs(time() - (int)$ts) <= 300
&& hash_equals(hash_hmac('sha256', $ts . '.' . $body, $secret), $signature);
if (!$ok) { http_response_code(401); exit; }
// … discard if $_SERVER['HTTP_X_SAPLIC_DELIVERY'] was already processed …
http_response_code(200);
Python:
import hmac, hashlib, time
def valid_signature(secret: str, timestamp: str, body: bytes, signature: str) -> bool:
if not timestamp.isdigit() or abs(time.time() - int(timestamp)) > 300:
return False
expected = hmac.new(secret.encode(), timestamp.encode() + b"." + body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)
Node.js:
const crypto = require('crypto');
function validSignature(secret, timestamp, body /* Buffer */, signature) {
if (!/^\d+$/.test(timestamp) || Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
const expected = crypto.createHmac('sha256', secret).update(timestamp + '.').update(body).digest('hex');
return expected.length === signature.length && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}
If the email does not go out or the webhook does not answer 2xx within 10 seconds, Saplic retries after 5 minutes, 30 minutes and 2 hours. If the last retry also fails, the delivery is marked as failed and the Saplic team is alerted; the application stays stored and can be resent by hand.
Each webhook retry carries a new X-Saplic-Timestamp and signature, and the same X-Saplic-Delivery.
The CV is not attached: it is sent as a link (cv_url in the webhook, a button in the email).
Download the file when you receive the application rather than storing the link.
Subject: New application: {job title} — via Saplic, in the language the source was registered with (Spanish, English, Portuguese or French). It carries the job reference, the candidate’s details (name, email, phone, country, city, experience, education and the answers to the job’s questions) and the CV link.
The secret can be regenerated from the source dashboard on Saplic at any time. The previous one stops working immediately, so it must be updated on the source side at the same moment.