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 browser
const 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);
}
file.js

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"
        }
      ],
      "total": 16500,
      "currency": "MNT",
      "merchant": "KFC",
      "date": "2025-12-28T22:15:54.000"
    },
    "error": null
  },
  "createdAt": "2025-12-28T17:05:01.165Z",
  "updatedAt": "2025-12-28T17:05:17.187Z",
  "completedAt": "2025-12-28T17:05:17.185Z"
}
GET /v1/receipts/:id

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 browser
const 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);
}
file.js

Example Response:

{
  "id": "6951633d3cb8e19dac7023e8",
  "status": "processing",
  "imageSHA256": "f1c47660d7ed1b2852da631fe68dc9f43f088b537b67053819143be58ff8932f",
  "createdAt": "2025-12-28T17:05:01.165Z",
  "updatedAt": "2025-12-28T17:05:01.165Z"
}
POST /v1/receipts?async

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);
}
file.js

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"
        }
      ],
      "total": 16500,
      "currency": "MNT",
      "merchant": "KFC",
      "date": "2025-12-28T22:15:54.000"
    },
    "error": null
  },
  "createdAt": "2025-12-28T17:05:01.165Z",
  "updatedAt": "2025-12-28T17:05:17.187Z",
  "completedAt": "2025-12-28T17:05:17.185Z"
}
GET /v1/receipts/:id

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.

When the job has completed/failed, you will receive Cache-Control header with long-term caching instructions for the endpoint. (e.g., ‘public, max-age=31536000, immutable’)

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);
}
file.js

Example Response:

This endpoint is public, so you’d need to refetch the processed receipt. i.e., GET /v1/receipts/:id

{
  "hasFinishedProcessing": true
}
GET /v1/receipts/:id/longpoll