جرّب الخدمة بطريقتين: رفع مباشر (Multipart) أو JSON (Base64)
data:application/pdf;base64,...استخدم الخدمة برمجياً من أي بيئة
multipart/form-data · حقل pdf (مطلوب) + reason, location, contact
application/pdf (binary) · الملف الموقّع مباشرة
curl -X POST https://signer.ejadtech.sa/sign \ -H "X-API-Key: $SIGNER_KEY" \ -F "pdf=@document.pdf" \ -F "reason=Approved" \ -o signed.pdf
import requests session = requests.Session() session.headers.update({"X-API-Key": "..."}) with open("doc.pdf", "rb") as f: r = session.post( "https://signer.ejadtech.sa/sign", files={"pdf": f}, data={"reason": "Approved"}, timeout=30, ) r.raise_for_status() open("signed.pdf", "wb").write(r.content)
import fs from "node:fs"; const form = new FormData(); form.append("pdf", new Blob([fs.readFileSync("doc.pdf")]), "doc.pdf"); form.append("reason", "Approved"); const res = await fetch("https://signer.ejadtech.sa/sign", { method: "POST", headers: { "X-API-Key": process.env.SIGNER_KEY }, body: form, }); fs.writeFileSync("signed.pdf", Buffer.from(await res.arrayBuffer()));
{
"pdf_base64": "JVBERi0xLjQK...",
"reason": "Approved",
"location": "Riyadh, SA",
"contact": "devops@ejadtech.sa",
"return_format": "base64" // or "binary"
}
{
"success": true,
"pdf_base64": "JVBERi0xLjQK...",
"original_size": 12345,
"signed_size": 15678,
"filename": "signed.pdf"
}
PDF_B64=$(base64 -w0 document.pdf) curl -X POST https://signer.ejadtech.sa/sign-base64 \ -H "X-API-Key: $SIGNER_KEY" \ -H "Content-Type: application/json" \ -d "{ \"pdf_base64\": \"$PDF_B64\", \"reason\": \"Approved\", \"return_format\": \"base64\" }" | jq -r '.pdf_base64' | base64 -d > signed.pdf
import base64, requests with open("doc.pdf", "rb") as f: pdf_b64 = base64.b64encode(f.read()).decode() r = requests.post( "https://signer.ejadtech.sa/sign-base64", headers={"X-API-Key": "..."}, json={ "pdf_base64": pdf_b64, "reason": "Approved", "return_format": "base64", }, timeout=30, ) r.raise_for_status() data = r.json() open("signed.pdf", "wb").write(base64.b64decode(data["pdf_base64"]))
import fs from "node:fs"; const pdfB64 = fs.readFileSync("doc.pdf").toString("base64"); const res = await fetch("https://signer.ejadtech.sa/sign-base64", { method: "POST", headers: { "X-API-Key": process.env.SIGNER_KEY, "Content-Type": "application/json", }, body: JSON.stringify({ pdf_base64: pdfB64, reason: "Approved", return_format: "base64", }), }); const data = await res.json(); fs.writeFileSync("signed.pdf", Buffer.from(data.pdf_base64, "base64"));
# داخل Odoo model — التكامل السلس import requests class DocumentSigner(models.Model): _name = 'document.signer' def sign_attachment(self, attachment): # attachment.datas في Odoo يكون base64 أصلاً! key = self.env['ir.config_parameter'].sudo().get_param('signer.key') r = requests.post( 'https://signer.ejadtech.sa/sign-base64', headers={'X-API-Key': key}, json={ 'pdf_base64': attachment.datas.decode(), 'reason': f'Signed by {self.env.user.name}', 'return_format': 'base64', }, timeout=30, ) r.raise_for_status() return self.env['ir.attachment'].create({ 'name': f'{attachment.name}_signed.pdf', 'datas': r.json()['pdf_base64'], 'mimetype': 'application/pdf', })
Session() / AsyncClient يوفر ~200ms/طلب (TLS handshake).asyncio.gather بحد 10-15 طلب متزامن.200 — الملف الموقّع (binary أو JSON)400 — PDF غير صالح / base64 خاطئ401 — API key غير صحيح413 — الملف أكبر من الحد المسموح500 — خطأ داخلي (راجع اللوق)