Introduction
Welcome to the LeadPages Asset API documentation. It manages images and other media assets including HTML files for LeadPages apps and services. It is designed to be a simple (and somewhat primitive) service that provides a generic platform for asset management, instead of serving specific applications.
This API adheres to the (still-in-development) LeadPages HTTP API Standards document, which is available on GitHub.
We suggest starting with the Walkthrough to begin accessing the API.
For a larger overview, the Architecture section provides some not-so-light reading.
Finally, the API section lists the API endpoints.
Walkthrough
All requests must be authorized by Stargate. You cannot use PyChevron or Charteris to upload a file because it does not support multipart requests. However, you may use it for other operation such as updating or deleting a resource OR for creating a reference asset which just points to an existing URL.
Create
There are two ways to create an asset--multipart or reference. Multipart allows you to upload actual file content whereas reference just points to already existing CDN URL. The former also allows you to upload multiple files in a single request. Please note that we currently do not support asynchronous file uploads.
Multipart Request
First, we will look at how to upload a file using multipart.
You can upload a file by providing at least two parts in the request--one for properties and another for actual file content. You can repeat these parts for uploading multiple files at once. Currently, the maximum filesize is 50MB. For multiple file uploads, the entire request should not exceed more than 50MB.
Single File Upload
An asset can be uploaded by creating an asset resource (POST
/asset/v1/assets). The endpoint takes multipart request, first of which
defines a JSON object and second of which takes the asset file content.
------WebKitFormBoundaryDhtqWjbqgAw1cz6R
Content-Disposition: form-data; name="json"; filename="blob"
Content-Type: application/json
{"filename": "sample.png", "public": true}
------WebKitFormBoundaryDhtqWjbqgAw1cz6R
Content-Disposition: form-data; name="file-0"; filename="blob"
Content-Type: image/png
------WebKitFormBoundaryDhtqWjbqgAw1cz6R--
Multiple File Upload
You may upload more than one files at a time by alternating the properties-content multipart pairs.
------WebKitFormBoundaryDhtqWjbqgAw1cz6R
Content-Disposition: form-data; name="json"; filename="blob"
Content-Type: application/json
{"filename": "sample.png", "public": true}
------WebKitFormBoundaryDhtqWjbqgAw1cz6R
Content-Disposition: form-data; name="file-0"; filename="blob"
Content-Type: image/png
------WebKitFormBoundaryDhtqWjbqgAw1cz6R
Content-Disposition: form-data; name="json"; filename="blob2"
Content-Type: application/json
{"filename": "sample.png", "public": true}
------WebKitFormBoundaryDhtqWjbqgAw1cz6R
Content-Disposition: form-data; name="file-0"; filename="blob2"
Content-Type: image/png
------WebKitFormBoundaryDhtqWjbqgAw1cz6R--
Boundary
The part boundary is defined by Content-Type header of the request itself
(not a section within boundaries), as shown below:
multipart/form-data; boundary=----WebKitFormBoundaryDhtqWjbqgAw1cz6R
Notice there is an extra -- in front of the actual boundaries in the
message and at the end of the last boundary as well.
Headers
Each section (within two boundaries) must have Content-Disposition and
Content-Type header. Asset API will use the filename and content type
information in these headers if JSON object does not specify these values.
The name property does not really matter. Asset API will treat the first
section as properties and the second section as asset content.
Size Limit
As mentioned above, the entire request must not exceed 50MB. If it does, you will get a 413 status.
Reference Asset
You may create a reference asset which just points to an existing URL that works as the source of truth. Although we discourage the use of this feature, there is a legitimate case--sync between Builder3 and the core app. In order to allow images from the core app to be queried, a reference must be created on the Asset API side.
To create a reference, use application/json content type instead of
multipart and utilize fileUri parameter to create the reference. For the
sync feature, refer to the Sync section below.
Read
Simply request a GET method on the resource.
HTTP GET /asset/v1/assets/GrgmQfkzEqp6prBr6Dhj6R
{ "contentType": "image/jpeg", "module": null, "userUuid":
"RdXx6BNx3x2hLEQ6EGQNrn", "generalType": "image", "size": 1208800, "_meta":
{ "updated": "2015-11-24T21:23:27+00:00", "created":
"2015-11-24T21:23:19+00:00", "id": "GrgmQfkzEqp6prBr6Dhj6R", "uri":
"http://asset.docker/asset/v1/assets/GrgmQfkzEqp6prBr6Dhj6R" }, "filename":
"22598292462_cee2d5a528_k.jpg", "application": null, "fileUri":
"https://storage.googleapis.com/lp-assets-local/4dj844yjEgmE54YDrBXu8E%2FGrgmQfkzEqp6prBr6Dhj6R",
"public": true, "metadata": {} }
Update
You may update an existing asset but the following properties are not allowed to be modified:
application, module, fileUri, myImageId
But, you shouldn't be updating your asset. If this is the case, please contact the engineers and notify them of your use case.
Delete
In order to delete, just use DELETE method on the asset resource. For
instance, to delete resource GrgmQfkzEqp6prBr6Dhj6R, do the following.
http DELETE /asset/v1/assets/GrgmQfkzEqp6prBr6Dhj6R
If successful, it will be a 204 response.
JSON Parameters
Request
You can specify metadata of the asset you are uploading in the first part of the multipart request. Please note that some properties are permitted for certain operations only. Properties for sync are not listed here.
| Key | Value |
|---|---|
| application | Optional. The application from which the asset is uploaded. Will be used for filtering in the future. |
| contentType | Optional. The content-type of the file. If this is not specified, Content-Type header in the blob section of the multipart will be used instead. |
| fileUri | Required if creating a reference which is just a soft link to an existing URL. It can be an arbitrary URL that is to be used as the source of truth. |
| filename | Optional. The filename. If this is not specified, Content-Disposition header in the blob section of the multipart will be used instead. Note that this property does not affect file URL in the response. The UUID of the asset will be used instead for constructing the URL. |
| metadata | Optional. An arbitrary JSON dictionary data. |
| module | Optional. More granular source of the asset than application. |
| size | The byte size of the asset content. Only accepted for reference assets. |
| public | Default: true. Always set to true for now. Do not set this to false. It is not supported yet. |
Response
Here is the definition of the response you will get:
| Key | Value |
|---|---|
| application | Optional. The application from which the asset is uploaded. Will be used for filtering in the future. |
| contentType | The content type of the file. |
| fileUri | The public URI of the uploaded file content. |
| filename | The filename. |
| generalType | The general type of the content type. Possible values are: application, audio, image, message, multipart, text, video, x-token |
| metadata | An arbitrary JSON dictionary data. |
| module | Optional. More granular source of the asset than application. |
| public | True if the file content can be accessed publicly. False otherwise. |
| size | The byte size of the asset content. |
| userUuid | The UUID of the owner. |
For a single file upload, there will be a single resource whereas for a multiple file upload, there will be multiple resources in the JSON response.
Application and Module
So what are application and module? I will try to explain here.
You can register your application and module before using Asset API so the team can keep track of legit uses of Asset APIs (although you can specify arbitrary values for these properties). Currently, we officially have:
| Application | Module | Description |
|---|---|---|
builder3 |
image-uploader |
Builder3's image uploading feature |
core |
image-uploader |
The core app's image uploading feature |
Note that this is how the app (your app) will determine or filter assets
that are appropriate for your use. Asset API does not support any filtering
at the moment, therefore, you will have to filter them yourself using
application and module properties. Remember, other apps can upload
assets as well.
Public (vs. Private)
Always set public parameter to false until further notice.
Permission
By default, an asset will be only accessible to the user who created it.
Sync
We only sync between Builder3 and the core app (aka Builder2). This is a
somewhat intricate operation, so feel free to reach out to me
(david.an@ave81.com) or Joe (joe@ave81.com) for more details.
From Builder3 to Builder2
We sync assets uploaded directly from Builder3 back to Builder2 as well as the assets deleted from Builder3.
Create
Set sync query parameter to true to enable the sync feature.
POST /asset/v1/assets?sync=true
will synchronize the newly created asset to Builder2. The following JSON parameters must be specified with the given values (in addition to required JSON parameters defined above):
"application": "builder3""module": "image-uploader"
Note that only assets with those parameter values will be sync'ed. If the sync fails, the upload request will fail and return 50x.
Delete
Similar to Upload. Just use DELETE method instead. For example,
DELETE /asset/v1/assets/{asset_id}?sync=true
will attempt to delete the image in the core app first, then the original asset you uploaded.
From Builder2 to Builder3
Refer to the core app documentation for more details on how Builder2
triggers the sync. In summary, Builder2 will create a reference asset that
points to the serving URL that AppEngine has generated. Thus, no file
content will be sent to Asset API. Make sure to use application/json
content type instead of multipart. For deletion, simply DELETE the
reference asset. DO NOT specify sync query parameter for creating or
deleting reference assets.
If you want to use sync feature, please contact engineers first.
Errors
There are three possible errors when using this API:
| Code | Description |
|---|---|
| 400 | Bad Request. Your request is likely to have malformed data. |
| 401 | Unauthorized. You probably did not provide a valid security token or key. |
| 404 | Not Found. The resource you are trying to access does not exist, or you do not have access to the resource you are trying to access. |
| 413 | Request Entry Too Large. Max filesize has been reached. Try again with a smaller media file. |
| 50x | Internal Error. Contact API engineers right away. |
API
| Request | Description |
|---|---|
POST /asset/v1/assets |
Create assets for the authenticated user. You may post more than one asset by alternativing properties-content multiparts. For a single file upload, only one resource is returned. For a multiple file upload, multiple resources are returned in the response. |
POST /asset/v1/users/current/assets |
Same as above. |
POST /asset/v1/users/:user_uuid/assets |
Same as above except use the specified user UUID. |
GET /asset/v1/assets |
Get the list of all assets that belong to the authenticated user. |
GET /asset/v1/users/current/assets |
Same as above. |
GET /asset/v1/users/:user_uuid/assets |
Same as above except use the specified user UUID. |
DELETE /asset/v1/assets |
Bulk delete all assets that belong to the authenticated user. |
DELETE /asset/v1/users/current/assets |
Same as above. |
DELETE /asset/v1/users/:user_uuid/assets |
Same as above except use the specified user UUID. |
PATCH /asset/v1/assets/:asset_uuid |
Updates the asset owned by the authenticated user. |
GET /asset/v1/assets/:asset_uuid |
Get the asset data (not including the asset itself) |
DELETE /asset/v1/assets/:asset_uuid |
Soft deletes the asset. The actual file content of the file URL is not deleted. |
Endpoints
/asset/v1
Ping
/asset/v1/ping
Request
GET /asset/v1/ping
| Body | |
|---|---|
| Empty | |
Response
| Body | |
|---|---|
_meta._version |
StringThe current internal version number of the API. |
_meta |
Dictionary |
| Responses | |
|---|---|
200 OK |
|
| Errors | |
|---|---|
| Empty | |
Assets
/asset/v1/assets
Request
GET /asset/v1/assets
Get a list of assets. Supports a basic "type" filter for favicons or facebook images.
| Body | |
|---|---|
| Empty | |
| Query string | |
|---|---|
limit |
Regexp?(\d+)The maximum number of items to return in the response. |
cursor |
String?A string representing where a previous request "left off" |
search |
String? |
Response
| Body | |
|---|---|
_meta |
ListingMetaMeta information about the response. |
_items |
List[Asset]A list of returned assets. |
| Responses | |
|---|---|
200 OK |
|
| Errors | |
|---|---|
400 Bad Request |
unknown message |
400 Bad Request |
bad content type |
400 Bad Request |
missing Content-Type header |
400 Bad Request |
failed to parse JSON request |
Request
POST /asset/v1/assets
Upload an asset. Can be one more multiple multipart POST requests, or a reference request.
TODO: that because this handler uses req's json response and calls the schemas' build_from method directly (which calls materialize), the Response schema set below doesn't actually matter. Refactor this to align with other ASK APIs and just return listings for both single and multiple uploads. The frontends don't consume the response anyway.
| Body | |
|---|---|
contentType |
String? |
filename |
String? |
metadata |
Dictionary? |
public |
Boolean? |
size |
Integer? |
width |
Integer? |
height |
Integer? |
myImageId |
String? |
application |
String? |
module |
String? |
fileUri |
URI |
| Query string | |
|---|---|
sync |
Enum('true', 'True', 'yes', '1', 'on', 'false', 'False', 'no', '0', 'off') |
Response
| Body | |
|---|---|
| Empty | |
| Responses | |
|---|---|
201 Created |
|
| Errors | |
|---|---|
400 Bad Request |
bad content type |
400 Bad Request |
missing Content-Type header |
400 Bad Request |
failed to parse JSON request |
400 Bad Request |
unknown message |
400 Bad Request |
Malformed Content-Type header |
400 Bad Request |
Bad request |
400 Bad Request |
Invalid multipart content |
413 Payload Too Large |
File is too large |
413 Payload Too Large |
Max filesize exceeded |
500 Internal Server Error |
Upload failed due to sync failure |
Request
DELETE /asset/v1/assets
| Body | |
|---|---|
| Empty | |
Response
| Body | |
|---|---|
| Empty | |
| Responses | |
|---|---|
204 No Content |
|
| Errors | |
|---|---|
400 Bad Request |
unknown message |
400 Bad Request |
bad content type |
400 Bad Request |
missing Content-Type header |
400 Bad Request |
failed to parse JSON request |
Favicons
/asset/v1/assets/favicons
Endpoint for listing favicons.
Request
GET /asset/v1/assets/favicons
| Query string | |
|---|---|
limit |
Regexp?(\d+)The maximum number of items to return in the response. |
cursor |
String?A string representing where a previous request "left off" |
search |
String? |
Response
| Body | |
|---|---|
_meta |
ListingMetaMeta information about the response. |
_items |
List[Asset]A list of returned assets. |
| Responses | |
|---|---|
200 OK |
|
| Errors | |
|---|---|
400 Bad Request |
unknown message |
/asset/v1/assets/facebook
Endpoint for listing Facebook-supported images.
Request
GET /asset/v1/assets/facebook
| Body | |
|---|---|
| Empty | |
| Query string | |
|---|---|
limit |
Regexp?(\d+)The maximum number of items to return in the response. |
cursor |
String?A string representing where a previous request "left off" |
search |
String? |
Response
| Body | |
|---|---|
_meta |
ListingMetaMeta information about the response. |
_items |
List[Asset]A list of returned assets. |
| Responses | |
|---|---|
200 OK |
|
| Errors | |
|---|---|
400 Bad Request |
unknown message |
Asset
/asset/v1/assets/{uuid}
Request
GET /asset/v1/assets/{uuid}
Get an asset resource.
| Body | |
|---|---|
| Empty | |
Response
| Body | |
|---|---|
_meta |
MetaMeta information about the resource. |
contentType |
String? |
filename |
String? |
metadata |
Dictionary |
public |
Boolean |
size |
Integer? |
width |
Integer? |
height |
Integer? |
myImageId |
String? |
application |
String? |
module |
String? |
fileUri |
URI |
generalType |
String? |
| Responses | |
|---|---|
200 OK |
|
| Errors | |
|---|---|
400 Bad Request |
bad content type |
400 Bad Request |
missing Content-Type header |
400 Bad Request |
failed to parse JSON request |
404 Not Found |
asset {uuid} not found |
Request
PATCH /asset/v1/assets/{uuid}
Update an asset. Disallows updating of certain properties.
| Body | |
|---|---|
contentType |
String? |
filename |
String? |
metadata |
Dictionary? |
public |
Boolean? |
size |
Integer? |
width |
Integer? |
height |
Integer? |
myImageId |
String? |
Response
| Body | |
|---|---|
_meta |
MetaMeta information about the resource. |
contentType |
String? |
filename |
String? |
metadata |
Dictionary |
public |
Boolean |
size |
Integer? |
width |
Integer? |
height |
Integer? |
myImageId |
String? |
application |
String? |
module |
String? |
fileUri |
URI |
generalType |
String? |
| Responses | |
|---|---|
200 OK |
|
| Errors | |
|---|---|
400 Bad Request |
bad content type |
400 Bad Request |
missing Content-Type header |
400 Bad Request |
failed to parse JSON request |
404 Not Found |
asset {uuid} not found |
Request
DELETE /asset/v1/assets/{uuid}
| Body | |
|---|---|
| Empty | |
| Query string | |
|---|---|
sync |
Enum('true', 'True', 'yes', '1', 'on', 'false', 'False', 'no', '0', 'off') |
Response
| Body | |
|---|---|
| Empty | |
| Responses | |
|---|---|
204 No Content |
|
| Errors | |
|---|---|
400 Bad Request |
bad content type |
400 Bad Request |
missing Content-Type header |
400 Bad Request |
failed to parse JSON request |
404 Not Found |
asset {uuid} not found |
500 Internal Server Error |
Could not delete. |
Fonts
/asset/v1/fonts
Request
GET /asset/v1/fonts
| Body | |
|---|---|
| Empty | |
| Query string | |
|---|---|
limit |
Regexp?(\d+)The maximum number of items to return in the response. |
cursor |
String?A string representing where a previous request "left off" |
Response
| Body | |
|---|---|
_meta |
ListingMetaMeta information about the response. |
_items |
List[FontFamily] |
| Responses | |
|---|---|
200 OK |
|
| Errors | |
|---|---|
| Empty | |
Request
POST /asset/v1/fonts
| Body | |
|---|---|
name |
String |
Response
| Body | |
|---|---|
_meta |
MetaMeta information about the resource. |
name |
String |
boldFont |
Font? |
boldItalicFont |
Font? |
italicFont |
Font? |
regularFont |
Font? |
cssUri |
String? |
| Responses | |
|---|---|
200 OK |
|
| Errors | |
|---|---|
400 Bad Request |
Font {name} already exists |
Fontfamily
/asset/v1/fonts/family/{uuid}
Request
GET /asset/v1/fonts/family/{uuid}
| Body | |
|---|---|
| Empty | |
Response
| Body | |
|---|---|
_meta |
MetaMeta information about the resource. |
name |
String |
boldFont |
Font? |
boldItalicFont |
Font? |
italicFont |
Font? |
regularFont |
Font? |
cssUri |
String? |
| Responses | |
|---|---|
200 OK |
|
| Errors | |
|---|---|
400 Bad Request |
bad content type |
400 Bad Request |
missing Content-Type header |
400 Bad Request |
failed to parse JSON request |
404 Not Found |
{uuid} not found. |
Request
POST /asset/v1/fonts/family/{uuid}
| Body | |
|---|---|
| Empty | |
Response
| Body | |
|---|---|
_meta |
MetaMeta information about the resource. |
name |
String |
boldFont |
Font? |
boldItalicFont |
Font? |
italicFont |
Font? |
regularFont |
Font? |
cssUri |
String? |
| Responses | |
|---|---|
200 OK |
|
| Errors | |
|---|---|
400 Bad Request |
bad content type |
400 Bad Request |
Bad request. |
400 Bad Request |
missing Content-Type header |
400 Bad Request |
failed to parse JSON request |
400 Bad Request |
Malformed Content-Type header |
404 Not Found |
{uuid} not found. |
413 Payload Too Large |
Max filesize exceeded. |
413 Payload Too Large |
File is too large |
Request
PATCH /asset/v1/fonts/family/{uuid}
| Body | |
|---|---|
name |
String? |
boldFont |
String? |
boldItalicFont |
String? |
italicFont |
String? |
regularFont |
String? |
Response
| Body | |
|---|---|
_meta |
MetaMeta information about the resource. |
name |
String |
boldFont |
Font? |
boldItalicFont |
Font? |
italicFont |
Font? |
regularFont |
Font? |
cssUri |
String? |
| Responses | |
|---|---|
200 OK |
|
| Errors | |
|---|---|
400 Bad Request |
bad content type |
400 Bad Request |
missing Content-Type header |
400 Bad Request |
failed to parse JSON request |
400 Bad Request |
Font {name} already exists |
404 Not Found |
{uuid} not found. |
Request
DELETE /asset/v1/fonts/family/{uuid}
| Body | |
|---|---|
| Empty | |
Response
| Body | |
|---|---|
| Empty | |
| Responses | |
|---|---|
204 No Content |
|
| Errors | |
|---|---|
400 Bad Request |
bad content type |
400 Bad Request |
missing Content-Type header |
400 Bad Request |
failed to parse JSON request |
404 Not Found |
{uuid} not found. |
Font
/asset/v1/fonts/font/{uuid}
Request
GET /asset/v1/fonts/font/{uuid}
| Body | |
|---|---|
| Empty | |
Response
| Body | |
|---|---|
_meta |
MetaMeta information about the resource. |
name |
String? |
weight |
Integer(100 < n < 900| n divides 100) |
style |
Enum('regular', 'italic') |
size |
Integer |
label |
String |
woffUri |
String |
woff2Uri |
String |
| Responses | |
|---|---|
200 OK |
|
| Errors | |
|---|---|
404 Not Found |
{uuid} not found. |
Definitions
ListingMeta
| ListingMeta | |
|---|---|
limit |
IntegerThe requested limit on the number of items. |
total |
Integer?The number of items in the database. |
count |
IntegerThe total number of items in the response. |
cursor |
String?This is used in conjunction with limit to paginate through lists of items. |
Asset
| Asset | |
|---|---|
_meta |
MetaMeta information about the resource. |
contentType |
String? |
filename |
String? |
metadata |
Dictionary |
public |
Boolean |
size |
Integer? |
width |
Integer? |
height |
Integer? |
myImageId |
String? |
application |
String? |
module |
String? |
fileUri |
URI |
generalType |
String? |
Meta
| Meta | |
|---|---|
id |
StringThe resource's unique identifier. |
uri |
URIThe resource's absolute URI. |
created |
DateTimeWhen the resource was created. |
updated |
DateTimeWhen the resource was last updated. |
deleted |
DateTime?When the resource was deleted. |
Font?
| Font? | |
|---|---|
_meta |
MetaMeta information about the resource. |
name |
String? |
weight |
Integer(100 < n < 900| n divides 100) |
style |
Enum('regular', 'italic') |
size |
Integer |
label |
String |
woffUri |
String |
woff2Uri |
String |
FontFamily
| FontFamily | |
|---|---|
_meta |
MetaMeta information about the resource. |
name |
String |
boldFont |
Font? |
boldItalicFont |
Font? |
italicFont |
Font? |
regularFont |
Font? |
cssUri |
String? |