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-10-24

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 nullable|date + year between 2000 and 2100 null
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, decimals within the currency's scale 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 · partner_id nullable|integer|exists null
cheque_leaf_id nullable|integer|exists + the leaf guard (below) —
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_id is silently ignored — the status derives from cheque_type: OUT ⟹ being issued · IN ⟹ in wallet · unknown ⟹ no status (which you don’t want — always send the direction).
  • bank_id is accepted but not read here — the bank resolves from bank_name alone by a case-insensitive match after trimming; send the name as /api/banks returns it.
  • The image is not stored unless save_cheque_image: true with image_base64/image — and without a watermark.
  • cheque_leaf_id: an available leaf of an issued-cheque book in the key's company; the cheque number, book and account come from it, and it is marked used with the row.

Guards that raise 422

Case Message (Arabic)
Number belongs to a cheque-book leaf and no cheque_leaf_id is sent (issued cheques only: a leaf in a book of the account sent, or of the bank's books in the company when no account is sent) هذا الرقم يخص دفتر شيكات — اطبعه من وضع الدفتر
cheque_leaf_id of a deleted or missing leaf الورقة المختارة غير موجودة. (leaf not found)
cheque_leaf_id on a received cheque (IN) أوراق الدفاتر للشيكات الصادرة وحدها. (book leaves are for issued cheques only)
The leaf does not belong to the cheque_book_id, bank_account_id or bank_name sent الورقة المختارة لا تتبع الدفتر/الحساب/البنك المرسَل. (leaf does not match the book/account/bank sent)
The leaf is not available (reserved · used · damaged) الورقة المختارة غير متاحة — حالتها: {status}. (leaf not available — its status)
cheque_number sent and different from the leaf's number رقم الشيك لا يطابق رقم الورقة المختارة ({n}). (number does not match the leaf)
The leaf's book is not active الدفتر غير نشط. (book not active)
The leaf's number is printed on another cheque of the same bank رقم الشيك {n} موجود بالفعل (مطبوع) على نفس البنك. (number already printed on this bank)
Number reserved in an open batch الرقم :number محجوز في دفعة مفتوحة (الدفعة #:batch) — اطبعها أو ألغِها أولًا.
Duplicate in its context — same company, direction and bank (plus the account for issued · the customer for received, when sent) رقم الشيك {N} مستعمَل بالفعل على بنك {البنك} — اختر رقمًا آخر
Amount too large القيمة كبيرة جدًا — لا يزيد الجزء الصحيح عن 13 خانة.
Fraction digits كسر المبلغ يتجاوز خانات {العملة} (خانتان عشريتان).
Cheque date year before 2000 or after 2100 تاريخ الشيك يجب أن يقع بين سنة 2000 وسنة 2100. (cheque date must fall between 2000 and 2100)
Reference from another company المستفيد لا يتبع شركة الشيك. · الحساب البنكي المختار لا يتبع شركة الشيك. · دفتر الشيكات المختار … · الورقة المختارة لا تتبع شركة الشيك.
Key without a company مفتاح الـAPI غير منسوب لشركة — عيّن شركته من شاشة «التكامل ← مفاتيح API».
company_id contradicts the key الحمولة تطلب شركة «…» بينما مفتاح الـAPI منسوب لشركة «…» — احذف الحقل أو استعمل مفتاح الشركة الصحيحة.

Example

bash
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:

json
{
  "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":["…"]}} — the field is cheque_number, cheque_leaf_id or cheque_book_id depending on the guard; 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.

With cheque_leaf_id: the leaf is locked and checked inside the same save transaction, and the cheque number, book and account come from it (send cheque_number equal to its number, or omit it); it becomes used with the row. On the key path the leaf is not restricted to the book's next leaf — the call records a cheque that was already printed. A resend with the same external_source + external_id returns the existing row (200 reused) and leaves the leaf as it is.

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):

  1. Cheque number in its context: a second call with the same number and bank in the same company and direction (and the same account for issued cheques when sent · the same customer for received ones when partner_id is sent) ⟹ 422 “already used” — treat it as a prior success in your logic.
  2. 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 uses action: "reused" instead).
  3. 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.

Get your free trial