Process Receipts
Sync Processing
When using sync processing, request responds only after the receipt is processed, This method is suitable for scenarios where immediate feedback is required.
Submitting a job:
import axios from "axios";// You can use// - readFile if you're on Node.js// - File input element if you're on browserconst file = ...;const form = new FormData();form.append("image", file);// Optional; Tab-separataed list of category hints// form.append("categories", ["food", "grocery"].join("\t"));const options = { method: "POST", url: "https://eny.gege.mn/api/v1/receipts", headers: { "x-api-key": "your_api_key", // starts with 'eny' }, data: form,};try { const result = await axios.request(options); console.log(result.data);} catch (error) { console.error(error);} Example Response:
{ "id": "6951633d3cb8e19dac7023e8", "status": "completed", "imageSHA256": "f1c47660d7ed1b2852da631fe68dc9f43f088b537b67053819143be58ff8932f", "imageUrl": "https://eny.gege.mn/api/v1/receipts/6951633d3cb8e19dac7023e8/image", "result": { "data": { "items": [ { "name": "FILLET BURGER BOX", "amount": 16000, "currency": "MNT", "quantity": 1, "category": "Food" }, { "name": "PACKAGE +500", "amount": 500, "currency": "MNT", "quantity": 1, "category": "Food" } ], "tax": 1500, "total": 16500, "currency": "MNT", "merchant": "KFC", "date": "2025-12-28T22:15:54.000", "paymentMethod": "card", "receiptNumber": "000412" }, "error": null }, "createdAt": "2025-12-28T17:05:01.165Z", "updatedAt": "2025-12-28T17:05:17.187Z", "completedAt": "2025-12-28T17:05:17.185Z"} Async Processing
For async processing, the request returns immediately with a receipt ID. You can use this ID to check the processing status later.
Submitting an async job:
import axios from "axios";// You can use// - readFile if you're on Node.js// - File input element if you're on browserconst file = ...;const form = new FormData();form.append("image", file);// Optional; Tab-separataed list of category hints// form.append("categories", ["food", "grocery"].join("\t"));const options = { method: "POST", url: "https://eny.gege.mn/api/v1/receipts", params: { async: "" }, // remove async if you want synchronous processing headers: { "x-api-key": "your_api_key", // starts with 'eny' }, data: form,};try { const result = await axios.request(options); console.log(result.data);} catch (error) { console.error(error);} Example Response:
{ "id": "6951633d3cb8e19dac7023e8", "status": "processing", "imageSHA256": "f1c47660d7ed1b2852da631fe68dc9f43f088b537b67053819143be58ff8932f", "createdAt": "2025-12-28T17:05:01.165Z", "updatedAt": "2025-12-28T17:05:01.165Z"} Retrieving job
import axios from "axios";const id = "your_receipt_id"; // e.g., "41870e9a517e4e73b93b9a254204a49d"const options = { method: "GET", url: `https://eny.gege.mn/api/v1/receipts/${id}`, headers: { "x-api-key": "your_api_key", // starts with 'eny' }};try { const result = await axios.request(options); console.log(result.data);} catch (error) { console.error(error);} Example Response:
{ "id": "6951633d3cb8e19dac7023e8", "status": "completed", "imageSHA256": "f1c47660d7ed1b2852da631fe68dc9f43f088b537b67053819143be58ff8932f", "imageUrl": "https://eny.gege.mn/api/v1/receipts/6951633d3cb8e19dac7023e8/image", "result": { "data": { "items": [ { "name": "FILLET BURGER BOX", "amount": 16000, "currency": "MNT", "quantity": 1, "category": "Food" }, { "name": "PACKAGE +500", "amount": 500, "currency": "MNT", "quantity": 1, "category": "Food" } ], "tax": 1500, "total": 16500, "currency": "MNT", "merchant": "KFC", "date": "2025-12-28T22:15:54.000", "paymentMethod": "card", "receiptNumber": "000412" }, "error": null }, "createdAt": "2025-12-28T17:05:01.165Z", "updatedAt": "2025-12-28T17:05:17.187Z", "completedAt": "2025-12-28T17:05:17.185Z"} Receipt fields
A completed receipt has its data under result.data. Only items and total are
always present; every other field appears only when it is printed on the receipt.
items: purchased items, each withname,amount(line total),currency,quantity,unitPriceandcategorysubtotal: sum before tax, tip and receipt-level discountsdiscount: receipt-level discounts, as a positive numbertax: total tax amount (VAT, GST, sales tax…)tip: tip, gratuity or service chargetotal: final amount paid, after discounts and including tax and tipcurrency: ISO 4217 currency codemerchant,address,tel,website,email: merchant detailscategory: category of the purchase as a wholedate: ISO 8601 date in the receipt’s local time, without a timezonepaymentMethod: one ofcash,card,mobile,transfer,voucher,otherreceiptNumber: receipt, invoice or order number
To get categories, send your own list as a tab-separated categories form field with
the upload, or save a list in the dashboard. Categories are always picked from that list.
The full JSON Schema is available at /api/schema/25001.
Failed receipts
When a receipt cannot be processed, its status is failed, result.data is null and result.error.message explains why. An image that is not a receipt fails with
“The image does not appear to be a receipt”. A failed receipt does not use a credit.
Long polling
Long polling allows you to wait for the server to provide the processing result.
You can combine this with async processing by making your initial request in a non-blocking manner. Max waiting period is 30 seconds, and you can reconnect if the connection drops.
The response is never cached, so you can call it again right away if the job has not finished yet.
import axios from "axios";const id = "your_receipt_id"; // e.g., "41870e9a517e4e73b93b9a254204a49d"const options = { method: "GET", url: `https://eny.gege.mn/api/v1/receipts/${id}`, headers: { "x-api-key": "your_api_key", // starts with 'eny' }};try { const result = await axios.request(options); console.log(result.data);} catch (error) { console.error(error);} Example Response:
This endpoint only reports whether processing has finished, so fetch the processed
receipt afterwards, i.e., GET /v1/receipts/:id
{ "hasFinishedProcessing": true}