Please note that we've ended development on Astra. While these docs will remain online for reference, we're no longer accepting new trials and will be working to phase out existing accounts.
For more information about moving off the service, please contact us directly.
Astra is a modern cloud platform for storing, transforming, and delivering media. The system includes:
- key-value storage for static files, with type info (image, generic blob, etc.);
- type-specific transforms (e.g., image resizing, video cutting), which can be applied on the fly;
- content delivery via direct link or built-in CDN; and
- flat rates for disk space and bandwidth (no tiers or additional API fees).
The infrastructure behind Astra has powered PhotoShelter for the last decade. Our distributed, redundant storage system currently handles billions of objects, comprising several PBs of data.
Astra has been sunsetted, and we're no longer accepting trial accounts or feature requests.
For questions about moving off Astra, please contact us directly: [email protected]
This version of Astra is a preview release which we are sunsetting. Prior to ending development, we had also planned usage endpoints, cache rulesets, auth tokens, query ranges/paging, and more.
Astra organizes data using a bucket-object model. You can create unlimited buckets (which do not nest) in your account, provided they are uniquely named. Each bucket can contain any number of objects whose names are unique to it. Together, a bucket-object name tuple uniquely identifies a file.
Objects in Astra are typed, with a generic blob
type available as a catch-all. Types are required and determine what metadata the API computes for objects, as well as how they can be transformed.
The RESTful API supports standard CRUD ops, authentication via shared secret or HMAC signature, and serves data directly or via CDN. Except when streaming, the API returns JSON exclusively.
We charge for storage and bandwidth only; API calls are unlimited, except to guard against abuse.
API releases are indicated by major and minor version numbers. Specifying only the major version number always calls the most recent minor release. So right now v0
points to v0.2
.
Your client can check the API version programmatically by calling the root
endpoint.
Minor version updates may add fixes or small features but will always be backward-compatible. Any changes that break compatibility will be released as new major versions, on an opt-in basis.
The simplest API requests you can make are private. Private requests use:
- HTTPS; and
- authentication via shared secrets (pre-shared keys).
Private requests are most appropriate for server-side API clients. You should not make private requests that would expose your account's secrets (over plain HTTP, in client-side code, and so on).
The base URL for private requests, which are served directly, is currently:
https://api.astra.io/v0/
(You can substitute v0.2
for v0
to target the minor version specifically.)
Shared secrets are 32-character, base64url-encoded (i.e., from the set [A-Za-z0-9\-_]
) strings. The API authenticates private requests via secrets passed in the Astra-Secret
HTTP request header:
$ curl https://api.astra.io/v0/... \
-H 'Astra-Secret: 3jaX4Bls9rxCiqSYfv5FaRMbfqff2Vh7' \
...
Future versions of the API may allow you to authenticate requests using tokens.
You can maintain your account's secrets by logging into the control panel. In addition to adding and deleting secrets, you can also toggle their active statuses in order to disable them temporarily.
Except when streaming binary data, the Astra API returns JSON exclusively. All JSON responses, regardless of the resource, contain an ok
boolean to say whether the request succeeded.
Requests for single resources return JSON objects under the data
field:
{
"ok": true,
"data": { ... }
}
When the API returns multiple resources, data
is an array of objects:
{
"ok": true,
"data": [
...,
{ ... },
...
]
}
In both cases, the API will also set the response's HTTP status code to 200 OK
.
If any request fails, the ok
field will be false
, and the API will return an error
object instead of data
. Clients should always check the ok
field first when handling responses.
(For specific examples of signing URLs, see the section on public
endpoint requests.)
In addition to private requests, the API also supports public requests. These requests are:
- aliases for certain
object
andstream
endpoints; - served over vanilla HTTP (versus HTTPS);
- authenticated by calculating and appending HMAC signatures;
- often temporary, with lifetimes enforced using
expires
parameters; and - optionally delivered via built-in CDN.
Public requests are appropriate for client-side use: serving images on web pages, handling user uploads, etc. In these cases, you would build URLs server-side and then pass them to the front end.
Authentication using one-time tokens may be supported in future API versions.
When using the public
endpoint, change the standard base URL's protocol to plain http
:
http://api.astra.io/v0/public/...
To serve public requests via CDN, you can substitute cdn
for api
in the subdomain:
http://cdn.astra.io/v0/public/...
The API supports delivery via CDN for public streaming only; metadata must be accessed directly.
HMAC signatures are used to verify the sources and integrity of public requests. Since changing URLs invalidates their signatures, signing "locks in" parameters like expires
fields and transforms.
The API's method for constructing HMAC-SHA1 signatures is (in PHP-style pseudocode):
function sign_request($http_method, $path, $percent_encoded_query_str=null, $secret)
{
if (isset($percent_encoded_query_str)) {
$sorted_qs = sort_by_field_name($percent_encoded_query_str); // lexicographical order
}
$str = $http_method . ':' . $path . (empty($sorted_qs) ? '' : ('?' . $sorted_qs));
$sha1 = hash_hmac('sha1', $str, $secret, true); // as raw binary data
return rtrim(strtr(base64_encode($sha1), '+/', '-_'), '='); // unpadded base64url sig
}
You can then pass signatures with requests by adding hmac={signature}
to their query strings.
Buckets and objects are the two entities you'll manipulate using the API's current endpoints. The list of entities will likely grow as we add support for rulesets, account configuration endpoints, etc.
Entities have two standard JSON representations, called long and short forms:
- Long forms list all attributes and are usually returned when interacting with a single entity.
- Short forms are truncated versions, which are more appropriate for nesting (e.g., listing objects within buckets) or inclusion in lists of multiple entities, like query results.
A few things to keep in mind when dealing with entity fields:
- The API serves and accepts timestamp strings in RFC 3339 format only. These timestamps must be UTC-offset, with second-level precision (e.g.,
2014-08-30T14:28:56Z
). - All integers are potentially 64-bit, which may cause problems for JavaScript clients.
- Buckets and objects both have
status
fields which are alwaysready
. We may create values in later API versions to handle async processing, so filtering forready
is smart future-proofing.
Buckets are containers for objects. They cannot nest, and must be uniquely named within your account. Deleting buckets from Astra also deletes all the objects they contain.
Field | Type | Description |
---|---|---|
name |
string | 1-256 chars from [A-Za-z0-9.\-_] (can't begin/end with . ) |
size |
integer | total of all objects (in bytes) |
status |
string | ready (reserved for future use) |
objects |
array | list of short-form objects |
ctime |
timestamp | creation time |
mtime |
timestamp | modification time (doesn't inherit from objects) |
{
"name": "someBucket",
"size": 437716,
"status": "ready",
"objects": [
{"name": "fooObject.gif"},
{"name": "barObject.js"},
{"name": "bazObject.pdf"}
],
"ctime": "2014-08-30T14:28:56Z",
"mtime": "2014-10-07T18:35:19Z"
}
Short-form buckets replace the objects
array with an integer count:
{
"name": "someBucket",
"size": 437716,
"status": "ready",
"objects": 3,
"ctime": "2014-08-30T14:28:56Z",
"mtime": "2014-10-07T18:35:19Z"
}
Objects sit inside buckets and represent data you've uploaded, plus metadata the API has parsed. Types determine objects' metadata and transforms. A generic blob
type can be used as a catch-all.
You can identify objects in your account uniquely using bucket-object name tuples.
Field | Type | Description |
---|---|---|
name |
string | 1-2048 chars from [A-Za-z0-9.\-_] (can't begin/end with . ) |
bucket |
string | name of parent bucket |
hash |
string | SHA-1 hash (40 hex chars) |
size |
integer | size (in bytes) |
type |
string | currently blob , image , or video |
... | ... | type-specific fields |
status |
string | ready (reserved for future use) |
ctime |
timestamp | creation time |
mtime |
timestamp | modification time |
Type-specific fields:
Field | Type | Description |
---|---|---|
content |
string | Content-Type ([A-Za-z0-9\-]+\/[A-Za-z0-9\-]+ ) (may be empty) |
{
"name": "blobObject.pdf",
"bucket": "someBucket",
"hash": "1a5699e83a1d4aaf7a23ddb5e9f0a8979d0007d8",
"size": 9381224,
"type": "blob",
"status": "ready",
"content": "application/pdf",
"ctime": "2014-07-28T14:42:27Z",
"mtime": "2014-07-28T14:42:27Z"
}
Type-specific fields:
Field | Type | Description |
---|---|---|
format |
string | currently gif , jpeg , or png |
width |
integer | image width (in pixels) |
height |
integer | image height (in pixels) |
{
"name": "imageObject.jpg",
"bucket": "someBucket",
"hash": "dc53baf6000a0b7d3ef55afe86a7f48fc16c5373",
"size": 1845778,
"type": "image",
"status": "ready",
"format": "jpeg",
"width": 3264,
"height": 2448,
"ctime": "2014-06-03T10:56:08Z",
"mtime": "2014-06-14T02:17:13Z"
}
Type-specific fields:
Field | Type | Description |
---|---|---|
format |
string | currently mp4 , ogg , or webm |
width |
integer | video width (in pixels) |
height |
integer | video height (in pixels) |
start |
float | video start (in seconds) |
duration |
float | video duration (in seconds) |
{
"name": "videoObject.mp4",
"bucket": "someBucket",
"hash": "06e786af81f20f7d31ba34fb0a5e92b0e7c4ff19",
"size": 99476300,
"type": "video",
"status": "ready",
"format": "mp4",
"width": 1280,
"height": 720,
"start": 0,
"duration": 112.831667,
"ctime": "2014-11-16T20:22:58Z",
"mtime": "2014-11-16T20:22:58Z"
}
Regardless of type, short-form objects consist of a name
field only:
{"name": "blobObject.pdf"}
{"name": "imageObject.jpg"}
{"name": "videoObject.mp4"}
The Astra API uses a RESTful structure, organizing CRUD operations on entities around HTTP methods. (Absent a true PATCH
verb, the API uses POST
for both creating and updating entities.)
You can pass required or optional parameters as multipart form data (multipart/form-data
). Query strings are used for setting request-specific info, like transform details or HMAC signatures.
Currently, the API supports only ASCII values in form data, and requires timestamps to be in RFC 3339 format (relative to UTC) with second-level precision (e.g., 2014-08-30T14:28:56Z
).
Any values you pass to the API in query string fields should be percent-encoded.
The root
pseudo-endpoint is located at the API base and returns info about the API itself. Right now, root
indicates only the version of the API you're accessing. We may expand this in the future.
Action | Method | Path |
---|---|---|
Read | GET |
/ |
- Method:
GET
- Path:
/
Example
Fetch the API version programmatically, which is useful if you're specifying only major revisions:
$ curl https://api.astra.io/v0/ \
-H 'Astra-Secret: 3jaX4Bls9rxCiqSYfv5FaRMbfqff2Vh7' \
-X GET
=>
{
"ok": true,
"data": {
"version": {
"string": "0.2",
"major": 0,
"minor": 2
}
}
}
The bucket
endpoint lets you maintain buckets. Note that deleting buckets deletes their contents.
Action | Method | Path |
---|---|---|
Create | POST |
/bucket |
Query | GET |
/bucket |
Read | GET |
/bucket/{bkt_name} |
Update | POST |
/bucket/{bkt_name} |
Delete | DELETE |
/bucket/{bkt_name} |
- Method:
POST
- Path:
/bucket
- Form fields:
name
- bucket name
Example
Make a new bucket called fooBucket
:
$ curl https://api.astra.io/v0/bucket \
-H 'Astra-Secret: 3jaX4Bls9rxCiqSYfv5FaRMbfqff2Vh7' \
-X POST \
-F name=fooBucket
=>
{
"ok": true,
"data": {
"name": "fooBucket",
"size": 0,
"status": "ready",
"objects": [],
"ctime": "2014-09-02T10:11:34Z",
"mtime": "2014-09-02T10:11:34Z"
}
}
- Method:
GET
- Path:
/bucket
Example
List all the buckets in your account:
$ curl https://api.astra.io/v0/bucket \
-H 'Astra-Secret: 3jaX4Bls9rxCiqSYfv5FaRMbfqff2Vh7' \
-X GET
=>
{
"ok": true,
"data": [
...,
{
"name": "uploads",
"size": 479236,
"status": "ready",
"objects": 2,
"ctime": "2014-08-27T16:22:32Z",
"mtime": "2014-09-01T05:36:45Z"
},
{
"name": "fooBucket",
"size": 0,
"status": "ready",
"objects": 0,
"ctime": "2014-09-02T10:11:34Z",
"mtime": "2014-09-02T10:11:34Z"
},
...
]
}
- Method:
GET
- Path:
/bucket/{bkt_name}
Example
Fetch a bucket named uploads
:
$ curl https://api.astra.io/v0/bucket/uploads \
-H 'Astra-Secret: 3jaX4Bls9rxCiqSYfv5FaRMbfqff2Vh7' \
-X GET
=>
{
"ok": true,
"data": {
"name": "uploads",
"size": 1479236,
"status": "ready",
"objects": [
{"name": "upload-0.jpg"},
{"name": "upload-1.png"}
],
"ctime": "2014-08-27T16:22:32Z",
"mtime": "2014-09-01T05:36:45Z"
}
}
- Method:
POST
- Path:
/bucket/{bkt_name}
- Form fields:
- [
name
] - new bucket name (optional)
- [
Example
Rename fooBucket
to barBucket
:
$ curl https://api.astra.io/v0/bucket/fooBucket \
-H 'Astra-Secret: 3jaX4Bls9rxCiqSYfv5FaRMbfqff2Vh7' \
-X POST \
-F name=barBucket
=>
{
"ok": true,
"data": {
"name": "barBucket",
"size": 0,
"status": "ready",
"objects": [],
"ctime": "2014-09-02T10:11:34Z",
"mtime": "2014-09-04T12:01:27Z"
}
}
- Method:
DELETE
- Path:
/bucket/{bkt_name}
Example
Remove barBucket
(including any objects inside) from your account:
$ curl https://api.astra.io/v0/bucket/barBucket \
-H 'Astra-Secret: 3jaX4Bls9rxCiqSYfv5FaRMbfqff2Vh7' \
-X DELETE
=>
{"ok": true}
The object
endpoint lets you perform CRUD operations on objects. The parameters you pass to this endpoint may differ from object type to object type (when creating an object, for example).
Use this endpoint to act on objects as entities. If you need to stream them, use the stream
endpoint.
Action | Method | Path |
---|---|---|
Create | POST |
/bucket/{bkt_name}/object |
Query | GET |
/bucket/{bkt_name}/object |
Read | GET |
/bucket/{bkt_name}/object/{obj_name} |
Update | POST |
/bucket/{bkt_name}/object/{obj_name} |
Delete | DELETE |
/bucket/{bkt_name}/object/{obj_name} |
- Method:
POST
- Path:
/bucket/{bkt_name}/object
- Form fields:
name
- object nametype
- object type (currentlyblob
orimage
)file
- binary data- if
blob
:- [
content
] -Content-Type
for streaming (optional)
- [
Example 1
Upload a new blob
object named static.js
to testBucket
:
$ curl https://api.astra.io/v0/bucket/testBucket/object \
-H 'Astra-Secret: 3jaX4Bls9rxCiqSYfv5FaRMbfqff2Vh7' \
-X POST \
-F name=static.js \
-F type=blob \
-F file=@/path/to/local/file/static-local.js \
-F content=application/javascript
=>
{
"ok": true,
"data": {
"name": "static.js",
"bucket": "testBucket",
"hash": "1d0204069fa14db15adf1ac0e925ed166b9f2a51",
"size": 83968,
"type": "blob",
"status": "ready",
"content": "application/javascript",
"ctime": "2014-06-03T18:11:51Z",
"mtime": "2014-06-03T18:11:51Z"
}
}
Example 2
Make a new image
object called hawaii.jpg
in testBucket
:
$ curl https://api.astra.io/v0/bucket/testBucket/object \
-H 'Astra-Secret: 3jaX4Bls9rxCiqSYfv5FaRMbfqff2Vh7' \
-X POST \
-F name=hawaii.jpg \
-F type=image \
-F file=@/path/to/local/file/hawaii-local.jpg
=>
{
"ok": true,
"data": {
"name": "hawaii.jpg",
"bucket": "testBucket",
"hash": "8b9f3c27fc466cf8a1c6627166b6227385e45886",
"size": 686480,
"type": "image",
"status": "ready",
"format": "jpeg",
"width": 1600,
"height": 1200,
"ctime": "2014-06-05T07:42:24Z",
"mtime": "2014-06-05T07:42:24Z"
}
}
- Method:
GET
- Path:
/bucket/{bkt_name}/object
Example
List all the objects in testBucket
:
$ curl https://api.astra.io/v0/bucket/testBucket/object \
-H 'Astra-Secret: 3jaX4Bls9rxCiqSYfv5FaRMbfqff2Vh7' \
-X GET
=>
{
"ok": true,
"data": [
...,
{
"name": "static.js",
"bucket": "testBucket",
"hash": "1d0204069fa14db15adf1ac0e925ed166b9f2a51",
"size": 83968,
"type": "blob",
"status": "ready",
"content": "application/javascript",
"ctime": "2014-06-03T18:11:51Z",
"mtime": "2014-06-03T18:11:51Z"
},
{
"name": "hawaii.jpg",
"bucket": "testBucket",
"hash": "8b9f3c27fc466cf8a1c6627166b6227385e45886",
"size": 686480,
"type": "image",
"status": "ready",
"format": "jpeg",
"width": 1600,
"height": 1200,
"ctime": "2014-06-05T07:42:24Z",
"mtime": "2014-06-05T07:42:24Z"
},
...
]
}
- Method:
GET
- Path:
/bucket/{bkt_name}/object/{obj_name}
Example
Fetch an image
object called hawaii.jpg
from testBucket
:
$ curl https://api.astra.io/v0/bucket/testBucket/object/hawaii.jpg \
-H 'Astra-Secret: 3jaX4Bls9rxCiqSYfv5FaRMbfqff2Vh7' \
-X GET
=>
{
"ok": true,
"data": {
"name": "hawaii.jpg",
"bucket": "testBucket",
"hash": "8b9f3c27fc466cf8a1c6627166b6227385e45886",
"size": 686480,
"type": "image",
"status": "ready",
"format": "jpeg",
"width": 1600,
"height": 1200,
"ctime": "2014-06-05T07:42:24Z",
"mtime": "2014-06-05T07:42:24Z"
}
}
- Method:
POST
- Path:
/bucket/{bkt_name}/object/{obj_name}
- Form fields:
- [
bucket
] - move object to new bucket (optional) - [
name
] - new object name (optional) - [
type
] - new object type (optional) - [
file
] - new binary data (required if newtype
; otherwise optional) - if
blob
:- [
content
] - newContent-Type
for streaming (optional)
- [
- [
Example 1
Update a blob
object named static.js
in testBucket
:
$ curl https://api.astra.io/v0/bucket/testBucket/object/static.js \
-H 'Astra-Secret: 3jaX4Bls9rxCiqSYfv5FaRMbfqff2Vh7' \
-X POST \
-F name=static.min.js \
-F file=@/path/to/local/file/static-local.min.js
=>
{
"ok": true,
"data": {
"name": "static.min.js",
"bucket": "testBucket",
"hash": "c79b0a1cbc9707b58a8a4a8638df4a32ca507087",
"size": 48312,
"type": "blob",
"status": "ready",
"content": "application/javascript",
"ctime": "2014-06-03T18:11:51Z",
"mtime": "2014-06-03T22:05:48Z"
}
}
Example 2
Upload a new image
to replace hawaii.jpg
in testBucket
:
$ curl https://api.astra.io/v0/bucket/testBucket/object/hawaii.jpg \
-H 'Astra-Secret: 3jaX4Bls9rxCiqSYfv5FaRMbfqff2Vh7' \
-X POST \
-F file=@/path/to/local/file/kauai-local.jpg
=>
{
"ok": true,
"data": {
"name": "hawaii.jpg",
"bucket": "testBucket",
"hash": "7892bec20a397645bb6a5a6777933b2265303082",
"size": 512191,
"type": "image",
"status": "ready",
"format": "jpeg",
"width": 1200,
"height": 800,
"ctime": "2014-06-05T07:42:24Z",
"mtime": "2014-06-05T19:27:11Z"
}
}
- Method:
DELETE
- Path:
/bucket/{bkt_name}/object/{obj_name}
Example
Remove blob
object static.min.js
from testBucket
:
$ curl https://api.astra.io/v0/bucket/testBucket/object/static.min.js \
-H 'Astra-Secret: 3jaX4Bls9rxCiqSYfv5FaRMbfqff2Vh7' \
-X DELETE
=>
{"ok": true}
The stream
endpoint delivers objects as binary data. To act on objects, use the object
endpoint.
You can apply transforms when streaming by adding optional parameters via query string.
Action | Method | Path |
---|---|---|
Read | GET |
/bucket/{bkt_name}/stream/{obj_name} |
- Method:
GET
- Path:
/bucket/{bkt_name}/stream/{obj_name}
- Query string:
- type-specific transforms
(Refer to the section on transforms for examples of on-the-fly modifications.)
Example
Serve an image called foo.png
directly, without applying any transforms:
$ curl 'https://api.astra.io/v0/bucket/content/stream/foo.png' \
-H 'Astra-Secret: 3jaX4Bls9rxCiqSYfv5FaRMbfqff2Vh7' \
-X GET
=> image streams directly as Content-Type: image/png
The public
endpoint aliases certain object
and stream
endpoints to deliver objects publicly. You can use this endpoint to build self-contained, signed requests suitable for embedding, etc.
- Form fields:
- form fields are forwarded to aliased endpoints
- Query string:
- query strings are forwarded to aliased endpoints
hmac
- HMAC-SHA1 signature- [
expires
] - percent-encoded RFC 3339 timestamp (optional)
(Refer to the section on HMAC signatures to learn the algorithm for signing messages.)
Action | Method | Path |
---|---|---|
Create | POST |
/public/{acct_label}/{bkt_name} |
Query | GET |
/public/{acct_label}/{bkt_name} |
Read | GET |
/public/{acct_label}/{bkt_name}/{obj_name} |
Update | POST |
/public/{acct_label}/{bkt_name}/{obj_name} |
Delete | DELETE |
/public/{acct_label}/{bkt_name}/{obj_name} |
(This aliases the object
create endpoint.)
(This aliases the object
query endpoint.)
(This aliases the stream
read endpoint; appending ?metadata=true
aliases object
read. As an alias to the stream
read endpoint, you can sign in on-the-fly transforms via query string.)
Example 1
Resize and serve otis-04.jpg
from bucket assets
(in account pics
) via CDN:
$http_method = 'GET';
$path = '/v0/public/pics/assets/otis-04.jpg';
$sorted_qs = 'height=400&width=600';
$secret = '3jaX4Bls9rxCiqSYfv5FaRMbfqff2Vh7';
$str = $http_method . ':' . $path . (empty($sorted_qs) ? '' : ('?' . $sorted_qs));
// => 'GET:/v0/public/pics/assets/otis-04.jpg?height=400&width=600'
$sha1 = hash_hmac('sha1', $str, $secret, true);
$sig = rtrim(strtr(base64_encode($sha1), '+/', '-_'), '=');
// => 'Ezh1DtfZNp0_vgu85UURWlnTyko'
=>
$ curl 'http://cdn.astra.io/v0/public/pics/assets/otis-04.jpg?width=600&height=400&hmac=Ezh1DtfZNp0_vgu85UURWlnTyko' \
-X GET
=> image streams via CDN as Content-Type: image/jpeg
Example 2
Stream client.js
directly from bucket js
(in account code
) with expiration:
$http_method = 'GET';
$path = '/v0/public/code/js/client.js';
$sorted_qs = 'expires=2014-06-01T12%3A00%3A00Z'; // percent-encoded '2014-06-01T12:00:00Z'
$secret = '3jaX4Bls9rxCiqSYfv5FaRMbfqff2Vh7';
$str = $http_method . ':' . $path . (empty($sorted_qs) ? '' : ('?' . $sorted_qs));
// => 'GET:/v0/public/code/js/client.js?expires=2014-06-01T12%3A00%3A00Z'
$sha1 = hash_hmac('sha1', $str, $secret, true);
$sig = rtrim(strtr(base64_encode($sha1), '+/', '-_'), '=');
// => 'iE16Op-GwtTm_urfx6od-mQV_5A'
=>
$ curl 'http://api.astra.io//v0/public/code/js/client.js?expires=2014-06-01T12%3A00%3A00Z&hmac=iE16Op-GwtTm_urfx6od-mQV_5A' \
-X GET
=> blob streams directly as Content-Type: application/javascript
(This aliases object
update endpoint.)
(This aliases object
delete endpoint.)
Transforms are object manipulations (image resizing, video cutting, etc.) that the API can perform on the fly. Transformed objects are cached, so subsequent calls with the same parameters incur no cost.
You can apply transforms by modifying the query strings you pass to the stream
and public
endpoints. Note that transforms never modify the original objects you've uploaded.
Right now transforms cannot be combined. In the future, you'll be able to apply transforms in series.
n/a
Field | Type | Description |
---|---|---|
width |
integer | image width (in pixels) |
height |
integer | image height (in pixels) |
mode |
string (optional) | fill or fit sizing |
orient |
boolean (optional) | apply EXIF orientation to jpeg images |
The fill
parameter resizes an image to completely fill a bounding box whose dimensions you specify. The image's aspect ratio will be maintained, though the image may be cropped in order to fill the box. Specifying fit
is similar, except the image will not be cropped and thus may not fill the box.
Both width
and height
are required if mode
is not set (an arbitrary resize, which may distort the image), or if mode
is set to fill
. If mode
is fit
, then either width
or height
must be set.
The orient
flag can be used with any resize operation on jpeg
images. It's particularly useful when dealing with media uploaded from mobile devices, whose cameras often don't rotate images.
Dimensions for scaling up images are currently capped at 10,000 px each.
Example 1
Resize an image arbitrarily and serve directly:
$ curl 'https://api.astra.io/v0/bucket/content/stream/lol.gif?width=320&height=260' \
-H 'Astra-Secret: 3jaX4Bls9rxCiqSYfv5FaRMbfqff2Vh7' \
-X GET
=> image streams directly as Content-Type: image/gif
Example 2
Correctly orient an image named iPhone.jpg
, which has rotation EXIF data:
$ curl https://api.astra.io/v0/bucket/content/stream/iPhone.jpg?orient=true \
-H 'Astra-Secret: 3jaX4Bls9rxCiqSYfv5FaRMbfqff2Vh7' \
-X GET
=> image streams directly as Content-Type: image/jpeg
Example 3
Orient an image (in account biz
) and resize to completely fill a 400x400 bounding box:
$ curl 'http://cdn.astra.io/v0/public/biz/dogpics/zoe2.jpg?orient=true&mode=fill&width=400&height=400&expires=2015-01-14T16%3A30%3A00Z&hmac=yuEreJMqExv0A96Iu-HYAzMVo60' \
-X GET
=> image streams via CDN as Content-Type: image/jpeg
until 2015-01-14T16:30:00Z
Example 4
Resize an image to fit a bounding box 320 px wide, keeping its aspect ratio, and download it:
$ curl 'https://api.astra.io/v0/bucket/bikes/stream/fixie08.jpg?mode=fit&width=320' \
-H 'Astra-Secret: 3jaX4Bls9rxCiqSYfv5FaRMbfqff2Vh7' \
-X GET \
> /path/to/local/file/fixie08-resized.jpg
=> image saves locally as fixie08-resized.jpg
Field | Type | Description |
---|---|---|
width |
integer | video width (in pixels) |
height |
integer | video height (in pixels) |
Both width
and height
parameters are required, and the maximum downsizing factor is 60x in both dimensions (e.g., a video 600 px wide can be scaled down no smaller than 10 px wide). Also, the width
and height
for mp4
-format videos must be a multiple of 2 based on the encoder used.
Example 1
Resize a large video to 640x480 and download it:
$ curl 'https://api.astra.io/v0/bucket/doge/stream/wow.mp4?width=640&height=480' \
-H 'Astra-Secret: 3jaX4Bls9rxCiqSYfv5FaRMbfqff2Vh7' \
-X GET \
> /path/to/local/file/wow-resized.mp4
=> video saves locally as wow-resized.mp4
Example 2
Resize a video and stream it publicly (from account media
) with an expiration time:
$ curl 'http://api.astra.io/v0/public/media/web/X9qAkz.ogg?width=150&height=75&expires=2015-02-18T12%3A00%3A00Z&hmac=PhdpwhJ1uYdgVFXvw5v89yab2XM' \
-X GET
=> video streams directly as Content-Type: video/webm
until 2015-02-18T12:00:00Z
Field | Type | Description |
---|---|---|
start |
float | segment start time (in seconds) |
end |
float | segment end time (in seconds) |
The start
and end
parameters default to 0 and the duration of the video, respectively, if omitted.
Example 1
Cut a 28.25-second segment from a video (in account biz
) and stream it publicly via CDN:
$ curl 'http://cdn.astra.io/v0/public/biz/footage/interview3.webm?start=2&end=30.25&hmac=3syfFCpZR-PgoyJ_QN7kITd7Fyk' \
-X GET
=> video streams via CDN as Content-Type: video/webm
Example 2
Trim 3.5 seconds from the beginning of a video and download it:
$ curl https://api.astra.io/v0/bucket/ocean-uncut/stream/waves.ogg?start=3.5 \
-H 'Astra-Secret: 3jaX4Bls9rxCiqSYfv5FaRMbfqff2Vh7' \
-X GET \
> /path/to/local/file/waves-cut.ogg
=> video saves locally as waves-cut.ogg
If any request fails, the API will return an error
object instead of data
:
{
"ok": false,
"error": {
"type": ...,
"code": ...,
"message": ...
}
}
The API will also set the response's HTTP status code accordingly.
Type | Code | Message |
---|---|---|
ProtocolHTTPRequiredErr |
403 |
protocol http required |
ProtocolHTTPSRequiredErr |
403 |
protocol https required |
Type | Code | Message |
---|---|---|
AuthSecretMissingErr |
401 |
request header requires secret |
AuthSecretInvalidErr |
401 |
invalid or expired secret |
AuthHMACErr |
401 |
invalid hmac signature |
AuthExpiredErr |
401 |
expired link |
Type | Code | Message |
---|---|---|
FormFieldErr |
400 |
field '{field_name}' required |
FormValueErr |
401 |
value '{value}' invalid for field '{field_name}' |
FormFileErr |
400 |
field '{field_name}' expects input file |
(A FormErr
indicates a problem with the HTML form data sent to an endpoint.)
Type | Code | Message |
---|---|---|
BucketNotFoundErr |
404 |
bucket '{bkt_name}' not found |
BucketAlreadyExistsErr |
409 |
bucket '{bkt_name}' already exists |
Type | Code | Message |
---|---|---|
ObjectNotFoundErr |
404 |
object '{obj_name}' not found in bucket '{bkt_name}' |
ObjectAlreadyExistsErr |
409 |
object '{obj_name}' already exists in bucket '{bkt_name}' |
n/a
Type | Code | Message |
---|---|---|
ObjectImageFormatErr |
400 |
image type does not support this format |
ObjectImageEmptyErr |
400 |
file empty or image has no width/height |
Type | Code | Message |
---|---|---|
ObjectImageFormatErr |
400 |
video type does not support this format |
ObjectImageEmptyErr |
400 |
file empty or first video stream has no width/height |
Type | Code | Message |
---|---|---|
InternalErr |
500 |
internal server error |
(An InternalErr
signifies a server-side problem, which we'll investigate.)
- 2015-07-25 - Add note about sunsetting service
- 2014-11-14 - Clarify image resizing options
- 2014-11-10 - Note that update can be used to move objects
- 2014-11-03 - Add back vanilla object stream example
- 2014-11-03 - Bump version in root; revise long-form object types
- 2014-11-03 - Break out transforms; move section on versioning
- 2014-10-22 - Add video type support; orient flag for images
- 2014-08-06 - Fix blob content field regex; other cleanups
- 2014-08-04 - Update header and link to control panel
- 2014-08-04 - Clarify HMAC code and add ProtocolErr type
- 2014-08-01 - Note CDN for public streams only
- 2014-08-01 - Clarify period in bucket/object names
- 2014-08-01 - Add TOC link to public endpoint
- 2014-05-13 - Correct direct streaming example
- 2014-05-13 - Fix missing name in object update path
- 2014-05-12 - Initial API release