Skip to content
AdCrunch
Esc
↑↓navigate↵open⌘Jpreview
On this page

Upload a file

Upload an image or a video as an Asset, or a file as a Brand Document. Then register an Asset in the library of an advertiser.

The bytes of a large file never go through the API. You reserve the file and send the bytes to a storage URL. A Document then needs a finalize call. An Asset needs none: a read of the Asset completes it.

  • An Asset is an image or a video that goes into an ad. You register it in the library of an advertiser.
  • A Document is reference material on a Brand, such as a logo or a guidelines PDF. An agent reads it. It never leaves AdCrunch.

Upload a small Asset in one call

Send the file as the raw body of POST /assets. The answer is the Asset, with the status ready.

curl --data-binary @ad.png \
  -H "Authorization: Bearer $ADCRUNCH_API_KEY" \
  "https://api.adcrunch.dev/assets?filename=ad.png"
  • filename is required. name is optional and replaces the filename in the display.
  • Do not use multipart/form-data. The body is the file.
  • The request needs a Content-Length. Without one, the answer is 411 length_required.
  • The route takes a body up to 95 MB. Over that, the answer is 413 use_upload_url: use the two steps below. A body over the limit of the Cloudflare plan of the domain, 100 MB at the lowest, gets a 413 from Cloudflare with no error code.
  • AdCrunch identifies the type from the bytes. A refused file leaves no object and no Asset. The answer is 413 too_large or 415 unsupported_type or unreadable.

Import an Asset from a URL

Send a JSON body to POST /assets. AdCrunch fetches the file from the URL. The answer is 202 with the Asset, with the status pending.

curl -X POST https://api.adcrunch.dev/assets \
  -H "Authorization: Bearer $ADCRUNCH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "sourceUrl": "https://example.com/ad.png" }'
  • sourceUrl is required, and it must be an https URL. Another scheme answers 400 invalid_url, and AdCrunch creates nothing. name is optional.
  • The host must be a public name. An IP address, a local or private host, or an AdCrunch domain (adcrunch.dev and its subdomains) answers 400 source_not_allowed. To store a file that is on an AdCrunch domain, send its bytes instead.
  • The source must send a Content-Length. A source that declares a type AdCrunch does not accept, such as image/svg+xml or text/html, fails at once with unsupported_type. AdCrunch follows a redirect only to an https URL.
  • Read the Asset with GET /assets/{id} until its status is ready or failed.
  • A failure is on the Asset, not in the answer. failureCode is source_unreachable (the source did not answer, answered with an error, or sent the file in part), source_length_unknown (the source sent no Content-Length), too_large, unsupported_type or unreadable.
  • The file takes its name from the Content-Disposition of the source, or else from the last segment of the URL.

Upload an Asset in two steps

Reserve the Asset

curl -X POST https://api.adcrunch.dev/assets/uploads \
  -H "Authorization: Bearer $ADCRUNCH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "filename": "spring-sale.mp4" }'

The answer holds the id of the Asset, the storage URL, and the time when the URL stops working:

{
  "assetId": "ast_7c1e9a",
  "uploadUrl": "https://…",
  "expiresAt": 1790000000000
}

Send the bytes to the storage URL

curl -X PUT "$UPLOAD_URL" \
  -H "If-None-Match: *" \
  --upload-file spring-sale.mp4

The PUT of an Asset needs the header If-None-Match: *. A PUT without it answers 403. The URL can create the file once, and it can never replace it:

  • The first PUT answers 200.
  • A second PUT answers 412. A 412 means that the file is already stored, for example after a retry when the first answer was lost. Continue to the next step.

The bytes of an Asset never change. To use a different file, reserve a new Asset.

The PUT of an Asset needs no Content-Type. AdCrunch identifies the type of an Asset from its bytes, and a Content-Type is only a hint. A Document still needs the Content-Type of its file.

Do not send your API key to this URL. The URL itself gives write access: each person who holds it can create that one file until the URL expires.

Read the Asset

curl https://api.adcrunch.dev/assets/ast_7c1e9a \
  -H "Authorization: Bearer $ADCRUNCH_API_KEY"

The first read after the PUT inspects the stored file and completes the Asset. The answer is the Asset, with the status ready or failed. A read before the PUT answers pending. Read again until the status is ready or failed.

AdCrunch also completes a reservation that nobody reads. The daily sweep inspects each pending Asset that is one day old. It completes the Asset when the file exists, and it deletes the reservation when no file exists.

Upload a Document

A Document has three steps, on the Brand:

  1. POST /context/brands/{slug}/documents with filename and content_type. The answer holds documentId, uploadUrl, and expiresInSeconds.
  2. PUT the bytes to uploadUrl, with the Content-Type of the file.
  3. POST /context/brands/{slug}/documents/{documentId}/finalize.

The two flows use different names for some fields:

Asset Document
Permission asset:write brand:write
The id in the answer assetId documentId
The end of the URL expiresAt, a timestamp expiresInSeconds, a duration
Header on the PUT If-None-Match: * Content-Type of the file
Read of the Asset before the bytes arrive pending not applicable
Finalize before the bytes arrive not applicable 409 no_object

The stored file is the only check

The storage URL applies no rule to the content of a file. It accepts each file that you send to it. So AdCrunch checks the file when it completes the Asset or the Document, from what storage holds: the size of the stored file, and, for a Document, the Content-Type that your PUT sent. What you declared at step 1 controls nothing.

For an Asset, AdCrunch also reads the header of the stored file. The bytes decide the type, and AdCrunch stores that type as mimeType. A PNG that your PUT sent as image/jpeg becomes a ready Asset of type image/png. The header gives width and height as the file is displayed, with its rotation applied, and durationMs for a video.

Types Largest file
An image Asset GIF, JPEG, PNG, WebP 30 MB
A video Asset MP4, QuickTime 4 GB
A Document PDF, GIF, JPEG, PNG, WebP 25 MB

A file that fails the check is deleted. A Document finalize answers 413 too_large or 415 unsupported_type. For an Asset, the read answers the Asset with the status failed and a failureCode. The Asset stays. See The status of an Asset. For an Asset, unsupported_type means that the bytes are no accepted type. An Asset can also have the failureCode unreadable, when the file ends before its header does. Reserve and upload again. When AdCrunch does not accept the declared content_type of a Document, step 1 also answers 415. That answer names the accepted types in allowed.

The status of an Asset

GET /assets/{id} answers an Asset in every status. GET /assets lists ready Assets only.

status Meaning
pending AdCrunch has not inspected the bytes yet.
ready AdCrunch inspected and accepted the bytes. You can register the Asset.
failed AdCrunch refused the file and deleted it. failureCode holds the code and failureReason holds a sentence. Branch on failureCode, never on the sentence.

failureCode is unsupported_type, too_large or unreadable. An import adds source_unreachable and source_length_unknown. It is null unless the status is failed. A failed Asset cannot recover. Create a new Asset.

Register an Asset

A Registration puts an Asset in the library of one advertiser, at its provider. The creative that you create with the Mutations API takes the Asset from that library.

curl -X POST https://api.adcrunch.dev/assets/ast_7c1e9a/registrations \
  -H "Authorization: Bearer $ADCRUNCH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "advertiserId": "acc_1203456789012345" }'

The answer is the Registration, with the status running. The provider does the work after the answer. To follow it, read Get one Asset: registrations holds each Registration of the Asset. Register an Asset to an advertiser shows each field of a Registration.

status Meaning
running The provider has not finished. A video can stay running for several minutes, and that is not a failure.
ready The file is in the library of the advertiser. providerIdentifier holds the id that the provider gave.
failed The Registration did not occur. failureReason holds the reason.

When a provider does not accept a Registration, the Registration ends failed, and failureReason says why. The Asset stays stored. What each provider supports lists the providers that accept a Registration.

When AdCrunch refuses the advertiser before any provider call, failureCode holds one of three codes. Branch on failureCode, never on the sentence in failureReason:

failureCode Meaning What to do
not_found Your organization owns no advertiser of this provider with this id. Check the advertiser id.
provider_not_connected The advertiser has no usable connection to the provider. Reconnect the provider, then send the request again.
missing_write_access The connection does not permit this kind of file. Reconnect the provider to grant the permission, then send the request again.

failureCode is null when the provider refused the file.

Only a ready Asset can be registered. A request for another Asset answers 409:

error Meaning What to do
asset_not_ready The Asset is pending. Read the Asset until its status is ready, then send the request again.
asset_failed The Asset is failed. Read failureCode and failureReason, then create a new Asset.

An Asset can go in the library of many advertisers, with one Registration for each. For one Asset and one advertiser:

  • A Registration that is failed can start again. Send the same request. AdCrunch replaces the failed Registration with a new one.
  • A Registration that is running or ready blocks a second one. The second request answers 409 already_registered.

Delete an Asset

DELETE /assets/{id} deletes the Asset from AdCrunch. It does not remove the file from the library of an advertiser, because that file belongs to the advertiser now. The answer counts those copies in remainingRegistrations.

Was this page helpful?