API / API reference

Assets

Uploading and managing artwork.

Single resources and collections come back wrapped in data. Paginated collections add links and meta. Errors are never wrapped; see Errors.
GET /api/v1/projects/{project}/assets Scope assets:read

List files stored for this project

Everything in this project's storage folder: a key, a public url and a size for each file.

The key is what you pass to the delete endpoint. The url is what you put in a component's image_url. These files count against the designer's storage quota, so /me is worth reading before a large upload.

curl "https://dustinsdesignerden.com/api/v1/projects/1/assets" \
  -H "Authorization: Bearer $DDD_TOKEN"
const res = await fetch('https://dustinsdesignerden.com/api/v1/projects/1/assets', {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${token}`,
  },
});

const data = await res.json();
$response = Http::withToken($token)->get('https://dustinsdesignerden.com/api/v1/projects/1/assets');

$data = $response->json();
res = requests.get(
    'https://dustinsdesignerden.com/api/v1/projects/1/assets',
    headers={'Authorization': f'Bearer {token}'},
)

data = res.json()
Response 200
{
    "data": []
}

Parameters

project integer · path required
Project id.

Response: Asset

key string
Storage key. Pass this to the delete endpoint.
url string
Public URL. Put this in a component's image_url.
size integer
Stored size in bytes, after any conversion.
name string
Stored filename.
last_modified string
When it was last written. Listings only.
POST /api/v1/projects/{project}/assets Scope assets:write

Upload artwork (multipart)

Field name is file. Images only (jpeg, png, gif, webp, avif, svg), 50 MB max. Optional convert_to_webp / convert_to_avif booleans. Counts against the designer's storage quota.

curl -X POST "https://dustinsdesignerden.com/api/v1/projects/1/assets" \
  -H "Authorization: Bearer $DDD_TOKEN" \
  -F "file=@artwork.png"
const form = new FormData();
form.append('file', fileInput.files[0]);

const res = await fetch('https://dustinsdesignerden.com/api/v1/projects/1/assets', {
  method: 'POST',
  headers: { Authorization: `Bearer ${token}` },
  body: form,
});

const data = await res.json();
$response = Http::withToken($token)
    ->attach('file', file_get_contents('artwork.png'), 'artwork.png')
    ->post('https://dustinsdesignerden.com/api/v1/projects/1/assets');

$data = $response->json();
with open('artwork.png', 'rb') as fh:
    res = requests.post(
        'https://dustinsdesignerden.com/api/v1/projects/1/assets',
        headers={'Authorization': f'Bearer {token}'},
        files={'file': fh},
    )

data = res.json()
Response 201
{
    "key": "users/8513abae35a92148a8d6ae87/projects/1/dagger.png",
    "url": "https://assets.dustinsdesignerden.com/ebf3cf58d1b64d4087087b7a37bc9782:pro-assets/users/8513abae35a92148a8d6ae87/projects/1/dagger.png",
    "size": 107,
    "name": "dagger.png"
}

Parameters

project integer · path required
Project id.

Body parameters

file file required
multipart/form-data. jpeg, png, gif, webp, avif or svg. 50 MB max.
convert_to_webp boolean
Convert to WebP on the way in.
convert_to_avif boolean
Convert to AVIF on the way in.

Response: Asset

key string
Storage key. Pass this to the delete endpoint.
url string
Public URL. Put this in a component's image_url.
size integer
Stored size in bytes, after any conversion.
name string
Stored filename.
last_modified string
When it was last written. Listings only.
DELETE /api/v1/projects/{project}/assets Scope assets:write

Delete a file

Removes one stored file and frees the space against the designer's quota. Address it with the key from the asset listing.

Components pointing at that URL are not changed, so deleting a file that is in use leaves them with a broken image. Repoint or remove those components first. Only keys inside this project's folder can be reached: not the designer's avatar, and not another project's artwork.

curl -X DELETE "https://dustinsdesignerden.com/api/v1/projects/1/assets" \
  -H "Authorization: Bearer $DDD_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "key": "users/8513abae35a92148a8d6ae87/projects/1/dagger.png"
}'
const res = await fetch('https://dustinsdesignerden.com/api/v1/projects/1/assets', {
  method: 'DELETE',
  headers: {
    Authorization: `Bearer ${token}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "key": "users/8513abae35a92148a8d6ae87/projects/1/dagger.png"
  }),
});

const data = await res.json();
$response = Http::withToken($token)->delete('https://dustinsdesignerden.com/api/v1/projects/1/assets', [
    'key' => 'users/8513abae35a92148a8d6ae87/projects/1/dagger.png',
]);

$data = $response->json();
res = requests.delete(
    'https://dustinsdesignerden.com/api/v1/projects/1/assets',
    headers={'Authorization': f'Bearer {token}'},
    json={
    'key': 'users/8513abae35a92148a8d6ae87/projects/1/dagger.png'
},
)

data = res.json()
Response 200
{
    "deleted": true
}

Parameters

project integer · path required
Project id.

Body parameters

key string required
The storage key returned by an upload. Must be inside this project's folder.

Response: Deletion result

deleted boolean|integer
true for a single delete, or the number removed for a bulk one.
components_retained boolean
Only on a group delete. Confirms removing the deck or stack left its components in the project.
POST /api/v1/projects/{project}/assets/from-url Scope assets:write

Mirror artwork you already host

The server fetches the URL and stores a copy in the designer's own storage. Public http(s) only; private, loopback and link-local addresses are refused.

curl -X POST "https://dustinsdesignerden.com/api/v1/projects/1/assets/from-url" \
  -H "Authorization: Bearer $DDD_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://cdn.example.com/shield.png"
}'
const res = await fetch('https://dustinsdesignerden.com/api/v1/projects/1/assets/from-url', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${token}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
      "url": "https://cdn.example.com/shield.png"
  }),
});

const data = await res.json();
$response = Http::withToken($token)->post('https://dustinsdesignerden.com/api/v1/projects/1/assets/from-url', [
    'url' => 'https://cdn.example.com/shield.png',
]);

$data = $response->json();
res = requests.post(
    'https://dustinsdesignerden.com/api/v1/projects/1/assets/from-url',
    headers={'Authorization': f'Bearer {token}'},
    json={
    'url': 'https://cdn.example.com/shield.png'
},
)

data = res.json()
Response 201
{
    "key": "users/8513abae35a92148a8d6ae87/projects/1/shield.png",
    "url": "https://assets.dustinsdesignerden.com/ebf3cf58d1b64d4087087b7a37bc9782:pro-assets/users/8513abae35a92148a8d6ae87/projects/1/shield.png",
    "size": 107,
    "name": "shield.png"
}

Parameters

project integer · path required
Project id.

Body parameters

url url required
Public http(s) URL. Private, loopback and link-local addresses are refused, and redirects are followed only while they stay public.
convert_to_webp boolean
Convert to WebP.
convert_to_avif boolean
Convert to AVIF.

Response: Asset

key string
Storage key. Pass this to the delete endpoint.
url string
Public URL. Put this in a component's image_url.
size integer
Stored size in bytes, after any conversion.
name string
Stored filename.
last_modified string
When it was last written. Listings only.