# Create a fabric

> Turn photos of a fabric into a library fabric you can design with, rendered in every extra colour you ask for. The result is the fabric record, fabric:<id>.

**Endpoint:** `POST https://api.refabric.com/v1/tasks/fabric.create` · **Task:** `fabric.create` · **Scope:** `tasks:run` · **Category:** Records & libraries

Send photos of a fabric and get a fabric in your library, with its type, composition, pattern and weight filled in and rendered in every extra colour you ask for. Pass the fabric to generation to design with it.

## Quick start

```python
import os
import time
import requests

headers = {"Authorization": f"Key {os.environ['REFABRIC_API_KEY']}"}

job = requests.post(
    "https://api.refabric.com/v1/tasks/fabric.create",
    headers=headers,
    json={
        "name": "Washed linen",
        "images": [
            "https://cdn.example.com/linen-flat.jpg",
            "file:913",
        ],
    },
).json()
print(job["job_id"])

while True:
    status = requests.get(job["status_url"], headers=headers).json()
    if status["lifecycle"] == "terminal":
        break
    time.sleep(5)

print(requests.get(job["result_url"], headers=headers).json())
```

```javascript
const headers = {
  Authorization: `Key ${process.env.REFABRIC_API_KEY}`,
  "Content-Type": "application/json",
};

const job = await fetch("https://api.refabric.com/v1/tasks/fabric.create", {
  method: "POST",
  headers,
  body: JSON.stringify({
    "name": "Washed linen",
    "images": [
      "https://cdn.example.com/linen-flat.jpg",
      "file:913"
    ]
  }),
}).then((r) => r.json());
console.log(job.job_id);

let status = job;
while (status.lifecycle !== "terminal") {
  await new Promise((r) => setTimeout(r, 5000));
  status = await fetch(job.status_url, { headers }).then((r) => r.json());
}

console.log(await fetch(job.result_url, { headers }).then((r) => r.json()));
```

```bash
curl -X POST "https://api.refabric.com/v1/tasks/fabric.create" \
  -H "Authorization: Key $REFABRIC_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Prefer: wait=60" \
  -d '{"name":"Washed linen","images":["https://cdn.example.com/linen-flat.jpg","file:913"]}'
```

## Input schema

- `name` (string, _required_, min length 1, max length 255) — The fabric's name, as it is listed in your library.
  Example: `Washed linen`
- `images` (array<string>, _required_, at least 1 items, at most 4 items) — 1–4 photos of the fabric, each ONE string: a url, a file from an earlier result (`art:…`), an upload (`file:…`) or an `items[].url` of a record. The FIRST is the reference: a flat, well-lit swatch — the fabric and its own colour are made from it; the others help fill in its facts. Addresses that are not publicly reachable are refused.
  Example: `["https://cdn.example.com/linen-flat.jpg","file:913"]`
- `description` (string, _optional_, max length 2000) — Your own words about the fabric; returned as `data.description`.
  Example: `SS27 shirting base`
- `external_id` (string, _optional_, max length 255) — Your own code for the fabric, to match it in your system; returned as `data.external_id`.
  Example: `LIN-0042`
- `facts` (object, _optional_) — What you already know about the fabric, in the shape `data.facts` returns. Each fact you send is used as given; the rest are filled in for you.
  Example: `{"fabric_type":"Linen","composition":[{"name":"Linen","percentage":100}],"pattern":"Solid","weight_gsm":180}`
  - `fabric_type` (string, _optional_, max length 255) — What the fabric is (Twill, Denim, Jersey …). Omitted: filled in for you.
    Example: `Linen`
  - `composition` (array<object>, _optional_) — What it is made of, as [{name, percentage}] — the shape `data.facts.composition` returns. Omitted: filled in for you (up to three materials).
    Example: `[{"name":"Linen","percentage":100}]`
    - `name` (string, _required_, min length 1) — The material, e.g. Cotton.
      Example: `Linen`
    - `percentage` (number, _optional_, 0 to 100) — Its share in percent; leave it out (or null) when unknown.
      Example: `100`
  - `pattern` (string, _optional_, max length 255) — Its pattern (Solid, Striped, Houndstooth …). Omitted: filled in for you (Solid by default).
    Example: `Solid`
  - `weight_gsm` (integer, _optional_, 1 to 10000) — Grams per square metre. Omitted: filled in for you.
    Example: `180`
- `colours` (array<object>, _optional_, at most 24 items) — Up to 24 EXTRA colours to render the fabric in, each {hex}. The fabric's own colour is taken from the first photo and is not sent. Each extra colour is priced; see `/estimate`.
  Example: `[{"hex":"#1F3A5F"},{"hex":"#C8B89A"}]`
  - `hex` (string, _required_, pattern: ^#[0-9A-Fa-f]{6}$) — The colour as #RRGGBB, like "#E8D9C4".
  - `name` (string, _optional_) — A name for the colour.
  - `pantone` (string, _optional_) — Its Pantone code, when known.

## Required-fields example

```json
{
  "name": "Washed linen",
  "images": [
    "https://cdn.example.com/linen-flat.jpg",
    "file:913"
  ]
}
```

## Full example

```json
{
  "name": "Washed linen",
  "description": "SS27 shirting base",
  "external_id": "LIN-0042",
  "images": [
    "https://cdn.example.com/linen-flat.jpg",
    "file:913"
  ],
  "facts": {
    "fabric_type": "Linen",
    "composition": [
      {
        "name": "Linen",
        "percentage": 100
      }
    ],
    "pattern": "Solid",
    "weight_gsm": 180
  },
  "colours": [
    {
      "hex": "#1F3A5F"
    },
    {
      "hex": "#C8B89A"
    }
  ]
}
```

## Output schema

- `files` (array<object>, _optional_) — One file, the fabric record `fabric:<fabric_id>` (`application/json`): its `data` is name · description · status · external_id · facts · colours[{hex, pantone}] · items[{type: fabric, name: <hex>, url, status}] — each colour's images are items named by the colour. Read it again any time with GET /v1/files/fabric:<id>; pass the handle as a reference (`"image": "fabric:<id>"`, `use_case: "fabric"`) to image.generate.
- `summary` (object, _optional_) — How many colourways were asked for and rendered, and which extra colours did not render.
  - `requested` (integer, _optional_) — Colourways asked for: the base colour plus your extra colours.
  - `delivered` (integer, _optional_) — Colourways that rendered.
  - `warnings` (array<object>, _optional_) — One `{code, field, message}` per extra colour that did not render (`code: "output_not_produced"`, `field: "colours[i]"`); it was not charged and shows `status: failed` in the fabric.

## Response example

```json
{
  "job_id": "0d9e8f7a6b5c4d3e8f2a9b8c7d6e5f41",
  "lifecycle": "queued",
  "status_url": "http://v3-api.refabric.com/v1/jobs/0d9e8f7a6b5c4d3e8f2a9b8c7d6e5f41",
  "result_url": "http://v3-api.refabric.com/v1/jobs/0d9e8f7a6b5c4d3e8f2a9b8c7d6e5f41/result",
  "cancel_url": "http://v3-api.refabric.com/v1/jobs/0d9e8f7a6b5c4d3e8f2a9b8c7d6e5f41/cancel"
}
```

## Result example

```json
{
  "job_id": "0d9e8f7a6b5c4d3e8f2a9b8c7d6e5f41",
  "files": [
    {
      "file": "fabric:5f0c1d2e-8a41-4b7e-9c3d-1a2b3c4d5e60",
      "url": "https://files.example.com/fabric.create/1.png",
      "media_type": "application/json",
      "task": "fabric.create",
      "job_id": "0d9e8f7a6b5c4d3e8f2a9b8c7d6e5f41",
      "created_at": "2026-09-30T09:15:00Z",
      "data": {
        "name": "Washed linen",
        "description": "SS27 shirting base",
        "status": "ready",
        "external_id": "LIN-0042",
        "facts": {
          "weight_gsm": 180,
          "composition": [
            {
              "name": "Linen",
              "percentage": 100
            }
          ],
          "pattern": "Solid",
          "fabric_type": "Linen"
        },
        "colours": [
          {
            "hex": "#E9E2D0",
            "pantone": "11-0507"
          },
          {
            "hex": "#1F3A5F",
            "pantone": "19-4027"
          },
          {
            "hex": "#C8B89A",
            "pantone": "15-1214"
          }
        ],
        "items": [
          {
            "type": "fabric",
            "name": "#E9E2D0",
            "url": "https://files.example.com/fabric.create/1.png"
          },
          {
            "type": "fabric",
            "name": "#E9E2D0",
            "url": "https://files.example.com/fabric.create/2.png"
          },
          {
            "type": "fabric",
            "name": "#1F3A5F",
            "url": "https://files.example.com/fabric.create/3.png"
          },
          {
            "type": "fabric",
            "name": "#C8B89A",
            "status": "failed"
          }
        ]
      }
    }
  ],
  "has_more": false,
  "summary": {
    "requested": 3,
    "delivered": 2,
    "warnings": [
      {
        "code": "output_not_produced",
        "field": "colours[1]",
        "message": "This colour did not render. It was not charged and shows status failed in the fabric."
      }
    ]
  }
}
```

## Built for

- Your suppliers' fabrics, ready to design with
- One fabric in several colourways
- A fabric library matched to your own codes (`external_id`)

## What you get

- One `fabric:` record — its name, description, status, your `external_id`, its `facts` and its colours.
- Each colourway's images in the record's `data.items`, named by the colour.
- A `summary` that counts the colourways asked for and rendered, and names in `warnings` each extra colour that did not render.

## Specs

- **Input formats:** Images, each one string: a URL, an upload (`file:…`) or a file from an earlier result (`art:…`). Upload types and sizes: `GET /v1/meta` `limits.upload`.
- **Input count:** `images`: 1 to 4
- **Output format:** One `fabric:` record: its `data` is JSON in the record vocabulary, its `url` a preview image.
- **Outputs per job:** One record file, however many photos and colours you send.

## Choosing a task

- Use this when the fabric is not in your library yet. Use `fabric.add_colour` when the fabric is already made and you want one more colour of it.

## Errors

- `field_not_accepted`
- `invalid_request`
- `name_required`
- `images_required`
- `too_many_images`
- `image_not_public`
- `not_found`
- `invalid_colour`
- `too_many_colours`
- `invalid_weight`
- `permission_denied`
- `insufficient_credits`
- `processing_failed`

## Related

- `fabric.add_colour` — It runs after: it takes this task's result.
- `image.generate` — It runs after: it takes this task's result.

## Good to know

- `name` is at most 255 characters.
- `description` is at most 2000 characters.
- `external_id` is at most 255 characters.
- `images` holds at least 1 items.
- `images` holds at most 4 items.
- `facts.fabric_type` is at most 255 characters.
- `facts.composition[].percentage` is from 0 to 100.
- `facts.pattern` is at most 255 characters.
- `facts.weight_gsm` is from 1 to 10000.
- `colours` holds at most 24 items.

## For agents and code generation

- https://api.refabric.com/v1/tasks/fabric.create/llms.txt
- https://api.refabric.com/v1/tasks/fabric.create/openapi.json
- GET https://api.refabric.com/v1/tasks/fabric.create
