Create a cheque directly — POST /api/cheque-log/external
One endpoint records an externally printed cheque from your system with no screen and no preview. Its fields with literal rules, the guards that raise 422, the 201 response, and what to know about duplicates and images.
Last updated: 2026-09-21
On this page
When to use it
When your system prints the cheque itself (or does not print at all) and you want a row in the cheque log with its initial status for follow-up in the app. No preview, no printing — to print from the app’s screen use the Dynamics flow.
Route: POST /api/cheque-log/external — alias POST /api/cheque-logs (audited under the first name).
Fields
| Field | Literal rule | Required | Default |
|---|---|---|---|
bank_name |
required|string|max:255 |
✅ | — |
template_name |
nullable|string|max:255 |
null | |
cheque_type |
IN or OUT |
null ⟹ no status | |
cheque_date · stub_date |
nullable|date |
null | |
recipient_name · place · signed_by · reason · reference_number · stub_name · stub_reason |
nullable|string|max:255 |
null | |
amount_text · note · liner_text |
nullable|string |
null | |
amount |
nullable|numeric — ≤ 13 integer digits, fraction per currency |
null | |
stub_amount |
nullable|numeric — ≤ 8 digits |
null | |
currency |
nullable|string|max:10 |
EGP |
|
cheque_number |
nullable|string|max:50 + unique per bank among printed |
null | |
company_id |
nullable|integer|exists:companies,id |
the key’s company — if sent and different ⟹ 422 | |
bank_account_id · cheque_book_id · cheque_leaf_id · partner_id |
nullable|integer|exists |
null | |
liner_enabled · two_lines |
boolean |
false | |
image |
nullable|image|max:200048 (KB) |
— | |
image_base64 |
nullable|string |
— | |
save_cheque_image |
nullable|boolean |
false | |
external_source · external_id |
nullable|string |
null — the optional idempotency key |
Contract notes:
cheque_status_idis silently ignored — the status derives fromcheque_type:OUT⟹ being issued ·IN⟹ in wallet · unknown ⟹ no status (which you don’t want — always send the direction).bank_idis accepted but not read here — the bank resolves frombank_namealone by exact match after trimming; send the name exactly as/api/banksreturns it.- The image is not stored unless
save_cheque_image: truewithimage_base64/image— and without a watermark.
Guards that raise 422
| Case | Message (Arabic) |
|---|---|
| Number belongs to a cheque-book leaf | هذا الرقم يخص دفتر شيكات — اطبعه من وضع الدفتر |
| Number reserved in an open batch | الرقم :number محجوز في دفعة مفتوحة (الدفعة #:batch) — اطبعها أو ألغِها أولًا. |
| Duplicate on the same bank | رقم الشيك {N} مستعمَل بالفعل على بنك {البنك} — اختر رقمًا آخر |
| Amount too large | القيمة كبيرة جدًا — لا يزيد الجزء الصحيح عن 13 خانة. |
| Fraction digits | كسر المبلغ يتجاوز خانات {العملة} (خانتان عشريتان). |
| Reference from another company | المستفيد لا يتبع شركة الشيك. · الحساب البنكي المختار لا يتبع شركة الشيك. · دفتر الشيكات المختار … · ورقة الشيك المختار … |
| Key without a company | مفتاح الـAPI غير منسوب لشركة — عيّن شركته من شاشة «التكامل ← مفاتيح API». |
company_id contradicts the key |
الحمولة تطلب شركة «…» بينما مفتاح الـAPI منسوب لشركة «…» — احذف الحقل أو استعمل مفتاح الشركة الصحيحة. |
Example
curl -s -X POST "APP_URL/api/cheque-log/external" \
-H "X-API-KEY: KEY" -H "Content-Type: application/json" -H "Accept: application/json" \
-d '{
"bank_name": "بنك مصر",
"template_name": "بنك مصر - نموذج 1",
"cheque_type": "OUT",
"recipient_name": "شركة النيل للتوريدات",
"amount": 1250.50,
"currency": "EGP",
"cheque_date": "2026-10-15",
"cheque_number": "100200",
"reference_number": "PV-1001",
"reason": "دفعة مورّد",
"signed_by": "خالد عبد الرحمن"
}'
201:
{
"success": true,
"message": "تم الحفظ بنجاح",
"data": { "id": 4321, "bank_name": "بنك مصر", "cheque_number": "100200", "amount": "1250.500", "…": "the full cheque_logs row" },
"image_saved": false
}
data is the full row (100+ columns, including lifecycle columns that are empty now) — rely on id, cheque_number, bank_name, amount, cheque_date, currency, and do not build on the rest.
Errors
| Status | Body |
|---|---|
| 422 | {"message":"Validation failed","errors":{"cheque_number":["…"]}} — messages in Arabic |
| 500 | {"message":"Error saving cheque log","error":"…"} |
| 503 · 401 · 403 · 429 | from the key ladder |
Stamped server-side
printed_at = now() · printed_by = null · initial status from the direction · and company_id = the key’s company, always. The payload is checked against it: a different company_id, or a reference (account · book · leaf · partner) from another company ⟹ 422. No fallback and no default company on the key path.
The row is confirmed — and idempotency
The row is created printed and confirmed (the paper left outside the app): its number cannot be edited afterwards, like any confirmed cheque, and it enters confirmed reports and reminders — so send the number right the first time.
Three duplicate guards (since 1.8.0):
- Cheque number per bank: a second call with the same number ⟹ 422 “already used” — treat it as a prior success in your logic.
- External key (optional): send
external_source+external_id(as in Dynamics) — a resend returns the existing row with 200 and"reused": true, no new row (Dynamics usesaction: "reused"instead). - A row stamped for another company, or a final row (damaged · cancelled · reissued) ⟹ 422 instead of an update.
Recommendation: send both cheque_number and external_id.
Related
Did this page answer your question?
Thanks — your feedback helps us improve the guide.
Couldn't send — please try again shortly.