Documentation
MatteUsing the API
Updated
Matte's API is three routes. All three need a bearer credential in the Authorization header. Paths below are relative to your Matte environment's URL.
| Method and path | What it does |
|---|---|
POST /v1/remove |
Submit an image. Returns 202 and a job id. With ?sync=1, converts during the request and returns the PNG. |
GET /v1/jobs/{jobId} |
Report a job's status: queued, processing, done or failed. |
GET /v1/jobs/{jobId}/result |
Download the finished PNG. Returns 409 if the job is not done yet. |
The asynchronous flow
This is the default and the one to use in production.
-
POST /v1/removewith the image. Matte checks the credential, saves the original to the bucket, records a job and puts it on the queue. It answers202:{"envelope_version":1,"job_id":"01a0cb3d-484f-7194-82ce-f310e5938786","status":"queued"} -
Poll
GET /v1/jobs/{jobId}. The status moves fromqueuedtoprocessingwhen a worker picks the job up, then todoneorfailed. A failed job carries anerrormessage. -
When it says
done,GET /v1/jobs/{jobId}/resultreturns the PNG withContent-Type: image/png.
With curl, using a credential held in the TOKEN shell variable:
curl -F [email protected] -H "Authorization: Bearer $TOKEN" https://your-matte.example/v1/remove
curl -H "Authorization: Bearer $TOKEN" https://your-matte.example/v1/jobs/<job-id>
curl -o out.png -H "Authorization: Bearer $TOKEN" https://your-matte.example/v1/jobs/<job-id>/result
The synchronous flow
Add ?sync=1 to POST /v1/remove and Matte converts the image inside the request. A success is 200 with the PNG as the body. The request stays open until the conversion finishes or reaches the conversion timeout, 120 seconds by default.
Use it only where holding a request open that long is acceptable. The machine-learning engine loads its model from disk on every conversion, so it is far slower than grabcut: on a small test image the project measured about 12 seconds for ml against a tenth of a second for grabcut.
Request fields
Send these as multipart form fields on POST /v1/remove:
| Field | Values | Default |
|---|---|---|
image |
The image file. Required. | none |
mode |
ml or grabcut |
ml (the server's default mode) |
preset |
fast, balanced or quality |
balanced |
model |
A model file name. Used in ml mode. |
the server's default model, isnet-general-use.onnx |
edge_mode |
blur, bilateral or guided |
none |
iterations |
A positive integer: the GrabCut iteration count. | none |
margin |
A positive integer: the GrabCut margin. | none |
sync |
1 to convert during the request |
off |
The image must pass Laravel's image validation rule. JPEG, PNG, GIF, BMP, WebP, AVIF, HEIC and HEIF are accepted; SVG is not. Matte sets no explicit size or dimension limit of its own.
Choosing a mode
grabcutis a classical algorithm. It needs no model file and starts almost instantly. It works best on a distinct subject against a contrasting background.mlruns the server's machine-learning model. It handles harder edges, such as hair or busy backgrounds, and is much slower. It fails if the named model file is not present on the server.
Responses and errors
| Status | When |
|---|---|
202 |
An asynchronous job was accepted. |
200 |
A synchronous conversion succeeded, a status was returned, or a result was downloaded. |
401 |
The credential is missing, wrong, revoked, expired, minted for the wrong purpose, or of a kind Matte does not admit. |
404 |
No job has that id, or a finished job's result is no longer in storage. |
409 |
You asked for a result before the job reached done. The body includes the current status. |
422 |
The request is invalid: no image, an unknown option value, a malformed integer, or a client newer than the server (see Troubleshooting). |
500 |
A synchronous conversion failed. The body carries the error message. |
503 |
A synchronous request reached a machine where the binary cannot run. |
Storage and repeated images
Originals are stored under originals/ and results under outputs/ on the bucket. A result's name is a hash of the input bytes plus the options, so sending the same image with the same options writes to the same object rather than piling up copies. The conversion still runs again each time. Matte never deletes originals or results; clear them from the bucket yourself if you need to.
Getting a credential
Matte's image routes accept only bearer credentials minted for the consumption purpose (which Matte registers as matte.remove), owned either by an installation (one installed copy of one consuming app) or by a signed-in user.
-
For a Laravel app on Laravel Cloud or Forge, attach it through Scalpels. Scalpels mints a credential for that app and writes it straight into the app's environment. See Connecting your apps.
-
For anything else, mint an installation credential inside the Matte environment. Run this there, for example with
cloud command:run, replacingacme-crmwith a name for the consuming app:php artisan bfc:credential:mint installation 'acme-crm' --kind=bearer --purpose=consumption --name='matte-acme-crm' --localThe command prints the credential once and stores only a hash of it. Put it straight into the caller's secret manager; there is no way to read it back. A credential only works against the database it was minted in, so it must be minted in the deployed environment, not on your own machine.
To see which credentials exist, run php artisan bfc:credential:list --local in the environment; it never shows secrets. To cut one off, run php artisan bfc:credential:revoke <credential-id> --local. Revoking an installation credential cuts off that one consumer and nothing else.
Completion callbacks
Polling is the supported way to learn that a job has finished. Matte can also post a signed completion message, but only to a destination registered in the server's own configuration (matte-server.callback.destinations) in your fork. It never posts to a URL supplied in the request: callback_url is rejected, and callback_destination must name a registered destination and only works on asynchronous requests. Delivery is best effort and never changes the job's outcome. Setting a destination up end to end means changing your fork's configuration and installing a signing credential in the receiving app, and the project does not yet document that process, so start with polling.