Uploads
Files never pass through the API. You hash the file, ask for permission
to upload exactly those bytes, PUT them straight to object storage,
and then tell the API they are there.
requestUpload → { alreadyPresent } or { uploadUrl, requiredHeaders }
PUT uploadUrl → object storage verifies the SHA-256 you declared
completeUpload → the resource is backed by the bytesStorage is content-addressed, so if //SCHEMA already holds
the exact file you get alreadyPresent: true and skip the upload
entirely. Single uploads are limited to 5 GiB; deliver larger files
over SFTP.
See Upload media for a complete example.
- mutationrequestUpload
- mutationcompleteUpload
- mutationrequestDeliveryUpload
The UploadTicket object#
Permission to upload one file, or word that //SCHEMA already has it.
Attributes
alreadyPresentBoolean!truewhen //SCHEMA already holds these exact bytes. Skip the upload and go straight to completing it.- The presigned URL to
PUTthe file to.nullwhenalreadyPresent. requiredHeaders[HttpHeader!]!Headers you must send with thePUT, exactly as given. They are part of the signature; leaving one out or changing it gets a403.expiresInSecondsInt!How longuploadUrlstays valid.0whenalreadyPresent.
Request an upload#
Ask to upload a file for a resource you are authoring. Declare the file's SHA-256 and size; the returned URL accepts exactly those bytes and nothing else.
If //SCHEMA already has the bytes, alreadyPresent is true and
there is nothing to upload — call
completeUpload straight away.
Arguments
- The resource the bytes are for. Must be in your catalog.
- The file's SHA-256, as 64 lowercase hex characters.
- The file's size in bytes. Must be positive and at most 5 GiB (5,368,709,120 bytes).
Returns
An UploadTicket.
mutation {
requestUpload(
resourcePk: 771340
sha256: "9f2c4e0d4b1a7c3e8f6d5b2a1c0e9d8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d"
byteSize: 48213377
) {
alreadyPresent
uploadUrl
requiredHeaders { name value }
expiresInSeconds
}
}curl https://api.schema.fm/graphql \
-H "Authorization: Bearer $SCHEMA_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @- <<'EOF'
{
"query": "mutation {\n requestUpload(\n resourcePk: 771340\n sha256: \"9f2c4e0d4b1a7c3e8f6d5b2a1c0e9d8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d\"\n byteSize: 48213377\n ) {\n alreadyPresent\n uploadUrl\n requiredHeaders { name value }\n expiresInSeconds\n }\n}"
}
EOFconst res = await fetch("https://api.schema.fm/graphql", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SCHEMA_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
query: `
mutation {
requestUpload(
resourcePk: 771340
sha256: "9f2c4e0d4b1a7c3e8f6d5b2a1c0e9d8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d"
byteSize: 48213377
) {
alreadyPresent
uploadUrl
requiredHeaders { name value }
expiresInSeconds
}
}
`,
}),
});
const { data, errors } = await res.json();{
"data": {
"requestUpload": {
"alreadyPresent": false,
"uploadUrl": "https://media.schema.fm/sha256/9f/2c/9f2c4e0d…?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=900&…",
"requiredHeaders": [
{ "name": "x-amz-checksum-sha256", "value": "nyxODUsafD6PbVsqHA6djzp....Mi0=" }
],
"expiresInSeconds": 900
}
}
}Complete an upload#
Tell //SCHEMA the bytes are in place. It checks with storage — it
does not take your word for it — and, if the object is present,
backs the resource with it and moves it to stored.
Errors with those bytes are not in the store if the upload never
finished or its URL expired; request a new upload and try again.
Arguments
- The resource the bytes are for.
- The same SHA-256 you passed to
requestUpload.
Returns
A DraftResource in state stored.
mutation {
completeUpload(
resourcePk: 771340
sha256: "9f2c4e0d4b1a7c3e8f6d5b2a1c0e9d8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d"
) {
resourcePk
state
}
}curl https://api.schema.fm/graphql \
-H "Authorization: Bearer $SCHEMA_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @- <<'EOF'
{
"query": "mutation {\n completeUpload(\n resourcePk: 771340\n sha256: \"9f2c4e0d4b1a7c3e8f6d5b2a1c0e9d8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d\"\n ) {\n resourcePk\n state\n }\n}"
}
EOFconst res = await fetch("https://api.schema.fm/graphql", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SCHEMA_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
query: `
mutation {
completeUpload(
resourcePk: 771340
sha256: "9f2c4e0d4b1a7c3e8f6d5b2a1c0e9d8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d"
) {
resourcePk
state
}
}
`,
}),
});
const { data, errors } = await res.json();{
"data": {
"completeUpload": {
"resourcePk": 771340,
"state": "stored"
}
}
}Request a delivery upload#
Like requestUpload, but for a file you are delivering — a DDEX message or one of its media files — rather than one you are authoring. It names no resource, because a delivered file can arrive before //SCHEMA knows what it belongs to.
After the PUT, bind the bytes with
deliverMessage or
deliverFile.
Arguments
- The file's SHA-256, as 64 lowercase hex characters.
- The file's size in bytes. At most 5 GiB.
Returns
An UploadTicket.
mutation {
requestDeliveryUpload(
sha256: "4c1d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e3f2a1b0c9d"
byteSize: 18244
) {
alreadyPresent
uploadUrl
requiredHeaders { name value }
}
}curl https://api.schema.fm/graphql \
-H "Authorization: Bearer $SCHEMA_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @- <<'EOF'
{
"query": "mutation {\n requestDeliveryUpload(\n sha256: \"4c1d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e3f2a1b0c9d\"\n byteSize: 18244\n ) {\n alreadyPresent\n uploadUrl\n requiredHeaders { name value }\n }\n}"
}
EOFconst res = await fetch("https://api.schema.fm/graphql", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SCHEMA_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
query: `
mutation {
requestDeliveryUpload(
sha256: "4c1d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e3f2a1b0c9d"
byteSize: 18244
) {
alreadyPresent
uploadUrl
requiredHeaders { name value }
}
}
`,
}),
});
const { data, errors } = await res.json();{
"data": {
"requestDeliveryUpload": {
"alreadyPresent": true,
"uploadUrl": null,
"requiredHeaders": []
}
}
}