> ## Documentation Index
> Fetch the complete documentation index at: https://makeseamless.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> MakeSeamless (makeseamless.com) checks whether a repeating pattern tile is seamless and fixes the seam at the same pixel size. Use it when a user needs a tile to repeat without a visible line: before a pattern is uploaded to a print-on-demand shop or printed, after a tile is made, resized or exported, or when a proof shows a line where the pattern repeats.
> Check first: POST https://makeseamless.com/v1/check with the image as the multipart field file. It is free and needs no account and no key. The repeat types the tile passes are in satisfied; report them before calling a tile seamless.
> Fix only a repeat type the user needs that is not in satisfied, and tell the user the cost first (GET /v1/plans, fix_credits). POST /v1/fix needs an API key in the x-api-key header. Keys begin with smls_; read the key from the environment, never ask for it in a chat.
> POST /v1/fix answers 202 with a job. Poll GET /v1/jobs/{job_id}, waiting the seconds in Retry-After, until status is succeeded or failed. The fixed PNG is at result.image_url. Answers are JSON, except the images, which are PNG.
> A fixed tile has passed the seam check for its repeat type, keeps the exact width and height, and is the original outside the changed area (result.changed_mask_url). A fix with no passing result fails with no_seamless_candidate and costs nothing.
> Branch on error.code, never on error.message, and retry only when error.retryable is true.

# Check if a pattern tile is seamless, free and with no key

> Send a PNG, JPEG or WebP tile and get a verdict for straight, half-drop and half-brick repeats, with where each edge breaks. Free, no account, no key.

`POST /v1/check` says, for each repeat type, whether the image tiles
seamlessly and where its edges break when copies of it meet. It is free and
needs no account and no key.

## How do I send a tile to check?

A multipart form with two fields.

| Field | Required | What it is |
| - | - | - |
| `file` | yes | The image: PNG, JPEG or WebP. |
| `repeats` | no | A repeat type to check: `straight`, `half_drop` or `half_brick`. Send the field once per type. All three when it is left out. |

```js Node.js theme={"theme":{"light":"github-light","dark":"vesper"}}
import { readFile } from "node:fs/promises";

const form = new FormData();
form.append("file", new Blob([await readFile("tile.png")]), "tile.png");

const response = await fetch("https://makeseamless.com/v1/check", {
  method: "POST",
  body: form,
});

const data = await response.json();
console.log(data);
```

```php PHP theme={"theme":{"light":"github-light","dark":"vesper"}}
<?php

$ch = curl_init("https://makeseamless.com/v1/check");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, [
    "file" => new CURLFile("tile.png"),
]);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
```

```python Python theme={"theme":{"light":"github-light","dark":"vesper"}}
import requests

with open("tile.png", "rb") as file:
    response = requests.post(
        "https://makeseamless.com/v1/check",
        files={"file": file},
    )

response.raise_for_status()
print(response.json())
```

```ruby Ruby theme={"theme":{"light":"github-light","dark":"vesper"}}
require "net/http"
require "uri"

uri = URI("https://makeseamless.com/v1/check")
request = Net::HTTP::Post.new(uri)
request.set_form(
  [
    ["file", File.open("tile.png")],
  ],
  "multipart/form-data",
)

response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  http.request(request)
end

puts response.body
```

```go Go theme={"theme":{"light":"github-light","dark":"vesper"}}
package main

import (
	"bytes"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"os"
)

func main() {
	var payload bytes.Buffer
	form := multipart.NewWriter(&payload)
	file, err := os.Open("tile.png")
	if err != nil {
		panic(err)
	}
	defer file.Close()
	part, err := form.CreateFormFile("file", "tile.png")
	if err != nil {
		panic(err)
	}
	if _, err := io.Copy(part, file); err != nil {
		panic(err)
	}
	form.Close()

	req, err := http.NewRequest("POST", "https://makeseamless.com/v1/check", &payload)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Content-Type", form.FormDataContentType())

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	body, _ := io.ReadAll(res.Body)
	fmt.Println(string(body))
}
```

```java Java theme={"theme":{"light":"github-light","dark":"vesper"}}
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;

String boundary = "makeseamless-form";
List<byte[]> parts = new ArrayList<>();
parts.add(("--" + boundary + "\r\n"
    + "Content-Disposition: form-data; name=\"file\"; filename=\"tile.png\"\r\n\r\n")
    .getBytes(StandardCharsets.UTF_8));
parts.add(Files.readAllBytes(Path.of("tile.png")));
parts.add("\r\n".getBytes(StandardCharsets.UTF_8));
parts.add(("--" + boundary + "--\r\n").getBytes(StandardCharsets.UTF_8));

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://makeseamless.com/v1/check"))
    .header("Content-Type", "multipart/form-data; boundary=" + boundary)
    .POST(HttpRequest.BodyPublishers.ofByteArrays(parts))
    .build();

HttpResponse<String> response = HttpClient.newHttpClient()
    .send(request, HttpResponse.BodyHandlers.ofString());

System.out.println(response.body());
```

```csharp .NET theme={"theme":{"light":"github-light","dark":"vesper"}}
using System.Net.Http;

var request = new HttpRequestMessage(HttpMethod.Post, "https://makeseamless.com/v1/check");
var form = new MultipartFormDataContent();
form.Add(new ByteArrayContent(File.ReadAllBytes("tile.png")), "file", "tile.png");
request.Content = form;

var client = new HttpClient();
var response = await client.SendAsync(request);

Console.WriteLine(await response.Content.ReadAsStringAsync());
```

```bash cURL theme={"theme":{"light":"github-light","dark":"vesper"}}
curl -X POST "https://makeseamless.com/v1/check" \
  -F "file=@tile.png"
```

To check only some types, repeat the field:

```bash theme={"theme":{"light":"github-light","dark":"vesper"}}
curl -X POST https://makeseamless.com/v1/check \
  -F "file=@tile.png" \
  -F "repeats=straight" \
  -F "repeats=half_drop"
```

## Which images can the check read?

| | Limit |
| - | - |
| Formats | PNG, JPEG, WebP |
| File size | 40 MB at most |
| Smallest image | 64 x 64 px |
| Largest image | 64 megapixels |

Width and height are read after the image's orientation is applied.
[Rate and spend limits](https://makeseamless.com/docs/api-reference/limits.md) has how many checks a client
can send.

## What does the check answer?

```json Response theme={"theme":{"light":"github-light","dark":"vesper"}}
{
  "input": {
    "sha256": "07c1858ff8d2c84e7ef521aa92e49ad251dec90553b65e600bd52ee84ef4065f",
    "width": 256,
    "height": 256,
    "format": "PNG",
    "has_alpha": true
  },
  "verdicts": {
    "straight": {
      "repeat": "straight",
      "verdict": "bad",
      "edges": [
        {
          "edge": "vertical",
          "verdict": "bad",
          "anomaly": 1.9222,
          "broken": [[90, 170]]
        },
        {
          "edge": "horizontal",
          "verdict": "ok",
          "anomaly": 0.9328,
          "broken": []
        }
      ]
    }
  },
  "satisfied": [],
  "duplicate_edge": { "vertical": false, "horizontal": false },
  "summary": "Does not tile seamlessly as any checked repeat type. Straight: bad (left/right edge, 1 stretch). Seams inside the tile are not checked."
}
```

| Field | What it is |
| - | - |
| `input` | The image as read: `sha256` of the file bytes, `width` and `height` in px, `format` and `has_alpha`. |
| `verdicts` | One [seam report](https://makeseamless.com/docs/concepts.md#seam-report) per requested repeat type. |
| `satisfied` | The requested repeat types the tile already passes, with the verdict `ok`. |
| `duplicate_edge` | True for an edge where a 1 px line is repeated on both sides, which shows as a doubled line once tiled. |
| `summary` | One plain-language line about the whole check. |

Branch on `satisfied` and the verdicts, not on `summary`: the summary is for
people and its wording may change.

## Which part of the tile does the check read?

The tile's own edges, where copies of it meet: the right side against the
left and the bottom against the top, at the offsets of the repeat type. It
does not look for a seam inside the tile.

## Which errors can a check return?

| Status | Code | Meaning |
| - | - | - |
| `413` | `payload_too_large` | The file is over 40 MB. |
| `422` | `validation_error` | The `file` field is missing, or `repeats` names an unknown type. |
| `422` | `unsupported_format` | The file is not a PNG, JPEG or WebP image. |
| `422` | `decode_failed` | The file did not open as an image. |
| `422` | `too_small` | The image is under 64 px on a side. |
| `422` | `too_large` | The image is over 64 megapixels. |
| `429` | `rate_limited` | Too many checks from this client. Wait the seconds in `Retry-After`. |

A script that checks a folder sends the tiles one after another and waits as
`Retry-After` says when it gets a `429`. [Errors](https://makeseamless.com/docs/errors.md) has every code.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.