curl --request POST \
--url https://api.moda.app/v1/uploads/from-url \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"source_url": "<string>",
"filename": "<string>",
"folder_id": "fld_01HT9WK8N3M2J4A5Z6P7Q8R9TV"
}
'import requests
url = "https://api.moda.app/v1/uploads/from-url"
payload = {
"source_url": "<string>",
"filename": "<string>",
"folder_id": "fld_01HT9WK8N3M2J4A5Z6P7Q8R9TV"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
source_url: '<string>',
filename: '<string>',
folder_id: 'fld_01HT9WK8N3M2J4A5Z6P7Q8R9TV'
})
};
fetch('https://api.moda.app/v1/uploads/from-url', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.moda.app/v1/uploads/from-url",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'source_url' => '<string>',
'filename' => '<string>',
'folder_id' => 'fld_01HT9WK8N3M2J4A5Z6P7Q8R9TV'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.moda.app/v1/uploads/from-url"
payload := strings.NewReader("{\n \"source_url\": \"<string>\",\n \"filename\": \"<string>\",\n \"folder_id\": \"fld_01HT9WK8N3M2J4A5Z6P7Q8R9TV\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.moda.app/v1/uploads/from-url")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"source_url\": \"<string>\",\n \"filename\": \"<string>\",\n \"folder_id\": \"fld_01HT9WK8N3M2J4A5Z6P7Q8R9TV\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.moda.app/v1/uploads/from-url")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"source_url\": \"<string>\",\n \"filename\": \"<string>\",\n \"folder_id\": \"fld_01HT9WK8N3M2J4A5Z6P7Q8R9TV\"\n}"
response = http.request(request)
puts response.read_body{
"id": "file_01HT9WK8N3M2J4A5Z6P7Q8R9TV",
"url": "<string>",
"filename": "<string>",
"mime_type": "<string>",
"size_bytes": 123,
"was_duplicate": false,
"folder_id": "fld_01HT9WK8N3M2J4A5Z6P7Q8R9TV"
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}Upload From Url
Download a file from a URL and store it.
The returned URL can be used as an attachment in start_design_task.
A URL that cannot become a file is refused with a typed code: source_url_unreachable
(the fetch failed — honour retryable: a timeout or 429 is transient, a 404 is not),
unusable_source_url (it redirected somewhere unfetchable) or source_url_not_a_file
(the content’s type is unresolvable — pass filename with the real extension — or not
accepted). An upstream 5xx is a 502 upstream_error — the remote’s fault, worth a retry.
curl --request POST \
--url https://api.moda.app/v1/uploads/from-url \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"source_url": "<string>",
"filename": "<string>",
"folder_id": "fld_01HT9WK8N3M2J4A5Z6P7Q8R9TV"
}
'import requests
url = "https://api.moda.app/v1/uploads/from-url"
payload = {
"source_url": "<string>",
"filename": "<string>",
"folder_id": "fld_01HT9WK8N3M2J4A5Z6P7Q8R9TV"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
source_url: '<string>',
filename: '<string>',
folder_id: 'fld_01HT9WK8N3M2J4A5Z6P7Q8R9TV'
})
};
fetch('https://api.moda.app/v1/uploads/from-url', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.moda.app/v1/uploads/from-url",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'source_url' => '<string>',
'filename' => '<string>',
'folder_id' => 'fld_01HT9WK8N3M2J4A5Z6P7Q8R9TV'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.moda.app/v1/uploads/from-url"
payload := strings.NewReader("{\n \"source_url\": \"<string>\",\n \"filename\": \"<string>\",\n \"folder_id\": \"fld_01HT9WK8N3M2J4A5Z6P7Q8R9TV\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.moda.app/v1/uploads/from-url")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"source_url\": \"<string>\",\n \"filename\": \"<string>\",\n \"folder_id\": \"fld_01HT9WK8N3M2J4A5Z6P7Q8R9TV\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.moda.app/v1/uploads/from-url")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"source_url\": \"<string>\",\n \"filename\": \"<string>\",\n \"folder_id\": \"fld_01HT9WK8N3M2J4A5Z6P7Q8R9TV\"\n}"
response = http.request(request)
puts response.read_body{
"id": "file_01HT9WK8N3M2J4A5Z6P7Q8R9TV",
"url": "<string>",
"filename": "<string>",
"mime_type": "<string>",
"size_bytes": 123,
"was_duplicate": false,
"folder_id": "fld_01HT9WK8N3M2J4A5Z6P7Q8R9TV"
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}{
"type": "invalid_request",
"code": "<string>",
"message": "<string>",
"doc_url": "<string>",
"request_id": "<string>",
"causes": [
"<unknown>"
],
"details": {},
"retry_after_ms": 123,
"retryable": true
}Authorizations
API key from Settings > Developer > REST API
Headers
Calendar-dated API version pin. New integrations should pin 2026-05-01 to opt into the newest response shapes. For back-compat the server also accepts requests with no header and resolves them to the current default (today: 2026-04-12); that default advances on each sunset date. Any unsupported value returns 400 unsupported_version.
2026-04-12, 2026-05-01 "2026-05-01"
Body
Public URL of the file to download and store.
Filename to use. Inferred from URL if omitted.
Prefixed fld_ wire ID (Crockford base32 body) — the canonical, recommended form. For back-compat, a bare UUID string is also accepted in both path parameters and JSON request bodies (older integrations that stored raw UUIDs keep working), as is the prefix over a UUID body (fld_00000000-0000-4000-8000-000000000000). All three are permanent, supported inputs; only the canonical form is ever emitted.
^fld_[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$"fld_01HT9WK8N3M2J4A5Z6P7Q8R9TV"
Response
Successful Response
Unique file identifier (prefixed file_...).
^file_[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$"file_01HT9WK8N3M2J4A5Z6P7Q8R9TV"
Stable proxy URL for the uploaded file. Use this in attachment URLs.
Filename of the uploaded file.
MIME type of the file.
File size in bytes.
True if an identical file already existed (deduplicated).
Prefixed fld_ wire ID (Crockford base32 body) — the canonical, recommended form. For back-compat, a bare UUID string is also accepted in both path parameters and JSON request bodies (older integrations that stored raw UUIDs keep working), as is the prefix over a UUID body (fld_00000000-0000-4000-8000-000000000000). All three are permanent, supported inputs; only the canonical form is ever emitted.
^fld_[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$"fld_01HT9WK8N3M2J4A5Z6P7Q8R9TV"