DDinarGuard

Developer documentation

DinarGuard API reference

Everything here is based on the current public DinarGuard API routes, request schemas, response serializers, and webhook signing behavior.

Quickstart

How the flow works

  1. 1

    Register merchant

    Create a merchant and receive merchant_id, api_key, and webhook_secret by email.

  2. 2

    Connect Telegram

    Open the DinarGuard bot, send /start, then send the Telegram connect command from your credentials email.

  3. 3

    Create payment

    Your backend creates a session with amount, metadata, and webhook URL.

  4. 4

    Upload receipt

    Your backend uploads the receipt image. DinarGuard extracts fields, validates them, and sends Telegram review.

Base URL

Authentication

Merchant API routes use Authorization: Bearer YOUR_API_KEY. Keep the API key server-side. DinarGuard only sends credentials when they are generated and never returns them in API responses.

Base URL: https://dinarguard.mohamedazizheni.tn

Authorization: Bearer dg_live_your_api_key

Endpoint map

Available API routes

POST/api/v1/merchants/register

Create a merchant and receive credentials by email.

Auth
No API key required
POST/api/v1/payment-sessions

Create a D17 payment session.

Auth
Bearer API key
POST/api/v1/payment-sessions/{paymentId}/screenshot

Upload a customer receipt screenshot.

Auth
Bearer API key
GET/api/v1/payment-sessions/{paymentId}

Fetch one payment session.

Auth
Bearer API key
GET/api/v1/payments

List merchant payments.

Auth
Bearer API key
POST/api/v1/payment-sessions/{paymentId}/cancel

Cancel a payment that is not finalized.

Auth
Bearer API key
POST/api/v1/payment-sessions/{paymentId}/webhook/retry

Manually retry webhook delivery for a payment.

Auth
Bearer API key

Merchant registration

POST /api/v1/merchants/register

This endpoint creates a merchant, generates an API key and webhook secret, emails the credentials, then returns public merchant details.

FieldTypeNotes
business_namestringRequired. 2 to 120 chars. Must be unique case-insensitively.
contact_emailemailRequired. Max 200 chars. Must be unique case-insensitively.
d17_receiver_phonestringRequired. Must normalize to a valid Tunisian phone number.
d17_receiver_namestringOptional. Max 120 chars. Defaults to business_name.
curl -X POST https://dinarguard.mohamedazizheni.tn/api/v1/merchants/register \
  -H "Content-Type: application/json" \
  -d '{
    "business_name": "Demo Store",
    "contact_email": "owner@example.com",
    "d17_receiver_phone": "+21699980126",
    "d17_receiver_name": "Demo Store"
  }'

Create session

POST /api/v1/payment-sessions

FieldTypeNotes
amountnumberRequired. Positive amount. Stored with 3 decimals.
currency"TND"Optional. Defaults to TND. No other currency is accepted.
external_customer_idstringOptional. 1 to 200 chars. Your customer or order reference.
descriptionstringOptional. Up to 500 chars.
webhook_urlurlRequired. Must be HTTPS, no credentials, public IP. Blocked private/local IPs. Max 10s timeout.
metadataobjectOptional. Defaults to {}. Returned in payment objects and webhooks.
expires_in_minutesintegerOptional. 5 to 1440. Defaults to 120.
curl -X POST https://dinarguard.mohamedazizheni.tn/api/v1/payment-sessions \
  -H "Authorization: Bearer dg_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 50,
    "currency": "TND",
    "external_customer_id": "client_123",
    "description": "Monthly plan",
    "webhook_url": "https://your-app.com/api/dinarguard",
    "metadata": { "order_id": "order_789" },
    "expires_in_minutes": 120
  }'

Payment object

Response fields

FieldTypeNotes
payment_idstringPayment ID, generated with pay_ prefix.
statusstringExternal status: pending, processing, provisional, needs_review, approved, rejected, expired.
internal_statusstringDetailed status returned by the current API response.
amountnumberExpected amount.
currencystringCurrency. Currently TND.
external_customer_idstring | nullYour customer reference.
descriptionstring | nullOptional payment description.
webhook_urlstringCallback URL used for this payment.
metadataobjectYour metadata object.
extractedobjectReceipt extraction result.
validation_errorsarrayValidation error codes saved for the payment.
expires_atstringISO timestamp.
created_atstringISO timestamp.
updated_atstringISO timestamp.
{
  "payment_id": "pay_abc123",
  "status": "pending",
  "internal_status": "created",
  "amount": 50,
  "currency": "TND",
  "external_customer_id": "client_123",
  "description": "Monthly plan",
  "webhook_url": "https://your-app.com/api/dinarguard",
  "metadata": { "order_id": "order_789" },
  "extracted": {
    "sender_name": null,
    "sender_phone": null,
    "transaction_number": null,
    "amount": null,
    "currency": null,
    "payment_datetime": null,
    "confidence_score": null
  },
  "validation_errors": [],
  "expires_at": "2026-05-11T12:00:00.000Z",
  "created_at": "2026-05-11T10:00:00.000Z",
  "updated_at": "2026-05-11T10:00:00.000Z"
}

Receipt upload

POST /api/v1/payment-sessions/{paymentId}/screenshot

Uploads must be multipart form data. The image must be JPEG, PNG, or WebP and 5 MB or smaller. Duplicate screenshots for the same merchant return 409.

FieldTypeNotes
fileFileRequired multipart field. Must be JPEG, PNG, or WebP. Max 5MB. Production ignores merchant OCR overrides.
curl -X POST https://dinarguard.mohamedazizheni.tn/api/v1/payment-sessions/pay_abc123/screenshot \
  -H "Authorization: Bearer dg_live_your_api_key" \
  -F "file=@receipt.png"

Statuses

Status mapping

Detailed statusAPI statusMeaning
createdpendingPayment session was created. No receipt uploaded yet.
screenshot_uploadedpendingReceipt was accepted by the API.
processingprocessingReceipt is being extracted and checked.
extraction_failedneeds_reviewReceipt extraction failed.
validation_failedneeds_reviewValidation did not pass.
needs_reviewneeds_reviewTelegram review is expected.
provisionally_approvedprovisionalValidation passed and provisional access is enabled.
approvedapprovedTelegram approved the payment.
rejectedrejectedTelegram rejected the payment.
expiredexpiredPayment expired or was cancelled.

Validation

Receipt checks

DinarGuard compares extracted receipt data against the payment row and merchant receiver phone. These are the validation codes saved in validation_errors.

CodeMeaning
amount_mismatchExtracted amount is missing or differs from the session amount.
currency_mismatchExtracted currency exists and is not TND.
missing_transaction_numberNo authorization or transaction number was extracted.
duplicate_transaction_numberAnother payment for the same merchant already used this transaction number.
invalid_sender_phoneSender phone was present but not a valid Tunisian phone.
receiver_phone_mismatchExtracted receiver phone differs from the merchant D17 receiver phone.
low_confidenceExtraction confidence is below 0.65.
extraction_failedReceipt extraction threw an error.

Webhooks

Signed payment events

Webhooks are delivered when payments are approved, rejected, expired, cancelled through the cancel endpoint, or retried manually. The event name is payment. plus the external status.

Headers:
content-type: application/json
x-dinarguard-timestamp: 1778493600
x-dinarguard-signature: hmac_sha256_hex

Signature input:
timestamp + "." + raw_request_body

Payload:
{
  "event_id": "evt_abc123",
  "event": "payment.approved",
  "payment_id": "pay_abc123",
  "status": "approved",
  "amount": 50,
  "currency": "TND",
  "external_customer_id": "client_123",
  "metadata": { "order_id": "order_789" }
}

Errors

HTTP error behavior

Error responses use JSON with an error string. Some validation failures also include a details object, and duplicate screenshots include duplicate_payment_id.

StatusWhen it happens
400Invalid JSON body, invalid schema fields, invalid phone, invalid multipart form, missing file, invalid image type, or image larger than 5 MB.
401Missing or invalid authorization.
404Payment not found, or payment no longer cancelable.
409Duplicate merchant registration field, duplicate screenshot, or finalized payment upload.
429Too many requests. Rate limit exceeded.
500Receipt upload failed or another server error occurred.
502Merchant registration credentials email could not be sent.

Listing and actions

Fetch, list, cancel, retry

GET https://dinarguard.mohamedazizheni.tn/api/v1/payment-sessions/pay_abc123
Authorization: Bearer dg_live_your_api_key
GET https://dinarguard.mohamedazizheni.tn/api/v1/payments?status=approved&limit=50
Authorization: Bearer dg_live_your_api_key

limit is capped at 100.
POST https://dinarguard.mohamedazizheni.tn/api/v1/payment-sessions/pay_abc123/cancel
Authorization: Bearer dg_live_your_api_key

Sets the payment status to expired.
POST https://dinarguard.mohamedazizheni.tn/api/v1/payment-sessions/pay_abc123/webhook/retry
Authorization: Bearer dg_live_your_api_key

Data model

Public API data groups

These are public API data groups developers interact with. Internal storage details are intentionally omitted from the public docs.

Merchant credentials

merchant_idapi_keywebhook_secret

Payment session

payment_idstatusamountcurrencyexternal_customer_idmetadataexpires_at

Receipt extraction

sender_phonetransaction_numberamountcurrencyconfidence_scorevalidation_errors

Webhook event

event_ideventpayment_idstatusamountcurrencymetadata