Integroni timestamp me blockchain, nenshkrim elektronik eIDAS dhe vula dixhitale direkt ne sistemin tuaj.
https://www.doc.al/api/v1Permbajtja
API-ja eshte e disponueshme per organizatat me plan Enterprise. Krijoni nje API key nga paneli juaj, pastaj beni thirrjen e pare.
curl -X POST https://www.doc.al/api/v1/timestamp \
-H "X-API-Key: docal_xxxxx" \
-H "Content-Type: application/json" \
-d '{"hash":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"}'Cdo kerkese kerkon API key-in tuaj. Pranohen te dyja format e meposhtme, zgjidhni ate qe ju pershtatet me mire.
X-API-Key: docal_xxxxx
# ose
Authorization: Bearer docal_xxxxxKey-i trashegon identitetin e perdoruesit dhe organizates qe e krijoi. Dokumentet e krijuara permes API-se i perkasin asaj organizate, dhe endpoint-et e vulave dhe te kuotes kerkojne qe key-i te jete i lidhur me nje organizate.
Cdo key ka nje limit orar (parazgjedhur 100 kerkesa/ore), i zbatuar per key dhe jo per adrese IP. Kur tejkalohet, kthehet 429 me header-in Retry-After ne sekonda.
{
"success": false,
"error": "Limiti i kerkesave u tejkalua (100/ore). Provoni pas 1840 sekondash.",
"timestamp": "2026-09-07T15:00:00.000Z"
}Vulos nje hash SHA-256 ne zinxhirin e doc.al dhe e dergon automatikisht ne blockchain-in Polygon permes STAMLES. Pas konfirmimit, prova publikohet edhe ne IPFS.
/api/v1/timestampKrijo timestamp/api/v1/timestamp/verifyVerifiko nje hash# Me hash te llogaritur nga ju
curl -X POST https://www.doc.al/api/v1/timestamp \
-H "X-API-Key: docal_xxxxx" \
-H "Content-Type: application/json" \
-d '{"hash":"<sha256 64 karaktere hex>"}'
# Ose duke ngarkuar skedarin - hash-i llogaritet nga serveri
curl -X POST https://www.doc.al/api/v1/timestamp \
-H "X-API-Key: docal_xxxxx" \
-F "[email protected]"{
"success": true,
"data": {
"id": "cmms7s34n000001pmp31984ge",
"sequenceNumber": 27,
"fingerprint": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
"sequentialFingerprint": "4a44dc15364204a80fe80e9039455cc1608281820fe2b24f1e5233ade6af1dd5",
"type": "SUBMITTED_HASH",
"serverTimestamp": "2026-09-07T15:00:00.000Z",
"blockchain": {
"network": "Polygon PoS",
"system": "STAMLES Merkle Batching",
"status": "QUEUED",
"explorerUrl": "https://scan.stamles.eu/verify/9f86d081..."
},
"verifyUrl": "https://www.doc.al/verify/9f86d081...",
"statusUrl": "https://www.doc.al/api/v1/timestamp/verify"
}
}Konfirmimi nuk eshte i menjehershem. STAMLES i grupon hash-et ne nje peme Merkle dhe shkruan vetem rrenjen ne blockchain nje here ne 24 ore. Statusi kalon QUEUED → BATCHED → CONFIRMED. Fushat polygonTxHash dhe ipfs.cid mbushen vetem pas konfirmimit. Vulosja vlen qe nga momenti i thirrjes, jo qe nga konfirmimi.
curl -X POST https://www.doc.al/api/v1/timestamp/verify \
-H "X-API-Key: docal_xxxxx" \
-H "Content-Type: application/json" \
-d '{"hash":"<sha256>"}'
# Pergjigja
{
"success": true,
"data": {
"found": true,
"sequenceNumber": 27,
"serverTimestamp": "2026-09-07T15:00:00.000Z",
"blockchain": {
"network": "Polygon PoS",
"status": "CONFIRMED",
"txHash": "0x...",
"blockNumber": 62841003,
"batchId": "14",
"explorerUrl": "https://scan.stamles.eu/verify/..."
},
"ipfs": {
"cid": "QmXoyp...",
"gatewayUrl": "https://ipfs.io/ipfs/QmXoyp..."
}
}
}Krijon nje kerkese nenshkrimi, dergon ftesat me email me brandin tuaj, dhe kthen nje link te sigurt nenshkrimi per secilin nenshkrues. Dokumenti perfundimtar merr nenshkrim PAdES, vulosje ne blockchain dhe prove ne IPFS.
/api/v1/signingKrijo kerkese nenshkrimi/api/v1/signingLista e kerkesave/api/v1/signing/:id/statusStatusi dhe progresicurl -X POST https://www.doc.al/api/v1/signing \
-H "X-API-Key: docal_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"documentTitle": "Kontrata e Sherbimit",
"documentUrl": "https://sistemi-im.com/dok.pdf",
"documentHash": "<sha256 opsional>",
"signers": [
{ "email": "[email protected]", "name": "Emri Mbiemri", "order": 0 },
{ "email": "[email protected]", "name": "Emri Tjeter", "order": 1 }
],
"message": "Ju lutem nenshkruani kontraten",
"expiresInDays": 30,
"companyName": "Kompania Ime",
"companyLogo": "https://sistemi-im.com/logo.png",
"brandColor": "#dc2626",
"callbackUrl": "https://sistemi-im.com/webhook/docal",
"stamp": { "allPages": true, "barcode": "datamatrix" }
}'{
"success": true,
"data": {
"signingRequestId": "cmms7s34u000101pm...",
"documentId": "cmms7s34u000201pm...",
"status": "PENDING",
"expiresAt": "2026-10-07T15:00:00.000Z",
"signers": [
{
"id": "...",
"name": "Emri Mbiemri",
"email": "[email protected]",
"signingUrl": "https://www.doc.al/sign/a1b2c3...",
"status": "PENDING"
}
],
"tracking": {
"statusUrl": "https://www.doc.al/api/v1/signing/<id>/status",
"documentStatusUrl": "https://www.doc.al/api/v1/documents/<id>/status"
},
"webhook": {
"callbackUrl": "https://sistemi-im.com/webhook/docal",
"secret": "whsec_..."
}
}
}Ruajeni webhook.secret - kthehet vetem njehere dhe ju duhet per te verifikuar cdo thirrje qe merrni.
{
"success": true,
"data": {
"signingRequestId": "...",
"status": "IN_PROGRESS",
"expired": false,
"progress": { "signed": 1, "total": 2, "pending": 1 },
"document": { "id": "...", "title": "Kontrata", "status": "PARTIALLY_SIGNED", "fileHash": "..." },
"signers": [
{ "signerName": "Emri Mbiemri", "status": "SIGNED", "viewedAt": "...", "signedAt": "..." },
{ "signerName": "Emri Tjeter", "status": "PENDING", "viewedAt": null, "signedAt": null }
],
"timestamps": [ { "sequenceNumber": 28, "fingerprint": "...", "serverTimestamp": "..." } ]
}
}Ne parazgjedhje, blloku i certifikimit vendoset nje here, ne fund te faqes se fundit. Me opsionin stamp ai perseritet ne fund te cdo faqeje, keshtu qe secila flete skanohet me vete dhe mban numrin e saj (Faqe 3/12).
"stamp": {
"allPages": true,
"barcode": "datamatrix"
}allPages
false (parazgjedhur) vendos bllokun vetem ne faqen e fundit. true e perserit ne cdo faqe.
barcode
both (parazgjedhur) · qr · datamatrix · none
QR-i con te faqja e verifikimit, ndersa DataMatrix-i permban hash-in e dokumentit - i lexueshem edhe nga skanera industriale qe nuk mbeshtesin QR. Blloku permban gjithashtu emrin e nenshkruesit, daten, referencen eIDAS dhe hash-in e shkurtuar.
Aplikon vulen e kompanise mbi nje dokument. Vula dhe dokumenti duhet t'i perkasin organizates suaj.
/api/v1/sealsLista e vulave/api/v1/seals/:sealIdDetajet e nje vule/api/v1/seals/applyApliko vulen/api/v1/seals/:sealId/applyApliko vule specifike/api/v1/seals/verifyVerifiko vulencurl -X POST https://www.doc.al/api/v1/seals/apply \
-H "X-API-Key: docal_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"documentId": "cmms7s34u000201pm...",
"sealId": "cmms7s34u000301pm...",
"position": { "page": 1, "x": 400, "y": 100 }
}'/api/v1/documentsNgarko PDF/api/v1/documents/:id/statusStatus, nenshkrime, timestamps/api/v1/quotaKuota e organizatescurl -X POST https://www.doc.al/api/v1/documents \
-H "X-API-Key: docal_xxxxx" \
-F "[email protected]" \
-F "title=Kontrata e Sherbimit"Nese jepni callbackUrl kur krijoni kerkesen e nenshkrimit, doc.al ju njofton per cdo ndryshim. Dergesat riprovohen 3 here me backoff.
signature.signed
Sa here nje pale nenshkruan
signing_request.completed
Kur mbarojne te gjithe - permban hash-in perfundimtar
X-Docal-Event: signature.signed
X-Docal-Timestamp: 2026-09-07T15:00:00.000Z
X-Docal-Signature: sha256=<hmac>Nenshkrimi eshte HMAC-SHA256 mbi <timestamp>.<body> me sekretin tuaj. Verifikojeni gjithmone para se te besoni permbajtjen.
import crypto from "crypto";
// rawBody duhet te jete trupi i papërpunuar, jo JSON i ri-serializuar
export function verifyDocalWebhook(rawBody, headers, secret) {
const timestamp = headers["x-docal-timestamp"];
const received = headers["x-docal-signature"];
if (!timestamp || !received) return false;
const expected =
"sha256=" +
crypto.createHmac("sha256", secret)
.update(timestamp + "." + rawBody)
.digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(received);
if (a.length !== b.length) return false;
return crypto.timingSafeEqual(a, b);
}callbackUrl duhet te jete nje adrese publike http(s). Adresat lokale dhe rrjetet private refuzohen me 400.
Nuk kerkohet asnje pako e jashtme - API-ja eshte REST me JSON. Me poshte gjeni nje klient te gatshem per gjuhet me te perdorura. Kopjojeni ne projektin tuaj dhe vendosni key-in ne nje variabel mjedisi.
const BASE = "https://www.doc.al/api/v1";
export class DocAl {
constructor(apiKey = process.env.DOCAL_API_KEY) {
if (!apiKey) throw new Error("DOCAL_API_KEY mungon");
this.apiKey = apiKey;
}
async #request(path, { method = "GET", body } = {}) {
const res = await fetch(BASE + path, {
method,
headers: {
"X-API-Key": this.apiKey,
...(body ? { "Content-Type": "application/json" } : {}),
},
body: body ? JSON.stringify(body) : undefined,
});
const data = await res.json().catch(() => ({}));
if (!res.ok) {
const err = new Error(data.error || `HTTP ${res.status}`);
err.status = res.status;
throw err;
}
return data.data ?? data;
}
timestamp(hash) {
return this.#request("/timestamp", { method: "POST", body: { hash } });
}
verifyTimestamp(hash) {
return this.#request("/timestamp/verify", { method: "POST", body: { hash } });
}
createSigningRequest(payload) {
return this.#request("/signing", { method: "POST", body: payload });
}
signingStatus(id) {
return this.#request(`/signing/${id}/status`);
}
applySeal(documentId, sealId, position) {
return this.#request("/seals/apply", {
method: "POST",
body: { documentId, sealId, position },
});
}
quota() {
return this.#request("/quota");
}
}
// Perdorimi
import crypto from "crypto";
const docal = new DocAl();
const hash = crypto.createHash("sha256").update(fileBuffer).digest("hex");
const result = await docal.timestamp(hash);
console.log(result.sequenceNumber, result.blockchain.status);<?php
class DocAl
{
private const BASE = 'https://www.doc.al/api/v1';
private string $apiKey;
public function __construct(?string $apiKey = null)
{
$this->apiKey = $apiKey ?? getenv('DOCAL_API_KEY') ?: '';
if ($this->apiKey === '') {
throw new RuntimeException('DOCAL_API_KEY mungon');
}
}
private function request(string $path, string $method = 'GET', ?array $body = null): array
{
$ch = curl_init(self::BASE . $path);
$headers = ['X-API-Key: ' . $this->apiKey];
if ($body !== null) {
$headers[] = 'Content-Type: application/json';
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
}
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_TIMEOUT => 30,
]);
$raw = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$data = json_decode($raw, true) ?: [];
if ($status >= 400) {
throw new RuntimeException($data['error'] ?? "HTTP $status", $status);
}
return $data['data'] ?? $data;
}
public function timestamp(string $hash): array
{
return $this->request('/timestamp', 'POST', ['hash' => $hash]);
}
public function verifyTimestamp(string $hash): array
{
return $this->request('/timestamp/verify', 'POST', ['hash' => $hash]);
}
public function createSigningRequest(array $payload): array
{
return $this->request('/signing', 'POST', $payload);
}
public function signingStatus(string $id): array
{
return $this->request("/signing/$id/status");
}
}
// Perdorimi
$docal = new DocAl();
$hash = hash('sha256', file_get_contents('kontrata.pdf'));
$result = $docal->timestamp($hash);
echo $result['sequenceNumber'], ' ', $result['blockchain']['status'];import hashlib
import os
import requests
BASE = "https://www.doc.al/api/v1"
class DocAlError(Exception):
def __init__(self, message, status):
super().__init__(message)
self.status = status
class DocAl:
def __init__(self, api_key: str | None = None):
self.api_key = api_key or os.environ.get("DOCAL_API_KEY")
if not self.api_key:
raise RuntimeError("DOCAL_API_KEY mungon")
self.session = requests.Session()
self.session.headers["X-API-Key"] = self.api_key
def _request(self, path: str, method: str = "GET", body: dict | None = None):
res = self.session.request(method, BASE + path, json=body, timeout=30)
data = res.json() if res.content else {}
if not res.ok:
raise DocAlError(data.get("error", f"HTTP {res.status_code}"), res.status_code)
return data.get("data", data)
def timestamp(self, file_hash: str):
return self._request("/timestamp", "POST", {"hash": file_hash})
def verify_timestamp(self, file_hash: str):
return self._request("/timestamp/verify", "POST", {"hash": file_hash})
def create_signing_request(self, payload: dict):
return self._request("/signing", "POST", payload)
def signing_status(self, request_id: str):
return self._request(f"/signing/{request_id}/status")
# Perdorimi
docal = DocAl()
with open("kontrata.pdf", "rb") as f:
file_hash = hashlib.sha256(f.read()).hexdigest()
result = docal.timestamp(file_hash)
print(result["sequenceNumber"], result["blockchain"]["status"])Te gjitha gabimet kthehen ne te njejtin format, me kodin HTTP perkates.
{
"success": false,
"error": "API key i pavlefshem ose i skaduar",
"timestamp": "2026-09-07T15:00:00.000Z"
}400Kerkese e pavlefshme - hash jo valid, fusha qe mungojne, callbackUrl jopublik401API key mungon, eshte i pavlefshem ose ka skaduar403Key-i nuk eshte i lidhur me nje organizate, ose burimi i perket dikujt tjeter404Burimi nuk u gjet429Limiti orar u tejkalua - shihni Retry-After500Gabim ne serverAPI-ja eshte pjese e planit Enterprise. Na kontaktoni per akses.