The Data Matrix Code Generator API turns one value into one Data Matrix (ECC 200) code, as an SVG or a PNG. Call it with a URL (GET) or a JSON body (POST). There is no key and nothing to install, and it uses the same encoder as the Data Matrix generator on this site. For many codes at once without code, use the bulk generator in your browser.
Quick start
The simplest call is a URL. Paste it into a browser, or use it as an image source:
https://datamatrixcodegenerator.com/api/v1/datamatrix?data=PART-000123&format=svgHTML
An image tag is enough. The browser fetches the code; after the first request it comes from cache.
<img src="https://datamatrixcodegenerator.com/api/v1/datamatrix?data=PART-000123&format=svg" alt="Data Matrix code">In Markdown (a README, a wiki page):
curl
GET saves a PNG with 8 pixels per module:
curl -o datamatrix.png 'https://datamatrixcodegenerator.com/api/v1/datamatrix?data=PART-000123&format=png&scale=8'POST sends the same request as JSON, which keeps the value out of the URL:
curl -X POST https://datamatrixcodegenerator.com/api/v1/datamatrix \
-H 'Content-Type: application/json' \
-d '{"data":"PART-000123","format":"png","scale":8}' \
-o datamatrix.pngJavaScript (fetch)
Works in the browser (CORS is open to every origin) and in Node 18 or later. Errors come back as JSON with a code and a message.
const res = await fetch("https://datamatrixcodegenerator.com/api/v1/datamatrix", {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
"data": "PART-000123",
"format": "svg"
}),
});
if (!res.ok) {
const { error } = await res.json();
throw new Error(`${error.code}: ${error.message}`);
}
const svg = await res.text(); // image/svg+xml
document.querySelector('#code').innerHTML = svg;Python (requests)
import requests
r = requests.post(
"https://datamatrixcodegenerator.com/api/v1/datamatrix",
json={"data": "PART-000123", "format": "png", "scale": 8},
timeout=10,
)
if r.status_code != 200:
raise SystemExit(r.json()["error"]["message"])
with open("datamatrix.png", "wb") as f:
f.write(r.content)Excel and Google Sheets
Put your values in column A, this formula in B2, and fill it down. Spreadsheets show PNG, not SVG, so the URL asks for format=png. The cell must be large enough to show the
squares clearly.
=IMAGE("https://datamatrixcodegenerator.com/api/v1/datamatrix?format=png&scale=8&data="&ENCODEURL(A2))- Google Sheets and Excel for Windows (Microsoft 365) understand the formula as written.
- Excel for Mac and Excel for the web have
IMAGE()but notENCODEURL(). If your values are only letters, digits and- . _ ~, leave it out:=IMAGE("https://datamatrixcodegenerator.com/api/v1/datamatrix?format=png&scale=8&data="&A2) - Excel needs a URL under 255 characters and does not follow redirects. The API answers directly, with no redirect.
- Spreadsheet apps may fetch images through their own servers, so many sheets can share one connection's limit. Repeated values come from cache and do not count.
Values in a URL are not private
With GET, the value is part of the URL, so it is stored wherever the URL is: the spreadsheet, browser history, proxies and log files. Use POST for confidential data.
Endpoints
All endpoints are on https://datamatrixcodegenerator.com under /api/v1/, over HTTPS only.
| Request | Returns | Use it for |
|---|---|---|
GET /api/v1/datamatrix?data=… | SVG or PNG | Image tags, spreadsheets, quick tests. Cached at our edge; browsers recheck daily. |
HEAD /api/v1/datamatrix?data=… | Headers only | Checking the symbol size or image size without the image. |
POST /api/v1/datamatrix | SVG or PNG | Software. A JSON body keeps the value out of URLs and logs. |
POST /api/v1/datamatrix/info | JSON | What would be drawn: symbol size, codewords used, the exact bytes, GS1 fields, notices. |
OPTIONS (any of the above) | 204 | CORS preflight. Browsers send it for you. |
POST bodies are a JSON object with the same parameter names as the URL, sent with Content-Type: application/json. Numbers and true/false may be JSON numbers and
booleans, but send data as a string, so leading zeros are kept.
Metadata: POST /info
Same parameters, no image. This is a real answer for the GS1 example below:
curl -X POST https://datamatrixcodegenerator.com/api/v1/datamatrix/info \
-H 'Content-Type: application/json' \
-d '{"data":"(01)09506000134352(17)271231(10)AB12","gs1":true}'Show the JSON answer
{
"engineVersion": "2.0.1",
"symbol": {
"size": "18x18",
"rows": 18,
"columns": 18,
"shape": "square",
"dmre": false,
"dataRegions": {
"vertical": 1,
"horizontal": 1
},
"dataCodewords": 18,
"usedCodewords": 17,
"fill": 0.944,
"capacity": {
"numeric": 36,
"alphanumeric": 25,
"bytes": 16
}
},
"data": {
"characters": 36,
"bytes": 30,
"hex": "30 31 30 39 35 30 36 30 30 30 31 33 34 33 35 32 31 37 32 37 31 32 33 31 31 30 41 42 31 32",
"charset": "ascii",
"eci": null,
"gs1": true
},
"gs1": {
"hri": "(01)09506000134352(17)271231(10)AB12",
"elementString": "01095060001343521727123110AB12",
"fields": [
{
"ai": "01",
"title": "Product number (GTIN)",
"value": "09506000134352"
},
{
"ai": "17",
"title": "Expiry date",
"value": "271231",
"readable": "31 Dec 2027"
},
{
"ai": "10",
"title": "Batch or lot number",
"value": "AB12"
}
],
"dictionaryRelease": "2026-01-27"
},
"image": {
"format": "svg",
"scale": 10,
"quiet": 2,
"widthPx": 220,
"heightPx": 220,
"captionAdded": false
},
"notices": []
} data.hex is the exact bytes in the code (FNC1 is a symbol character, not a byte, so it is not listed). notices lists warnings such as "UTF-8 with ECI: test your
scanner" or "transparent background", which the image endpoint does not report.
Parameters
Only data is required. Names are lower case. Booleans accept true/false, 1/0, yes/no. Unknown names are ignored and listed in the X-Ignored-Parameters header, so a typo is easy to spot. A parameter given
twice is an error.
What to draw
| Parameter | Values | Default | What it does |
|---|---|---|---|
data | text, up to 3,116 digits (fewer for other characters) | required | What to encode, exactly as sent: leading zeros, spaces and case are kept. In JSON, send it as a string, not a number. |
format | svg | png | svg | SVG is vector and scales to any size. PNG is a 1-bit image with whole pixels per module. |
gs1 | true | false | false | GS1 DataMatrix. Send (AI)value pairs such as (01)09506000134352(17)271231(10)AB12. Check digits, dates and field lengths are checked; FNC1 and separators are added for you. |
shape | square | rectangle | dmre | square | rectangle uses the 6 standard ECC 200 rectangles. dmre also allows the 18 DMRE rectangles (ISO/IEC 21471), which many older scanners cannot read. Ignored when size names a size. |
size | auto | RxC | auto | Force one symbol size, rows x columns, such as 24x24 or 16x48. If the data does not fit, the error names the smallest size that does. |
Image size
| Parameter | Values | Default | What it does |
|---|---|---|---|
scale or module | 1–40 | 10 | Whole pixels per module (each small square). The image is (columns + 2 x quiet) x scale pixels wide. |
width | 10–4,000 px | none | Target image width in pixels, quiet zone included. The API picks the largest whole number of pixels per module that fits, so the image can be a little narrower. Use it instead of scale. |
quiet | 1–10 modules | 2 | Blank border (quiet zone) on every side, in whole modules. It never goes below 1 module. |
module_mm SVG only | 0.05–20 mm | none | Module size in millimeters. The SVG gets width and height in mm, so it prints at true size. |
dpi PNG only | 72–2,400 | 300 | Resolution stored in the PNG (pHYs), so print and layout apps know the intended size. It does not change the pixels. |
Text and look
| Parameter | Values | Default | What it does |
|---|---|---|---|
charset | auto | latin1 | utf8 | utf8-eci | auto | auto sends ASCII and Latin-1 as single bytes, and anything else as UTF-8 with an ECI flag. utf8 skips the flag, which some scanners prefer. Ignored in GS1 mode. |
escapes | true | false | false | Read \n \r \t \G (group separator) \R \E \xHH and \\ in data. Off: backslashes are encoded as typed. Not used in GS1 mode. |
dark or color, fg | hex color | 000000 | Color of the modules, as 3 or 6 hex digits, with or without #. It must be darker than light (no inverted codes). |
light or bg, background | hex color | transparent | ffffff | Background color. The pair must have enough contrast to scan. transparent leaves the background empty: place the code on a plain, light surface. |
caption SVG only | text, up to 200 characters | none | One line of text under the code, outside the quiet zone. |
download | true | false | file name | false | Asks the browser to save the file (Content-Disposition: attachment). A name (letters, digits, - _ .) sets the file name; the extension is added for you. |
Image size: a PNG is (columns + 2 × quiet) × scale pixels wide. The default 14 × 14 code for PART-000123 at scale 10 with a 2-module quiet zone is
180 × 180 pixels. Pixels per module are always whole, so edges stay sharp; nothing is stretched or smoothed.
Responses and headers
A successful request returns 200 and the image. These headers describe it, and every one is readable from browser code (CORS exposes them):
| Header | Example | Meaning |
|---|---|---|
Content-Type | image/svg+xml; charset=utf-8 or image/png | The format you asked for. |
Cache-Control | public, max-age=86400, s-maxage=31536000, stale-while-revalidate=604800 | GET only: browsers keep it a day, then recheck with the ETag. POST answers are no-store. |
ETag | "2301bf754d8f438cc832c01335acd8a5" | Changes only when the image would change. Send it back as If-None-Match to get 304. |
X-Cache | HIT or MISS | GET only. HIT means our edge served a stored copy (free: it does not count). |
X-Symbol-Size | 14x14 | The symbol size used, rows x columns. |
X-Symbol-Rows, X-Symbol-Columns | 14, 14 | The same as two numbers. |
X-Symbol-Codewords | 8/8 | Data codewords used out of those the size holds. |
X-Image-Width, X-Image-Height | 180, 180 | Pixels, quiet zone included. Absent for an SVG sized in mm. |
X-Engine-Version | 2.0.1 | The encoder version that drew the image. |
X-Ignored-Parameters | v, t | Names you sent that the API does not know (a typo shows up here). |
Content-Disposition | inline, or attachment; filename="…" | attachment when you set download. |
Content-Security-Policy | default-src 'none'; …; sandbox | SVG only: an opened SVG can never run scripts or load anything. |
Every response also carries Access-Control-Allow-Origin: * (no cookies or credentials), X-Content-Type-Options: nosniff and
Cross-Origin-Resource-Policy: cross-origin, so the images embed on any page.
Errors
Errors return JSON with an HTTP status that matches the problem, and are never cached. code is stable and safe to branch on; message is for people;
hint says what to change; param names the parameter; detail is the encoder's own reason. This is a real error, for 100 characters forced into a
10 × 10 code:
{
"error": {
"code": "data_not_encodable",
"message": "This text does not fit in a 10 × 10 code. It needs at least 36 × 36.",
"hint": "Use size=auto, or size=36x36 or larger.",
"param": "size",
"detail": "does-not-fit-size",
"docs": "https://datamatrixcodegenerator.com/data-matrix-api/#errors"
}
}Request problems
| Status | Code | Meaning |
|---|---|---|
| 400 | missing_data | No data was sent, or it was empty. |
| 400 | invalid_parameter | A parameter has the wrong type or is out of range. param names it. |
| 400 | bad_request | The POST body is not a JSON object. |
| 404 | not_found | There is no endpoint at that path. |
| 405 | method_not_allowed | The method is not supported here. The Allow header lists the ones that are. |
| 413 | data_too_long | data is longer than any symbol can hold (the largest, 144x144, takes 3,116 digits, 2,335 capital letters or 1,556 bytes). |
| 413 | payload_too_large | The POST body is larger than 32 KB. |
| 415 | unsupported_media_type | A POST without Content-Type: application/json. |
Data problems
| Status | Code | Meaning |
|---|---|---|
| 422 | data_not_encodable | The data does not fit the size or shape you chose, uses a character the charset cannot hold, or has a bad escape. detail gives the reason. |
| 422 | gs1_invalid | GS1 data failed a syntax check, such as a wrong check digit or an impossible date. detail names the check. |
| 422 | colors_not_scannable | The colors are inverted (light modules on a dark background) or too close in brightness to scan. |
| 422 | image_too_large | The image would be more than 4,000 pixels on a side. Lower scale or width. |
Limits and server
| Status | Code | Meaning |
|---|---|---|
| 429 | rate_limited | Too many new images from one connection. Wait the number of seconds in Retry-After. |
| 500 | server_error | Something failed on our side. Retry later, and tell us if it keeps happening. |
The API never shortens your data to make it fit. If it does not fit, you get 422 and the smallest size that would work.
Limits and fair use
The API is free and has no key, so it has limits that keep it fast for everyone:
- 2,000 new images a day per connection. Short bursts above about 60 a minute may also be slowed. Over the daily limit, or in a large burst, you get
429and aRetry-Afterheader in seconds. - Cached GET repeats are free. A GET our edge has already answered, or a
304afterIf-None-Match, does not count. POST is never cached, so every POST counts. - Data: whatever fits the largest symbol (144 × 144): 3,116 digits, 2,335 capital letters or 1,556 bytes of other text.
- Image: up to 4,000 pixels a side, 40 pixels per module. POST body: up to 32 KB.
Please store images you reuse, rather than asking for the same one again from a server, and spread large jobs out. It is a free service: there is no uptime promise, and we may change the limits or block abusive use (see the terms). For thousands of codes in one go, the bulk generator makes up to 5,000 codes per export in your browser, with no API limits.
Caching and ETags
- Same request, same image. Output depends only on the parameters and the encoder version, so GET answers are sent with
Cache-Control: public, max-age=86400, s-maxage=31536000, stale-while-revalidate=604800. Our edge keeps an image for a year; browsers, CDNs and spreadsheet apps keep it for a day, then recheck it with the ETag, which costs nothing when the image has not changed. - Order and case do not matter at our edge.
?data=A&format=pngand?format=PNG&data=Ashare one cached copy. - ETags. Every image has a strong
ETag. Send it back inIf-None-Matchand you get304 Not Modified, which costs nothing and does not count. - POST is never cached (
no-store): keep the result yourself if you need it again. - Encoder updates. The cache key includes the encoder version (now 2.0.1). If we change how codes are drawn, the ETag changes too, so embedded images pick up the new drawing within about a day; images already cached stay valid codes.
Privacy
To draw a code, the API has to receive the value. It returns the image and keeps nothing: the value, caption and image are not logged or stored. Rate limits use a daily hashed connection value, never the IP address, and we keep only daily totals of requests by format and result. Details are in the privacy policy.
GET or POST? With GET the value is in the URL, so it can end up in browser history, proxy and server logs, analytics tools and anywhere the URL is pasted. That is fine for part numbers on a public page. For anything private (patient, customer or unreleased product data), use POST, which keeps the value in the request body.
GS1 DataMatrix
Add gs1=1 and send the data as (AI)value pairs, the way it prints under the code. For example, GTIN + expiry date + batch:
https://datamatrixcodegenerator.com/api/v1/datamatrix?data=(01)09506000134352(17)271231(10)AB12&format=png&gs1=1- The parentheses are not encoded. The code starts with FNC1, and a group separator follows each variable-length field that is not last. Scanners report
]d2. - Checks: GTIN and SSCC check digits, YYMMDD dates (day 00 means end of month; since 1 January 2025 regulated healthcare products must give the real day, and the notice
gs1-day00-healthcarewarns on medicine-style data), value lengths and characters, and pairs that GS1 requires or forbids, using the GS1 Barcode Syntax Dictionary. - A failed check returns
422 gs1_invalid, with the rule indetail(for examplegs1-incorrect-check-digit). - Passing means the supported GS1 fields passed syntax checks. It does not prove that a GTIN is registered to you or that a trading partner will accept the label. We are not GS1.
To fill in GS1 fields one by one, with dates and check digits explained, use the GS1 DataMatrix generator.
Symbol sizes
Data Matrix ECC 200 has 48 sizes: 24 squares, 6 standard rectangles and 18 DMRE rectangles. With size=auto the API picks the
smallest one of your shape that fits. Force one with size, written rows x columns. DMRE sizes (ISO/IEC 21471) are newer: test them with your scanners before you print.
Show all 48 sizes and their capacities
| size | Shape | Digits | Capital letters | Bytes |
|---|---|---|---|---|
10x10 | Square | 6 | 3 | 1 |
12x12 | Square | 10 | 6 | 3 |
14x14 | Square | 16 | 10 | 6 |
16x16 | Square | 24 | 16 | 10 |
18x18 | Square | 36 | 25 | 16 |
20x20 | Square | 44 | 31 | 20 |
22x22 | Square | 60 | 43 | 28 |
24x24 | Square | 72 | 52 | 34 |
26x26 | Square | 88 | 64 | 42 |
32x32 | Square | 124 | 91 | 60 |
36x36 | Square | 172 | 127 | 84 |
40x40 | Square | 228 | 169 | 112 |
44x44 | Square | 288 | 214 | 142 |
48x48 | Square | 348 | 259 | 172 |
52x52 | Square | 408 | 304 | 202 |
64x64 | Square | 560 | 418 | 277 |
72x72 | Square | 736 | 550 | 365 |
80x80 | Square | 912 | 682 | 453 |
88x88 | Square | 1,152 | 862 | 573 |
96x96 | Square | 1,392 | 1,042 | 693 |
104x104 | Square | 1,632 | 1,222 | 813 |
120x120 | Square | 2,100 | 1,573 | 1,047 |
132x132 | Square | 2,608 | 1,954 | 1,301 |
144x144 | Square | 3,116 | 2,335 | 1,555 |
8x18 | Rectangle | 10 | 6 | 3 |
8x32 | Rectangle | 20 | 13 | 8 |
12x26 | Rectangle | 32 | 22 | 14 |
8x48 | DMRE rectangle | 36 | 25 | 16 |
12x36 | Rectangle | 44 | 31 | 20 |
8x64 | DMRE rectangle | 48 | 34 | 22 |
8x80 | DMRE rectangle | 64 | 46 | 30 |
16x36 | Rectangle | 64 | 46 | 30 |
8x96 | DMRE rectangle | 76 | 55 | 36 |
12x64 | DMRE rectangle | 86 | 63 | 41 |
20x36 | DMRE rectangle | 88 | 64 | 42 |
8x120 | DMRE rectangle | 98 | 72 | 47 |
16x48 | Rectangle | 98 | 72 | 47 |
20x44 | DMRE rectangle | 112 | 82 | 54 |
16x64 | DMRE rectangle | 124 | 91 | 60 |
8x144 | DMRE rectangle | 126 | 93 | 61 |
12x88 | DMRE rectangle | 128 | 94 | 62 |
26x40 | DMRE rectangle | 140 | 103 | 68 |
22x48 | DMRE rectangle | 144 | 106 | 70 |
24x48 | DMRE rectangle | 160 | 118 | 78 |
20x64 | DMRE rectangle | 168 | 124 | 82 |
26x48 | DMRE rectangle | 180 | 133 | 88 |
24x64 | DMRE rectangle | 216 | 160 | 106 |
26x64 | DMRE rectangle | 236 | 175 | 116 |
Capacities are the published ISO/IEC 16022 and 21471 figures for one kind of character. Mixed text fits somewhere in between.
Versioning and terms
The version is in the path: /api/v1/. Within v1 we only add things, such as new optional parameters or headers. A change that could break your code would get a new path
(/api/v2/), with v1 kept running alongside it for a transition period announced on this page. The X-Engine-Version header tells you which encoder drew an image.
Use of the API is covered by the terms of use. The codes you make are yours, with no watermark and no attribution required. A link back to this page is always appreciated.