API Usage
ContentGrid applications expose a REST API using JSON as a response format. All JSON responses use HAL as a hypertext format, linking to related resources. Actions that can be taken on resources are specified using the HAL-FORMS format.
Before using the API, you need to authenticate and obtain an access token.
This documentation covers the basics of using the Application REST API, advanced usage with HAL is described in HAL Usage.
Because the specific API is generated from the configured data model, the examples will use an example datamodel.
OpenAPI spec
An OpenAPI spec for your application’s datamodel is available from the ContentGrid Console. Every Release has its own associated OpenAPI spec, which you can view or download.
For deployed applications, a copy of the OpenAPI spec is also available on /openapi.yaml (after authentication).
Resource types
A ContentGrid application can be configured with kinds of entities that have attributes and relations.
A single instance of such an entity is generically referred to as an entity-item. Multiple entity-items of the same kind together form an entity-collection.
These two form the main resource types in a ContentGrid application. To support these resource types, a couple of additional resource types exist. Their relation to the main resource types is explained in the Resource Types reference.
Basic operations
This section explains all the basic operations (create, read, update, delete) for the resource types.
The operations are explained in their minimal form, without any request modifiers applied.
Tip
You can follow along with the examples by creating an application with the Example datamodel set up. Define the following variables to make the examples easily runnable.
REGION="<Region where the application is deployed>"
APP_ID="<ID of the application>"
REALM="<Internal reference of your IAM Realm>"
CLIENT_ID="<IAM Service account Client ID>"
CLIENT_SECRET="<IAM Service account Client Secret>"You will need to obtain an access token. This can be done easily with an IAM service account. The Authentication documentation contains more details on this.
TOKEN="$(curl -Ss https://auth.$REGION.contentgrid.cloud/realms/$REALM/protocol/openid-connect/token \
-u $CLIENT_ID:$CLIENT_SECRET \
-d grant_type=client_credentials | jq .access_token -r)"An access token is valid for 5 minutes; you can obtain a new token by re-running the command above.
Next, set up some entities that will be used by the examples
INVOICE_ID="$(curl -Ss https://$APP_ID.$REGION.contentgrid.cloud/invoices \
-F "total_amount=15.95" \
-F "received=2024-07-15" \
-F "pay_before=2024-08-14" \
-F "document=dummy-invoice;filename=invoice.txt;type=text/plain" \
-H "Authorization: Bearer $TOKEN" \
| jq .id -r
)"
INVOICE2_ID="$(curl -Ss https://$APP_ID.$REGION.contentgrid.cloud/invoices \
-F "total_amount=123.4" \
-F "received=2020-01-01" \
-F "pay_before=2020-02-01" \
-H "Authorization: Bearer $TOKEN" \
| jq .id -r
)"
SUPPLIER_ID="$(curl -Ss https://$APP_ID.$REGION.contentgrid.cloud/suppliers \
-F "name=Test supplier" \
-F "telephone=test" \
-H "Authorization: Bearer $TOKEN" \
| jq .id -r
)"entity-item operations
An entity-item resource is exposed on the path /<entity-name-plural>/{id} (e.g. /invoices/{id} for the invoice entity type).
{id} is a placeholder for the actual ID of the entity-item.
The following operations are available:
| Method | Content-Type | Description |
|---|---|---|
GET |
application/hal+json |
Read the entity-item with the specified id |
PUT |
application/json |
Replace the entity-item data with the data supplied in the request body |
PATCH |
application/json |
Update the entity-item data, modifying only the fields supplied in the request body |
DELETE |
N/A | Remove the entity-item |
Note
The difference between PUT and PATCH is how attributes that are not present in the request body are handled:
PUT: It is written to the entity-item asnull, removing the stored value.PATCH: It is skipped, the stored value is unchanged.
This rule also applies to attributes of type content. Omitting the field will remove the content.
Update entity-item using PUT/PATCH
To show the difference between updating an entity-item with PUT or PATCH, we first show the existing state
{
"id": "3211be1d-1ed1-4850-8ea6-3fa3218031f6",
"received": "2024-07-15",
"document": {
"size": 123456,
"mimetype": "application/pdf",
"filename": "example-invoice.pdf"
},
"pay_before": "2024-08-14",
"total_amount": 15.95,
"_links": {
[...]
},
"_templates": {
[...]
}
}curl -i -X PUT https://$APP_ID.$REGION.contentgrid.cloud/invoices/$INVOICE_ID \
--json "{\"pay_before\": \"2024-08-31\", \"received\": \"2024-07-15\", \"total_amount\": 15.95}" \
-H "Authorization: Bearer $TOKEN"
PUT /invoices/$INVOICE_ID HTTP/1.1
Authorization: Bearer $TOKEN
Content-Type: application/json
{"pay_before": "2024-08-31", "received": "2024-07-15", "total_amount": 15.95}HTTP/1.1 204 No ContentNote that document was not present in the request body, and has now been set to null, removing the document.
curl -i https://$APP_ID.$REGION.contentgrid.cloud/invoices/$INVOICE_ID \
-H "Authorization: Bearer $TOKEN"
GET /invoices/$INVOICE_ID HTTP/1.1
Authorization: Bearer $TOKEN
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "3211be1d-1ed1-4850-8ea6-3fa3218031f6",
"received": "2024-07-15",
"document": null,
"pay_before": "2024-08-31",
"total_amount": 15.95,
"_links": {
[...]
},
"_templates": {
[...]
}
}curl -i -X PATCH https://$APP_ID.$REGION.contentgrid.cloud/invoices/$INVOICE_ID \
--json "{\"pay_before\": \"2024-08-31\", \"received\": \"2024-07-15\", \"total_amount\": 15.95}" \
-H "Authorization: Bearer $TOKEN"
PATCH /invoices/$INVOICE_ID HTTP/1.1
Authorization: Bearer $TOKEN
Content-Type: application/json
{"pay_before": "2024-08-31", "received": "2024-07-15", "total_amount": 15.95}HTTP/1.1 204 No ContentFields that are absent in the request body are not modified from their original values.
curl -i https://$APP_ID.$REGION.contentgrid.cloud/invoices/$INVOICE_ID \
-H "Authorization: Bearer $TOKEN"
GET /invoices/$INVOICE_ID HTTP/1.1
Authorization: Bearer $TOKEN
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "3211be1d-1ed1-4850-8ea6-3fa3218031f6",
"received": "2024-07-15",
"document": {
"size": 123456,
"mimetype": "application/pdf",
"filename": "example-invoice.pdf"
},
"pay_before": "2024-08-31",
"total_amount": 15.95,
"_links": {
[...]
},
"_templates": {
[...]
}
}entity-collection operations
The entity-collection resource is exposed on the path /<entity-name-plural> (e.g. /invoices for the invoice entity type).
The following operations are available:
| Method | Content-Type | Description |
|---|---|---|
GET |
application/hal+json |
Read the entity-collection, applying the specified filters and pagination |
POST |
application/json |
Create a new entity-item. The response will be the created entity-item resource |
POST |
application/x-www-form-urlencoded |
Create a new entity-item with a form submission. The response will be the created entity-item resource |
POST |
multipart/form-data |
Create a new entity-item, and immediately upload content as well. The response will be the created entity-item resource |
Create an entity using JSON
curl -i https://$APP_ID.$REGION.contentgrid.cloud/invoices \
--json "{\"received\": \"2024-07-15\", \"total_amount\": 15.95, \"pay_before\": \"2024-08-14\"}" \
-H "Authorization: Bearer $TOKEN"
POST /invoices HTTP/1.1
Authorization: Bearer $TOKEN
Content-Type: application/json
{"received": "2024-07-15", "total_amount": 15.95, "pay_before": "2024-08-14"}HTTP/1.1 201 Created
Location: /invoices/3211be1d-1ed1-4850-8ea6-3fa3218031f6
Content-Type: application/prs.hal-forms+json
{
"id": "3211be1d-1ed1-4850-8ea6-3fa3218031f6",
"received": "2024-07-15",
"document": null,
"pay_before": "2024-08-14",
"total_amount": 15.95,
"_links": {
[...]
},
"_templates": {
[...]
}
}Create an entity with content using multipart/form-data
curl -i https://$APP_ID.$REGION.contentgrid.cloud/invoices \
-F received=2024-07-15 \
-F total_amount=15.95 \
-F pay_before=2024-08-14 \
-F document=@example-invoice.pdf \
-H "Authorization: Bearer $TOKEN"
POST /invoices HTTP/1.1
Authorization: Bearer $TOKEN
Content-Type: multipart/form-data;boundary="delimiter123"
--delimiter123
Content-Disposition: form-data; name="received"
2024-07-15
--delimiter123
Content-Disposition: form-data; name="total_amount"
15.95
--delimiter123
Content-Disposition: form-data; name="pay_before"
2024-08-14
--delimiter123
Content-Disposition: form-data; name="document"; filename="example-invoice.pdf"
....Omitted contents of file example-invoice.pdf....
--delimiter123--HTTP/1.1 201 Created
Location: /invoices/3211be1d-1ed1-4850-8ea6-3fa3218031f6
Content-Type: application/prs.hal-forms+json
{
"id": "3211be1d-1ed1-4850-8ea6-3fa3218031f6",
"received": "2024-07-15",
"document": {
"size": 123456,
"mimetype": "application/pdf",
"filename": "example-invoice.pdf"
},
"pay_before": "2024-08-14",
"total_amount": 15.95,
"_links": {
[...]
},
"_templates": {
[...]
}
}Collection query parameters
An entity-collection has 3 query parameters that control the collection itself:
| Query Parameter | Type | Description |
|---|---|---|
_size |
integer, 1-1000 or absent | Page size, the number of entity-item resources that will be returned on a single page |
_cursor |
string or absent | Cursor for the page to retrieve. Absent to retrieve the first page |
_sort |
string or absent | Sort the collection by an attribute. Parameter can be repeated multiple times to sort on multiple attributes |
Pagination
By default, every page contains 20 entity-items. This can be changed with the _size query parameter.
When there are multiple pages, the meta information will contain prev_cursor and/or next_cursor fields.
A previous or next page can be retrieved by setting the _cursor query parameter to the value in the prev_cursor or next_cursor field.
Note
A cursor is not a fancy page number.
- Cursors are opaque. A client should not parse or attempt to modify a cursor; they are only meaningful to the server.
- Cursors are unique for every entity-collection. They can not be reused in a different context or used with different filter parameters.
- Cursors are ephemeral. They should not be stored permanently to use at a later point in time, and they do not permanently identify a certain page
Example of navigating through pages with a cursor
curl -i https://$APP_ID.$REGION.contentgrid.cloud/invoices \
-H "Authorization: Bearer $TOKEN"
GET /invoices HTTP/1.1
Authorization: Bearer $TOKEN
HTTP/1.1 200 OK
Content-Type: application/prs.hal-forms+json
{
"_embedded": {
[...]
},
"page": {
"size": 20,
"next_cursor": "1wskufc1",
"total_items_estimate": 48,
"total_items_exact": 48
}
}prev_cursor appears, which can be used to navigate to the previous page
curl -i https://$APP_ID.$REGION.contentgrid.cloud/invoices?_cursor=1wskufc1 \
-H "Authorization: Bearer $TOKEN"
GET /invoices?_cursor=1wskufc1 HTTP/1.1
Authorization: Bearer $TOKEN
HTTP/1.1 200 OK
Content-Type: application/prs.hal-forms+json
{
"_embedded": {
[...]
},
"page": {
"size": 20,
"prev_cursor": "0dtcbvz0",
"next_cursor": "0qk2h5e2",
"total_items_estimate": 48,
"total_items_exact": 48
}
}Navigate again to the next page. Note that this is the final page, and next_cursor is absent, indicating that there are no further pages.
curl -i https://$APP_ID.$REGION.contentgrid.cloud/invoices?_cursor=0qk2h5e2 \
-H "Authorization: Bearer $TOKEN"
GET /invoices?_cursor=0qk2h5e2 HTTP/1.1
Authorization: Bearer $TOKEN
HTTP/1.1 200 OK
Content-Type: application/prs.hal-forms+json
{
"_embedded": {
[...]
},
"page": {
"size": 20,
"prev_cursor": "1wskufc1",
"total_items_estimate": 48,
"total_items_exact": 48
}
}Sorting
By default, the collection is not sorted. The collection can be sorted by using the _sort query parameter.
The _sort query parameter can be repeated multiple times to sort on multiple attributes.
The _sort value is composed of the attribute name, followed by ,asc or ,desc to sort ascending or descending.
Note that not all attributes support sorting. The OpenAPI spec lists the valid values for the _sort query parameter.
Example of collection sorting on multiple attributes
First sort ascending on received, then descending on total_amount
curl -i https://$APP_ID.$REGION.contentgrid.cloud/invoices?_sort=received,asc\&_sort=total_amount,desc \
-H "Authorization: Bearer $TOKEN"
GET /invoices?_sort=received,asc&_sort=total_amount,desc HTTP/1.1
Authorization: Bearer $TOKEN
Filtering
Search filters can be applied to the entity-collection. By default no filters are applied.
All filters are application-specific, and are mapped directly to query parameters. The OpenAPI spec lists all the valid filters as query parameters.
Note
Using a query parameter that is not a known search filter or one of the special query parameters will be ignored and have no effect.
Multiple search filters can be combined. Different search filters are AND’ed together; repeating the same search filter multiple times will perform an OR on the different values of that filter.
Example of collection filtering with multiple search filters
Show invoices with total_amount equal to 15.95
curl -i https://$APP_ID.$REGION.contentgrid.cloud/invoices?total_amount=15.95 \
-H "Authorization: Bearer $TOKEN"
GET /invoices?total_amount=15.95 HTTP/1.1
Authorization: Bearer $TOKEN
curl -i https://$APP_ID.$REGION.contentgrid.cloud/invoices?total_amount=19.95\&total_amount=123.4 \
-H "Authorization: Bearer $TOKEN"
GET /invoices?total_amount=19.95&total_amount=123.4 HTTP/1.1
Authorization: Bearer $TOKEN
curl -i https://$APP_ID.$REGION.contentgrid.cloud/invoices?total_amount=15.95\&pay_before=2024-08-14 \
-H "Authorization: Bearer $TOKEN"
GET /invoices?total_amount=15.95&pay_before=2024-08-14 HTTP/1.1
Authorization: Bearer $TOKEN
curl -i https://$APP_ID.$REGION.contentgrid.cloud/invoices?total_amount=15.95\&total_amount=123.4\&pay_before=2024-08-14 \
-H "Authorization: Bearer $TOKEN"
GET /invoices?total_amount=15.95&total_amount=123.4&pay_before=2024-08-14 HTTP/1.1
Authorization: Bearer $TOKEN
relation operations
An entity can have relations to a different entity. These are exposed on the path /<entity-name-plural>/{id}/<relation-name>. (e.g. /invoices/{id}/supplier for the invoice entity type and a relation supplier)
Depending on the relation type, the available operations and responses are different.
to-one relation operations
These operations are applicable to one-to-one and many-to-one relations.
| Method | Content-Type | Description |
|---|---|---|
GET |
N/A | Read the relation link. Redirects to the entity-item that the relation refers to |
PUT |
text/uri-list |
Update the relation link. Requires a single URL to the entity-item that the relation should refer to |
DELETE |
N/A | Remove the relation link. No entity-items are deleted, only the link between the two is severed |
Reading and updating a to-one relation
Initially, no supplier is linked to the invoice, and fetching the relation results in a 404 Not Found error.
curl -i https://$APP_ID.$REGION.contentgrid.cloud/invoices/$INVOICE_ID/supplier \
-H "Authorization: Bearer $TOKEN"
GET /invoices/$INVOICE_ID/supplier HTTP/1.1
Authorization: Bearer $TOKEN
HTTP/1.1 404 Not FoundSetting a relation requires sending the URL of the created entity-item in the body.
curl -i -X PUT https://$APP_ID.$REGION.contentgrid.cloud/invoices/$INVOICE_ID/supplier \
--data-binary "https://$APP_ID.$REGION.contentgrid.cloud/suppliers/$SUPPLIER_ID" \
-H 'Content-Type: text/uri-list' \
-H "Authorization: Bearer $TOKEN"
PUT /invoices/$INVOICE_ID/supplier HTTP/1.1
Authorization: Bearer $TOKEN
Content-Type: text/uri-list
https://$APP_ID.$REGION.contentgrid.cloud/suppliers/$SUPPLIER_IDHTTP/1.1 204 No ContentReading the relation afterwards will result in a redirect to the specific item that was linked.
curl -i https://$APP_ID.$REGION.contentgrid.cloud/invoices/$INVOICE_ID/supplier \
-H "Authorization: Bearer $TOKEN"
GET /invoices/$INVOICE_ID/supplier HTTP/1.1
Authorization: Bearer $TOKEN
HTTP/1.1 302 Found
Location: /suppliers/$SUPPLIER_IDto-many relation operations
These operations are applicable to one-to-many and many-to-many relations.
| Method | Content-Type | Description |
|---|---|---|
GET |
application/json |
Read the relation collection. Redirects to the entity-collection containing all entity-items that the relation refers to |
POST |
text/uri-list |
Adds entity-items to the relation. Accepts one or more URLs to the entity-items that should be added to the relation collection |
DELETE |
N/A | Clear the relation collection. No entity-items are deleted, only the relation collection is emptied. |
Reading and updating a to-many relation
In this example, we will add 2 invoices to a supplier.
curl -i -X POST https://$APP_ID.$REGION.contentgrid.cloud/suppliers/$SUPPLIER_ID/invoices \
--data-binary "https://$APP_ID.$REGION.contentgrid.cloud/invoices/$INVOICE_ID
https://$APP_ID.$REGION.contentgrid.cloud/invoices/$INVOICE2_ID" \
-H 'Content-Type: text/uri-list' \
-H "Authorization: Bearer $TOKEN"
POST /suppliers/$SUPPLIER_ID/invoices HTTP/1.1
Authorization: Bearer $TOKEN
Content-Type: text/uri-list
https://$APP_ID.$REGION.contentgrid.cloud/invoices/$INVOICE_ID
https://$APP_ID.$REGION.contentgrid.cloud/invoices/$INVOICE2_IDHTTP/1.1 204 No ContentReading the relation will result in a redirect to a collection containing all items that are linked. Note that the query parameter used in the redirect is subject to change and is not part of the public API.
curl -i https://$APP_ID.$REGION.contentgrid.cloud/suppliers/$SUPPLIER_ID/invoices \
-H "Authorization: Bearer $TOKEN"
GET /suppliers/$SUPPLIER_ID/invoices HTTP/1.1
Authorization: Bearer $TOKEN
HTTP/1.1 302 Found
Location: /invoices?_internal_supplier=$SUPPLIER_IDrelation-item operations
A to-many relation also has a way to reference an individual item inside the relation; the relation-item resource.
These are exposed on the path /<entity-name-plural>/{id}/<relation-name>/{itemId} (e.g. /suppliers/{id}/invoices/{itemId} for the supplier entity type and a relation invoices).
| Method | Description |
|---|---|
GET |
Read the relation collection item. Redirects to the entity-item if it is part of the relation collection |
DELETE |
Remove the relation collection item from the relation collection. No entity-items are deleted, only the link between the two is severed |
Removing an item from a to-many relation
This will remove a single entity-item from the relation
curl -i -X DELETE https://$APP_ID.$REGION.contentgrid.cloud/suppliers/$SUPPLIER_ID/invoices/$INVOICE_ID \
-H "Authorization: Bearer $TOKEN"
DELETE /suppliers/$SUPPLIER_ID/invoices/$INVOICE_ID HTTP/1.1
Authorization: Bearer $TOKEN
HTTP/1.1 204 No ContentAfter the entity-item is removed from the relations, further attempts to remove the same item will result in a 404 Not Found error
curl -i -X DELETE https://$APP_ID.$REGION.contentgrid.cloud/suppliers/$SUPPLIER_ID/invoices/$INVOICE_ID \
-H "Authorization: Bearer $TOKEN"
DELETE /suppliers/$SUPPLIER_ID/invoices/$INVOICE_ID HTTP/1.1
Authorization: Bearer $TOKEN
HTTP/1.1 404 Not Foundentity-content operations
An entity-content resource is exposed on the path /<entity-name-plural>/{id}/<attribute-name> (e.g. /invoices/{id}/document for the invoice entity type and a content attribute document). {id} is a placeholder for the actual ID of the entity-item.
The following operations are available:
| Method | Content-Type | Description |
|---|---|---|
GET |
any | Retrieve stored file. If no file is currently stored, responds with HTTP 404 Not Found |
PUT |
any | Overwrite file with contents of request body |
PUT |
multipart/form-data |
Overwrite file with contents of the file form-field |
DELETE |
N/A | Remove stored file |
For the GET and PUT with arbitrary Content-Type; the filename is provided in the Content-Disposition header.
If no filename is provided during content upload, the filename field of the content attribute will be set to null
Read and write content
Read content of an invoice with id $INVOICE_ID
curl -i https://$APP_ID.$REGION.contentgrid.cloud/invoices/$INVOICE_ID/document \
-H "Authorization: Bearer $TOKEN"
GET /invoices/$INVOICE_ID/document HTTP/1.1
Authorization: Bearer $TOKEN
HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Disposition: attachment;filename="example-invoice.pdf"
....Raw PDF body omitted....curl -i -X PUT https://$APP_ID.$REGION.contentgrid.cloud/invoices/$INVOICE_ID/document \
--data-binary "@example-invoice.pdf" \
-H 'Content-Disposition: attachment;filename="example-invoice.pdf"' \
-H 'Content-Type: application/pdf' \
-H "Authorization: Bearer $TOKEN"
PUT /invoices/$INVOICE_ID/document HTTP/1.1
Authorization: Bearer $TOKEN
Content-Disposition: attachment;filename="example-invoice.pdf"
Content-Type: application/pdf
....Omitted contents of file example-invoice.pdf....HTTP/1.1 204 No Contentcurl -i -X PUT https://$APP_ID.$REGION.contentgrid.cloud/invoices/$INVOICE_ID/document \
-F file=@example-invoice.pdf \
-H "Authorization: Bearer $TOKEN"
PUT /invoices/$INVOICE_ID/document HTTP/1.1
Authorization: Bearer $TOKEN
Content-Type: multipart/form-data;boundary="delimiter123"
--delimiter123
Content-Disposition: form-data; name="file"; filename="example-invoice.pdf"
....Omitted contents of file example-invoice.pdf....
--delimiter123--HTTP/1.1 204 No ContentRequest modifiers
The basic operations explained above can be extended with additional functionality. Additional functionality is layered on top of the basic operations using HTTP headers.
Conditional requests
Conditional requests allow to check a precondition before applying the request to the target resource. They are an implementation of RFC9110 Conditional Requests.
The primary usage of conditional requests is to prevent the “lost update” problem, where one system overwrites the changes of another system that made a write between the read and write of the first system.
Conditional requests can be used on the resources that have an ETag response header, which are these:
| Name | URL |
|---|---|
| entity-item | /<entity-name-plural>/{id} |
| to-one relation | /<entity-name-plural>/{id}/<relation-name> |
| entity-content | /<entity-name-plural>/{id}/<attribute-name> |
To perform conditional requests, a previously obtained ETag value has to be placed in the If-Match or If-None-Match headers. Note that the quotes are part of the ETag value.
The If-Modified-Since and If-Unmodified-Since headers are not supported, because no Last-Modified response header is present, and they are less precise.
Using a conditional request for updating
In this example, we’re going to move the pay_before date one day earlier.
curl -i -X GET https://$APP_ID.$REGION.contentgrid.cloud/invoices/$INVOICE_ID \
-H "Authorization: Bearer $TOKEN"
GET /invoices/$INVOICE_ID HTTP/1.1
Authorization: Bearer $TOKEN
HTTP/1.1 200 OK
ETag: "1e0k4j9"
Content-Type: application/hal+json
{
"id": "019be613-baa4-7644-9438-e252be3bbe84",
"received": "2024-07-15",
"document": {
"filename": "invoice.txt",
"length": 13,
"mimetype": "text/plain"
},
"pay_before": "2024-08-14",
"total_amount": 15.95,
"_links": {
[...]
}
}After retrieving the invoice response, we take note of the ETag header, and place if in the If-Match header for our next request.
Then we perform a PATCH request to update only the pay_before attribute.
To execute this example, you will need to change the If-Match header to the correct value yourself.
curl -i -X PATCH https://$APP_ID.$REGION.contentgrid.cloud/invoices/$INVOICE_ID \
--json "{\"pay_before\": \"2024-08-13\"}" \
-H 'If-Match: "1e0k4j9"' \
-H "Authorization: Bearer $TOKEN"
PATCH /invoices/$INVOICE_ID HTTP/1.1
Authorization: Bearer $TOKEN
If-Match: "1e0k4j9"
Content-Type: application/json
{"pay_before": "2024-08-13"}HTTP/1.1 204 No Content
ETag: "i4xcj6"The response to the modification also contains the new ETag value for the updated version of the object.
curl -i -X PATCH https://$APP_ID.$REGION.contentgrid.cloud/invoices/$INVOICE_ID \
--json "{\"pay_before\": \"2024-08-13\"}" \
-H 'If-Match: "1e0k4j9"' \
-H "Authorization: Bearer $TOKEN"
PATCH /invoices/$INVOICE_ID HTTP/1.1
Authorization: Bearer $TOKEN
If-Match: "1e0k4j9"
Content-Type: application/json
{"pay_before": "2024-08-13"}HTTP/1.1 412 Precondition Failed
Content-Type: application/problem+json
{
"type": "https://contentgrid.cloud/problems/unsatisfied-version",
"title": "Object has changed",
"detail": "Requested version constraint 'is any of [exactly '1e0k4j9']' can not be satisfied (actual version exactly '1r061qt')",
"status": 412,
"actual_version": "1r061qt"
}More details about the error response format can be found in the error handling section.
Range requests
Range requests allow retrieving a partial representation of the entity-content resource. They are an implementation of RFC9110 Range Requests.
Range requests are only supported on the entity-content resource (/<entity-name-plural>/{id}/<attribute-name>), as indicated by the Accept-Ranges header.
You usually don’t use range requests directly, but some tools that work with potentially large files (like PDF viewers or download managers) can make use of them.
Warning
When composing a file together from multiple parts, it is critical to check that the ETags of all parts are identical.
Otherwise, a concurrent change of the content will result in the composed file being corrupted.
Using a range request to retrieve a part of a resource
In this example, the first 4 bytes are fetched separately.
curl -i https://$APP_ID.$REGION.contentgrid.cloud/invoices/$INVOICE_ID/document \
-H 'Range: bytes=0-3' \
-H "Authorization: Bearer $TOKEN"
GET /invoices/$INVOICE_ID/document HTTP/1.1
Authorization: Bearer $TOKEN
Range: bytes=0-3
HTTP/1.1 206 Partial Content
Accept-Ranges: bytes
Content-Range: bytes 0-3/13
ETag: "8xhtyfikrvnts4izydc95vfcn"
Content-Length: 4
Content-Type: text/plain
dummAfter the initial fetch, If-Match is used to ensure that the rest of the same file is fetched.
curl -i https://$APP_ID.$REGION.contentgrid.cloud/invoices/$INVOICE_ID/document \
-H 'If-Match: "8xhtyfikrvnts4izydc95vfcn"' \
-H 'Range: bytes=4-' \
-H "Authorization: Bearer $TOKEN"
GET /invoices/$INVOICE_ID/document HTTP/1.1
Authorization: Bearer $TOKEN
If-Match: "8xhtyfikrvnts4izydc95vfcn"
Range: bytes=4-
HTTP/1.1 206 Partial Content
Accept-Ranges: bytes
Content-Range: bytes 4-12/13
ETag: "8xhtyfikrvnts4izydc95vfcn"
Content-Length: 9
Content-Type: text/plain
y-invoice