Developers
Integrate the OCR API server to server
The bearer token gives access to your Easypromos OCR API. Never expose it in public JavaScript, HTML source, browser requests, or frontend environment variables shipped to the client.
Utility
Check available OCR credits
Use the credits endpoint from your backend to check remaining balance before submitting volume traffic.
curl -X GET "https://api.easypromosapp.com/v2/ocr/credits" \
-H "Authorization: Bearer $TOKEN"
<?php
$token = getenv('EASYPROMOS_API_TOKEN');
$credits = curl_init('https://api.easypromosapp.com/v2/ocr/credits');
curl_setopt_array($credits, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $token,
],
]);
$creditsResponse = json_decode(curl_exec($credits), true);
curl_close($credits);
import os
import requests
token = os.environ["EASYPROMOS_API_TOKEN"]
credits = requests.get(
"https://api.easypromosapp.com/v2/ocr/credits",
headers={"Authorization": f"Bearer {token}"},
timeout=30,
)
credits.raise_for_status()
print(credits.json())
require "net/http"
token = ENV.fetch("EASYPROMOS_API_TOKEN")
uri = URI("https://api.easypromosapp.com/v2/ocr/credits")
request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer #{token}"
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts response.body
import fetch from "node-fetch";
const token = process.env.EASYPROMOS_API_TOKEN;
const credits = await fetch("https://api.easypromosapp.com/v2/ocr/credits", {
headers: {
Authorization: `Bearer ${token}`,
},
});
console.log(await credits.json());
import fetch from "node-fetch";
type CreditsResponse = {
credits: number;
currency: string;
};
const token = process.env.EASYPROMOS_API_TOKEN;
if (!token) {
throw new Error("Missing EASYPROMOS_API_TOKEN");
}
const credits = await fetch("https://api.easypromosapp.com/v2/ocr/credits", {
headers: {
Authorization: `Bearer ${token}`,
},
});
console.log((await credits.json()) as CreditsResponse);
Sample response:
{
"status": "ok",
"credits": 1248,
"currency": "USD",
"updated_at": "2026-04-08T09:29:00Z"
}
Security
Keep the bearer token private
Your backend should upload receipts, poll events, and receive webhooks directly from Easypromos. The browser must never talk to the OCR API with your account token.
Mode 1
Polling workflow
Upload the receipt, store the returned event_id, then poll the event endpoint until you receive the final structured JSON.
curl -X POST "https://api.easypromosapp.com/v2/ocr/tickets" \
-H "Authorization: Bearer $TOKEN" \
-F "ticket=@receipt.jpg"
<?php
$token = getenv('EASYPROMOS_API_TOKEN');
$upload = curl_init('https://api.easypromosapp.com/v2/ocr/tickets');
curl_setopt_array($upload, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $token,
],
CURLOPT_POSTFIELDS => [
'ticket' => new CURLFile(__DIR__ . '/receipt.jpg'),
],
]);
$uploadResponse = json_decode(curl_exec($upload), true);
curl_close($upload);
import os
import requests
token = os.environ["EASYPROMOS_API_TOKEN"]
headers = {"Authorization": f"Bearer {token}"}
with open("receipt.jpg", "rb") as receipt:
upload = requests.post(
"https://api.easypromosapp.com/v2/ocr/tickets",
headers=headers,
files={"ticket": receipt},
timeout=30,
)
upload.raise_for_status()
print(upload.json())
require "net/http"
require "json"
token = ENV.fetch("EASYPROMOS_API_TOKEN")
uri = URI("https://api.easypromosapp.com/v2/ocr/tickets")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer #{token}"
request.set_form([["ticket", File.open("receipt.jpg")]], "multipart/form-data")
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts response.body
import fs from "node:fs";
import fetch from "node-fetch";
import FormData from "form-data";
const token = process.env.EASYPROMOS_API_TOKEN;
const form = new FormData();
form.append("ticket", fs.createReadStream("./receipt.jpg"));
const upload = await fetch("https://api.easypromosapp.com/v2/ocr/tickets", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
},
body: form,
});
console.log(await upload.json());
import fs from "node:fs";
import fetch from "node-fetch";
import FormData from "form-data";
type UploadResponse = {
event_id: number;
};
const token = process.env.EASYPROMOS_API_TOKEN;
if (!token) {
throw new Error("Missing EASYPROMOS_API_TOKEN");
}
const form = new FormData();
form.append("ticket", fs.createReadStream("./receipt.jpg"));
const upload = await fetch("https://api.easypromosapp.com/v2/ocr/tickets", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
},
body: form,
});
console.log((await upload.json()) as UploadResponse);
Upload response with the generated event_id:
{
"status": "ok",
"event_id": 987654,
"created_at": "2026-04-08T09:30:00Z"
}
curl -X GET "https://api.easypromosapp.com/v2/ocr/events/987654" \
-H "Authorization: Bearer $TOKEN"
<?php
$token = getenv('EASYPROMOS_API_TOKEN');
$eventId = 987654;
$poll = curl_init('https://api.easypromosapp.com/v2/ocr/events/' . $eventId);
curl_setopt_array($poll, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $token,
],
]);
$eventResponse = json_decode(curl_exec($poll), true);
curl_close($poll);
import os
import requests
token = os.environ["EASYPROMOS_API_TOKEN"]
event_id = 987654
event = requests.get(
f"https://api.easypromosapp.com/v2/ocr/events/{event_id}",
headers={"Authorization": f"Bearer {token}"},
timeout=30,
)
event.raise_for_status()
print(event.json())
require "net/http"
token = ENV.fetch("EASYPROMOS_API_TOKEN")
event_id = 987654
uri = URI("https://api.easypromosapp.com/v2/ocr/events/#{event_id}")
request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer #{token}"
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts response.body
import fetch from "node-fetch";
const token = process.env.EASYPROMOS_API_TOKEN;
const eventId = 987654;
const event = await fetch(`https://api.easypromosapp.com/v2/ocr/events/${eventId}`, {
headers: {
Authorization: `Bearer ${token}`,
},
});
console.log(await event.json());
import fetch from "node-fetch";
const token = process.env.EASYPROMOS_API_TOKEN;
if (!token) {
throw new Error("Missing EASYPROMOS_API_TOKEN");
}
const eventId = 987654;
const event = await fetch(`https://api.easypromosapp.com/v2/ocr/events/${eventId}`, {
headers: {
Authorization: `Bearer ${token}`,
},
});
console.log(await event.json());
Finished poll response:
{
"status": "finished",
"event_id": 987654,
"finished_status": "ok",
"result": {
"header": {
"store_name": "CLAREL",
"store_address": "AV PRIMERO DE JUNIO 66",
"tax_id": "A43227628",
"phone": "+34912345678",
"date": "2025-09-24",
"time": "20:08",
"receipt_number": "00309139",
"currency": "EUR",
"city": "Venta de Banos",
"postal_code": "34200",
"country": "Spain",
"country_code": "ES",
"timezone": "Europe/Madrid",
"utc_date_time": "2025-09-24T20:08:00+02:00"
},
"line_items": [
{
"article": "SERUM REVITALIFT LAS",
"sku": "171752",
"quantity": 1,
"total": 24.19
},
{
"article": "CREMA REVITALIF LASE",
"sku": "155687",
"quantity": 1,
"total": 22.09
},
{
"article": "DETER MAQU CAPSULA O",
"sku": "308872",
"quantity": 1,
"total": 9.99
},
{
"article": "ESPUMA PERFECT VOLUM",
"sku": "290794",
"quantity": 1,
"total": 5.49
},
{
"article": "LACA PERFECT VOLUMEN",
"sku": "290790",
"quantity": 1,
"total": 5.29
}
],
"footer": {
"total": 37.87
},
"controls": {
"handwritten": 0,
"text_quality": 95
}
},
"processed_at": "2026-04-08 09:30:18"
}
Mode 2
Webhook workflow
Upload the receipt with webhook_url and webhook_key. Easypromos will call your backend when processing finishes.
curl -X POST "https://api.easypromosapp.com/v2/ocr/tickets" \
-H "Authorization: Bearer $TOKEN" \
-F "ticket=@receipt.jpg" \
-F "webhook_url=https://your-app.example/webhooks/easypromos" \
-F "webhook_key=your-shared-secret"
<?php
$token = getenv('EASYPROMOS_API_TOKEN');
$request = curl_init('https://api.easypromosapp.com/v2/ocr/tickets');
curl_setopt_array($request, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $token,
],
CURLOPT_POSTFIELDS => [
'ticket' => new CURLFile(__DIR__ . '/receipt.jpg'),
'webhook_url' => 'https://your-app.example/webhooks/easypromos',
'webhook_key' => 'your-shared-secret',
],
]);
$response = json_decode(curl_exec($request), true);
curl_close($request);
import os
import requests
token = os.environ["EASYPROMOS_API_TOKEN"]
headers = {"Authorization": f"Bearer {token}"}
with open("receipt.jpg", "rb") as receipt:
response = requests.post(
"https://api.easypromosapp.com/v2/ocr/tickets",
headers=headers,
files={"ticket": receipt},
data={
"webhook_url": "https://your-app.example/webhooks/easypromos",
"webhook_key": "your-shared-secret",
},
timeout=30,
)
response.raise_for_status()
print(response.json())
require "net/http"
token = ENV.fetch("EASYPROMOS_API_TOKEN")
uri = URI("https://api.easypromosapp.com/v2/ocr/tickets")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer #{token}"
request.set_form(
[
["ticket", File.open("receipt.jpg")],
["webhook_url", "https://your-app.example/webhooks/easypromos"],
["webhook_key", "your-shared-secret"]
],
"multipart/form-data"
)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts response.body
import fs from "node:fs";
import fetch from "node-fetch";
import FormData from "form-data";
const token = process.env.EASYPROMOS_API_TOKEN;
const form = new FormData();
form.append("ticket", fs.createReadStream("./receipt.jpg"));
form.append("webhook_url", "https://your-app.example/webhooks/easypromos");
form.append("webhook_key", "your-shared-secret");
const response = await fetch("https://api.easypromosapp.com/v2/ocr/tickets", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
},
body: form,
});
console.log(await response.json());
import fs from "node:fs";
import fetch from "node-fetch";
import FormData from "form-data";
const token = process.env.EASYPROMOS_API_TOKEN;
if (!token) {
throw new Error("Missing EASYPROMOS_API_TOKEN");
}
const form = new FormData();
form.append("ticket", fs.createReadStream("./receipt.jpg"));
form.append("webhook_url", "https://your-app.example/webhooks/easypromos");
form.append("webhook_key", "your-shared-secret");
const response = await fetch("https://api.easypromosapp.com/v2/ocr/tickets", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
},
body: form,
});
console.log(await response.json());
Webhook payload sent by Easypromos:
{
"event_id": 987654,
"status": "finished",
"finished_status": "ok",
"result": {
"header": {
"store_name": "CLAREL",
"store_address": "AV PRIMERO DE JUNIO 66",
"tax_id": "A43227628",
"phone": "+34912345678",
"date": "2025-09-24",
"time": "20:08",
"receipt_number": "00309139",
"currency": "EUR",
"city": "Venta de Banos",
"postal_code": "34200",
"country": "Spain",
"country_code": "ES",
"timezone": "Europe/Madrid",
"utc_date_time": "2025-09-24T20:08:00+02:00"
},
"line_items": [
{
"article": "SERUM REVITALIFT LAS",
"sku": "171752",
"quantity": 1,
"total": 24.19
},
{
"article": "CREMA REVITALIF LASE",
"sku": "155687",
"quantity": 1,
"total": 22.09
},
{
"article": "DETER MAQU CAPSULA O",
"sku": "308872",
"quantity": 1,
"total": 9.99
},
{
"article": "ESPUMA PERFECT VOLUM",
"sku": "290794",
"quantity": 1,
"total": 5.49
},
{
"article": "LACA PERFECT VOLUMEN",
"sku": "290790",
"quantity": 1,
"total": 5.29
}
],
"footer": {
"total": 37.87
},
"controls": {
"handwritten": 0,
"text_quality": 95
}
},
"processed_at": "2026-04-08 09:30:18"
}