Skip to content

API Entry ​

Compatibility ​

  • ExpressionEngine 7.3+ (v10). For older versions of ExpressionEngine see the installation page.

Installation ​

The Entry API comes natively with the Webservice module.

Errors ​

An error has "success": false with the message, and an HTTP status:

StatusWhen
400The request is not complete, e.g. no entry_id or search, no search param, a search on an unknown field, a search that could not be executed, a search that returns more than one entry without force, or an update with a search without a filter that selects entries
403No permission for the channel, the entry or the author (member_id)
404The channel or the entry is not found, also when a search finds nothing
422A field is missing or invalid, e.g. a required field, an invalid date or an error of a fieldtype

The errors of the module itself (credentials, permissions of the API, rate limiting) are on the default parameters and rate limiting pages.


Methods ​

POST /index.php/webservice/entry — Create Entry ​

Create a new entry in a channel.


Request Parameters ​

ParameterTypeRequiredDescription
channel_namestringRequiredThe name of the channel where the entry must be inserted
titlestringRequiredThe title for the entry
url_titlestringOptionalThe url title, default made from the title
statusstringOptionalThe status of the entry, default the default status of the channel
allow_commentsbooleanOptionalAllow comments? Default the setting of the channel
stickybooleanOptionalIs the entry sticky?
entry_date, expiration_date, comment_expiration_dateinteger / stringOptionalA Unix timestamp or a date, the entry_date defaults to now
custom_fieldsmixedOptionalAny custom fields can be added, by their short name
structure, seo_lite, publisher_lang_id, publisher_statusmixedOptionalThe data of these add-ons, see Compatible add-ons
categoryarray / stringOptionalThe category IDs, an array or a pipe or comma separated string: 1|2|3. Only the categories of the category groups of the channel. Replaces the default category of the channel
member_idintegerOptionalMember ID, otherwise defaults to the logged-in user
site_idintegerOptionalDefault 1, required when Strict site_id is on in the settings

Headers ​

HeaderValue
Content-Typeapplication/json

Request Example ​

php
$client = new \GuzzleHttp\Client();

$request = new \GuzzleHttp\Psr7\Request(
    'POST',
    'https://your-domain.com/index.php/webservice/entry',
    ['Content-Type' => 'application/json'],
    json_encode([
        'auth' => [
            'session_id' => 'fa78db6b673b83c211e8cc7153528e9087f62de0',
        ],
        'data' => [
            'channel_name'   => 'news_channel',
            'title'          => 'Test entry',
            'status'         => 'closed',
            'sticky'         => 'y',
            'allow_comments' => 'n',
            'news_body'      => 'This is a full body text',
            'news_extended'  => 'This is some small text',
            'category'       => '1|2|3|4',
            'custom_file_field' => [
                'filedata' => base64_encode(file_get_contents('path_to_image.jpg')),
                'filename' => 'filename.jpg',
                'dir_id'   => 6,
            ],
        ],
    ])
);

$response = $client->send($request, ['timeout' => 2]);

Response — 201 Created ​

json
{
    "success": true,
    "message": "Created successfully",
    "metadata": {
        "id": 42
    }
}

Response Fields ​

FieldTypeDescription
successbooleantrue when the entry was created successfully
messagestringHuman readable status message
metadata.idintegerThe ID of the newly created entry

GET /index.php/webservice/entry — Search / Read Entry ​

Search or retrieve entries from a channel.

Note: the order of the request parameters will be the order of the query.


Request Parameters ​

ParameterTypeRequiredDescription
entry_idintegerOptionalFetch a single entry by ID
channel (or channel_name)stringOptionalChannel name, a contains search: use =news for an exact match
channel_idintegerOptionalSearch by Channel ID
url_titlestringOptionalURL title, a contains search: use =my-title for an exact match
statusstringOptionalFilter by entry status. On a public endpoint a guest only gets open entries, a member also the other statuses of its assigned channels
limitintegerOptionalMaximum number of results (used with offset), default 99
offsetintegerOptionalResult offset (used with limit)
orderbystringOptionalSort results by this column or custom field, default entry_date
sortstringOptionalSort direction (asc or desc), default desc
start_onstringOptionalFilter entries from this date
stop_beforestringOptionalFilter entries before this date
show_expiredbooleanOptionaltrue also returns the expired entries, false hides them. Default the setting Show expired entries in the settings
search_allstringOptionalSearch in the title and all custom fields. Every word must be in one field and words shorter than 3 characters are skipped; without any other word the search is ignored. "two words" searches for the phrase, -word excludes a word. Combined with AND with the other parameters
grid_field[col_name] / matrix_field[cell_name]stringOptionalSearch in a grid/matrix column, see Search in Grid/Matrix cells
cat:[field_name]stringOptionalSearch on category fields (cat_id, group_id, cat_name, cat_url_title, or a custom field)
includestringOptionalInclude extra data, pipe separated: channel|categories|author|parents|structure, see below
returnstringOptionalReturn only the metadata, with an empty data: data[return]=meta

Headers ​

HeaderValue
Content-Typeapplication/json

Request Example ​

GET /index.php/webservice/entry?auth[session_id]=fa78db6b673b83c211e8cc7153528e9087f62de0&data[site_id]=1&data[entry_id]=43
php
$client = new \GuzzleHttp\Client();

$response = $client->get('https://your-domain.com/index.php/webservice/entry', [
    'query' => [
        'auth' => [
            'session_id' => 'fa78db6b673b83c211e8cc7153528e9087f62de0',
        ],
        'data' => [
            'site_id'  => 1,
            'entry_id' => 43,
        ],
    ],
    'timeout' => 2,
]);

Response — 200 OK ​

json
{
    "success": true,
    "message": "Successfully read",
    "metadata": {
        "id": "43",
        "limit": 99,
        "offset": 0,
        "total_results": 1,
        "absolute_results": 1
    },
    "data": [
        {
            "entry_id": 43,
            "title": "My Entry",
            "status": "open",
            "channel_id": 1
        }
    ]
}

When nothing is found, the response is a 404 with {"success": false, "message": "No Entry found"}.

Response Fields ​

FieldTypeDescription
successbooleantrue when the request succeeded
messagestringHuman readable status message
metadata.idstringThe IDs of the returned entries, pipe separated
metadata.limit, metadata.offsetintegerThe paging of the request
metadata.total_resultsintegerThe number of returned entries
metadata.absolute_resultsintegerThe number of matching entries, without the limit
data[]arrayArray of matching entry objects
data[].entry_idintegerThe entry ID
data[].titlestringThe entry title
data[].statusstringThe entry status

The ip_address is only returned to a member with the permission Access members. For everyone else a search or orderby on it is ignored. Every entry has all its columns and fields, also when the value is empty (0, "" or false), e.g. view_count_one: 0 or sticky: false. Before v10.0.0 empty values were left out (Breaking change).

Include ​

IncludeDescription
channelThe channel of the entry
categories (or category)The categories of the entry
author (or member)The member_id, username and screen_name of the author, returned as both author and member. The email only for the author itself or a member with the permission Access members
parentsThe entries that relate to this entry with a relationship field (also in a grid): entry_id, title, url_title, channel_id, status and the field_id. Only the entries of the channels the member has access to, without closed entries. Available from v10.0.0, before it was the Parent Relationship extension
structureThe Structure page of the entry: type (page or listing), uri, url, parent_id, parent_uri, template_id, hidden and listing_channel_id, or null when the entry has no page. Needs the Structure add-on. Available from v10.0.0, before it was the Structure extension
bash
curl -G 'https://your-domain.com/index.php/webservice/entry' \
  -H 'Authorization: Bearer <shortkey>' \
  --data-urlencode 'data[entry_id]=12' \
  --data-urlencode 'data[include]=parents|structure'

Search Mechanism ​

Basic Operators ​
TypeOperatorExample
Contains(empty)data[body]=test
Contains with wildcard(empty)data[body]=~test → results in %test%
Contains NOT(empty)data[body]=not test
Exact matching=data[body]==test
Exact NOT matchingnot =data[body]=not =test
Numeric matching< > <= >=data[body]=>10
Empty fieldIS_EMPTYdata[body]=IS_EMPTY
Not empty fieldIS_EMPTYdata[body]=not IS_EMPTY

A field with _id in its name is an exact match without an operator. A value with , or | is always split into multiple values.

An entry without a value for the field, e.g. of a channel without that field, counts as empty: it matches not test, not =test and IS_EMPTY. Combine them with channel to search in one channel.

OR / AND ​

By default the query is built with AND. To switch to OR, add or before the value:

data[title]=or john
Multiple Values ​

Use a pipe | or comma , to match multiple values (results in an OR query). The values are a group, combined with AND with the other fields:

data[title]=test|john
sql
title LIKE '%test%' OR title LIKE '%john%'

Use =test|=john for an exact match.

Groups ​

Group conditions like you would in SQL: (field LIKE '%4%' OR field LIKE '%5%') AND (field LIKE '%2%' OR field LIKE '%3%')

The group name can be anything, but must be unique per group.

data[group_one][group_and][][title]=test|john&data[group_two][group_and][][title]=willem|doe
sql
(title LIKE '%test%' OR title LIKE '%john%') AND (title LIKE '%willem%' OR title LIKE '%doe%')

Use group_or instead of group_and to combine a group with OR with the groups before it.


PUT /index.php/webservice/entry — Update Entry ​

Update an existing entry by entry ID or search parameters.


Request Parameters ​

ParameterTypeRequiredDescription
entry_idintegerRequired*The entry ID to update
search[]arrayRequired*Identify the entry via search (see Search Mechanism)
titlestringOptionalThe title for the entry
url_titlestringOptionalThe url title
statusstringOptionalThe status of the entry
allow_commentsbooleanOptionalAllow comments?
stickybooleanOptionalIs the entry sticky?
entry_date, edit_dateinteger / stringOptionalA Unix timestamp or a date. Without an edit_date it is set to now
expiration_date, comment_expiration_dateinteger / stringOptionalA Unix timestamp or a date. When not given, the date stays the same; an empty value or 0 clears it
custom_fieldsmixedOptionalAny custom field(s). A field that is not given stays the same, a required field cannot be emptied (422)
categoryarray / stringOptionalThe category IDs, an array or a pipe or comma separated string: 1|2|3. Only the categories of the category groups of the channel. Replaces the categories of the entry, empty removes them
member_idintegerOptionalThe author, otherwise the author stays the same

*Either entry_id or search[] is required.

Headers ​

HeaderValue
Content-Typeapplication/json

Request Example — by Entry ID ​

PUT /index.php/webservice/entry?auth[session_id]=fa78db6b673b83c211e8cc7153528e9087f62de0&data[site_id]=1&data[entry_id]=3988&data[title]=updated&data[status]=open
php
$client = new \GuzzleHttp\Client();

$request = new \GuzzleHttp\Psr7\Request(
    'PUT',
    'https://your-domain.com/index.php/webservice/entry',
    ['Content-Type' => 'application/json'],
    json_encode([
        'auth' => [
            'session_id' => 'fa78db6b673b83c211e8cc7153528e9087f62de0',
        ],
        'data' => [
            'site_id'        => 1,
            'entry_id'       => 3988,
            'title'          => 'Updated title',
            'status'         => 'open',
            'sticky'         => 'y',
            'allow_comments' => 'n',
            'news_body'      => 'This is a full body text',
            'news_extended'  => 'This is some small text',
        ],
    ])
);

$response = $client->send($request, ['timeout' => 2]);

⚠️ The webservice returns an error if multiple entries match. Use force to update the first match. Updating by entry_id is safer but requires an extra request to look up the ID first. The search needs a filter that selects entries, otherwise the update returns a 400, also with force. Parameters like limit, orderby and show_expired, a search_all without a usable word and values like , or ~ do not count.

php
$request = new \GuzzleHttp\Psr7\Request(
    'PUT',
    'https://your-domain.com/index.php/webservice/entry',
    ['Content-Type' => 'application/json'],
    json_encode([
        'auth' => [
            'session_id' => 'fa78db6b673b83c211e8cc7153528e9087f62de0',
        ],
        'data' => [
            'search' => [
                'custom_field' => '=test', // = sign is for explicit matching
                'force'        => true,    // update first match if multiple found
            ],
            'title'  => 'Updated title',
            'status' => 'Closed',
        ],
    ])
);

Response — 200 OK ​

json
{
    "success": true,
    "message": "Successfully updated",
    "metadata": {
        "id": 3988
    }
}

📤 Response Fields ​

FieldTypeDescription
successbooleantrue when the entry was updated successfully
messagestringHuman readable status message
metadata.idintegerThe ID of the updated entry

DELETE /index.php/webservice/entry — Delete Entry ​

Delete an entry by its entry ID.


Request Parameters ​

ParameterTypeRequiredDescription
entry_idintegerRequiredThe entry ID to delete

Headers ​

HeaderValue
Content-Typeapplication/json

Request Example ​

DELETE /index.php/webservice/entry?auth[username]=person@gmail.com&auth[password]=1232&data[site_id]=1&data[entry_id]=3983
php
$client = new \GuzzleHttp\Client();

$request = new \GuzzleHttp\Psr7\Request(
    'DELETE',
    'https://your-domain.com/index.php/webservice/entry',
    ['Content-Type' => 'application/json'],
    json_encode([
        'auth' => [
            'username' => 'person@gmail.com',
            'password' => '1232',
        ],
        'data' => [
            'site_id'  => 1,
            'entry_id' => 3983,
        ],
    ])
);

$response = $client->send($request, ['timeout' => 2]);

Response — 200 OK ​

json
{
    "success": true,
    "message": "Successfully deleted",
    "metadata": {
        "id": 3983
    }
}

Response Fields ​

FieldTypeDescription
successbooleantrue when the entry was deleted successfully
messagestringHuman readable status message
metadata.idintegerThe ID of the deleted entry

POST /index.php/webservice/entry/view_count — Count a view ​

Available from v10.0.0, before it was the separate View Count API

Adds one view to a view count of an entry, like track_views of the channel module. For sites that show their entries without the templates of ExpressionEngine (e.g. a headless front-end). The counts are read with the view_count_one to view_count_four of an entry.

ParameterTypeRequiredDescription
entry_idintegerRequiredThe entry
counterintegerOptional1 (default) to 4: the view_count_one to view_count_four column
  • Enable entry view tracking must be on in the channel settings of ExpressionEngine, otherwise a 403 is returned.
  • Only an entry that can be seen: not closed, not in the future and not expired, otherwise a 404.
  • The count can only go up by one per call, to count the views of visitors make the endpoint public and use the rate limiting.
json
{"success": true, "message": "View counted", "metadata": {"id": 12}, "data": [{"entry_id": 12, "view_count_one": 43}]}

The hook webservice_increment_view_count_end is called with the entry_id and the counter.

Hooks ​

Every hook is called as webservice_<name> and as reinos_webservice_<name>, e.g. webservice_create_entry_end and reinos_webservice_create_entry_end.

webservice_create_entry_start ​

(added in v3.2.1)

$entry_data = ee()->extensions->call('webservice_create_entry_start', $entry_data);

webservice_create_entry_end ​

(added in v2.2)

ee()->extensions->call('webservice_create_entry_end', $entry_id, $post_data);

webservice_read_entry_start ​

(added in v3.2.1)

$entry_data = ee()->extensions->call('webservice_read_entry_start', $entry_data);

webservice_create_entry ​

(added in v4.4.2)
Runs after the validation, with the entry model before it is saved

$entry = ee()->extensions->call('webservice_create_entry', $entry, $post_data);

webservice_read_entry_end ​

(added in v2.2)

$entry_data = ee()->extensions->call('webservice_read_entry_end', $entry_data, $post_data);

webservice_update_entry_start ​

(added in v3.2.1)

$entry_data = ee()->extensions->call('webservice_update_entry_start', $entry_data);

webservice_update_entry ​

(added in v4.4.2)
Runs after the validation, with the entry model before it is saved

$entry = ee()->extensions->call('webservice_update_entry', $entry, $post_data);

webservice_update_entry_end ​

(added in v2.2)

With the saved entry model

ee()->extensions->call('webservice_update_entry_end', $entry, $post_data);

webservice_delete_entry_start ​

(added in v3.2.1)

$entry_data = ee()->extensions->call('webservice_delete_entry_start', $entry_data);

webservice_delete_entry_end ​

(added in v2.2)

ee()->extensions->call('webservice_delete_entry_end', $entry_id);

(added in v4.0)
With this hook you can extend the search by your own. Just make sure the hook will return an array of entry_ids.

$entry_ids = ee()->extensions->call('webservice_modify_search', $values, $fields);

webservice_search_entry_per_entry ​

(added in v3.2)

$entry_data = ee()->extensions->call('webservice_search_entry_per_entry', $entry_data, $fields, $post_data);

webservice_read_entry_per_entry ​

(added in v3.2)
Called per entry, with the same data as webservice_search_entry_per_entry

$entry_data = ee()->extensions->call('webservice_read_entry_per_entry', $entry_data, $fields, $post_data);

webservice_search_entry_start ​

(added in v3.2.1)

$entry_data = ee()->extensions->call('webservice_search_entry_start', $entry_data);

webservice_search_entry_end ​

(added in v2.2)

$entry_data = ee()->extensions->call('webservice_search_entry_end', $entry_data, $post_data);

webservice_entry_row ​

(added in v3.5)
Will be called per entry when reading entries, after webservice_read_entry_per_entry

$entry_data = ee()->extensions->call('webservice_entry_row', $entry_data, $fields, $post_data);

webservice_post_entry_row ​

(added in v6.1.0)
Called per entry with the entry model, before the fields are processed

$entry = ee()->extensions->call('webservice_post_entry_row', $entry, $fields, $post_data);

webservice_read_entry_matrix ​

(added in v4.0)

$value = ee()->extensions->call('webservice_read_entry_matrix', $value, $col_settings, $row_id);

webservice_read_entry_grid ​

(added in v4.0)

$value = ee()->extensions->call('webservice_read_entry_grid', $value, $col_settings, $row_id);