القاعدة: الوكيل يجهّز والإنسان يصدر
الفاتورة الضريبية لا تُسحب بعد إصدارها. الوكيل الذي يسيء فهم طلب يجب أن يكلفك مسودة تحذفها، لا إشعارًا دائنًا. وندرفاتورة مبنية حول هذه القاعدة.
اليوم: الواجهة البرمجية بمفتاح للمسودات
- أنشئ مفتاحًا بصلاحيتي
invoices:writeوinvoices:read، دونinvoices:issue. - امنح وكيلك أداة واحدة تستدعي
POST /invoicesمع"issue": false. - يراجع شخص المسودة في لوحة التحكم ويصدرها.
curl -X POST https://fatoora.tw.sa/api/v1/invoices \
-H "Authorization: Bearer wbk_test_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"issue": false,
"issue_date": "2026-11-03",
"customer": {
"name": "Example Trading Co.",
"vat_number": "300000000000003",
"address_line1": "King Fahd Rd",
"city": "Riyadh",
"postal_code": "12345",
"country": "SA"
},
"items": [
{ "description": "Consulting", "quantity": 2, "unit_price": 500, "vat_rate": 15 }
]
}'
<?php
$response = $client->post('invoices', [
'json' => [
'issue' => false, // a draft: no legal number, nothing sent to ZATCA
'issue_date' => '2026-11-03',
'customer' => [
'name' => 'Example Trading Co.',
'vat_number' => '300000000000003',
'address_line1' => 'King Fahd Rd',
'city' => 'Riyadh',
'postal_code' => '12345',
'country' => 'SA',
],
'items' => [
['description' => 'Consulting', 'quantity' => 2, 'unit_price' => 500, 'vat_rate' => 15],
],
],
'http_errors' => false,
]);
$body = json_decode((string) $response->getBody(), true);
if ($body['ok']) {
echo $body['data']['invoice']['number']; // DRAFT-… until it is issued
} else {
echo $body['error']['code'];
}
const res = await fetch("https://fatoora.tw.sa/api/v1/invoices", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.WONDERFATOORA_API_KEY}`,
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify({
issue: false, // a draft: no legal number, nothing sent to ZATCA
issue_date: "2026-11-03",
customer: {
name: "Example Trading Co.",
vat_number: "300000000000003",
address_line1: "King Fahd Rd",
city: "Riyadh",
postal_code: "12345",
country: "SA",
},
items: [{ description: "Consulting", quantity: 2, unit_price: 500, vat_rate: 15 }],
}),
});
const body = await res.json();
if (!body.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
console.log(body.data.invoice.id, body.data.invoice.number);
res = requests.post(
"https://fatoora.tw.sa/api/v1/invoices",
headers={
"Authorization": f"Bearer {os.environ['WONDERFATOORA_API_KEY']}",
"Accept": "application/json",
},
json={
"issue": False, # a draft: no legal number, nothing sent to ZATCA
"issue_date": "2026-11-03",
"customer": {
"name": "Example Trading Co.",
"vat_number": "300000000000003",
"address_line1": "King Fahd Rd",
"city": "Riyadh",
"postal_code": "12345",
"country": "SA",
},
"items": [
{"description": "Consulting", "quantity": 2, "unit_price": 500, "vat_rate": 15}
],
},
timeout=30,
)
body = res.json()
print(res.status_code, body["data"]["invoice"]["number"] if body["ok"] else body["error"])
حتى لو أرسل الوكيل "issue": true فالمفتاح الذي لا يملك invoices:issue يُرفض بـ 403 insufficient_scope؛ فالضمان لا يعتمد على التعليمات المعطاة للوكيل.
عبر MCP: Wonder Fatoora MCP
خادم MCP يمنح الوكلاء أدوات قراءة وتجهيز جاهزة، مع تعطيل الإصدار افتراضيًا وموافقة شخص داخل وندرفاتورة على كل إصدار.
ممارسات جيدة
- امنح الوكيل أضيق مفتاح ممكن، منفصلًا عن أنظمتك الأخرى.
- عامل النصوص القادمة من الفواتير والعملاء كبيانات، ولا تسمح لها بتغيير تعليمات الوكيل.
- سجّل ما أرسله الوكيل و
idالذي تلقاه. - استخدم
external_referenceحتى يعيد استدعاء الأداة المكرر المسودة نفسها.
صفحات ذات صلة
جاهز للبدء؟
الوصول إلى الواجهة البرمجية ضمن باقات: الأعمال والمؤسسات. أنشئ مفتاحًا من الإعدادات ← مفاتيح API وأرسل أول طلب خلال دقائق.