API Reference
This page is under construction.
Welcome to the Layer7 Solutions API reference. We provide an API for you to use for your own subreddit-specific applications or anything else you wish. Using our API you can manage your TheSentinelBot blacklist, fetch mod matrices, mod logs, and more.
Have a question or need help? Try asking in our subreddit at /r/Layer7
Overview
The web API takes the form https://layer7.solutions/api/v1/METHOD
.
For example, https://layer7.solutions/api/v1/identity
.
All methods must be called using HTTPS. The response will always be in JSON format. The properties within the response are defined in the documentation for the relevant method.
Errors
If an error occurred, there will be two properties: error
and
error_description
. The error code will remain constant for the given error type,
whereas the error_description is a human-readable description of the error and may change
at any time.
{ "error": "ERROR_CODE", "error_description": "Something happened", }
The HTTP status code will also be different from the usual 200. For example, if your request had invalid or missing parameters then the status code will be 400 Bad request, and if you attempt to make a request on a subreddit you don't mod then it'll be 403 Forbidden.
Authenticating
The api uses OAuth 2. If you are unsure of how to use OAuth 2, search for OAuth 2 tutorials.
Our OAuth2 server currently only enables these grant types: client_credentials, authorization_code, refresh_token
OAuth URLs | |
---|---|
Authorize URL | https://layer7.solutions/api/v1/authorize |
Access Token URL | https://layer7.solutions/api/v1/access_token |
To register an application click here.
API Usage Rules
Overall, our API rules aren't too strict. But if there is precedent we may make them more strict overtime. Any changes to this API will be announced on our subreddit.
- Authentication API clients must authenticate using OAuth 2
- Rate Limit: currently we do not have a rate limit, this is subject to change if it becomes a problem. So please use our API responsibly. You shouldn't really be going over 60 requests per minute.
-
User-Agent: the client's user-agent should be something unique and descriptive that identifies
your application.
- Do not lie about your user-agent. Such as masquerading as other bots or applications.
- Do not use our API for malicious purposes. We do reserve the right to refuse service to any user or subreddit mod team.
Quick guide on how to integrate with your PRAW bot or other Python applications
With Python 3, requests
library, and the client_credentials
grant type.
Or you could use a OAuth2 python library.
First click this link and register your OAuth2 application if you haven't done so already. Take note of the generated Consumer ID and Consumer Secret.
Then request an access token:
>>> import requests >>> import json >>> r = requests.post('https://layer7.solutions/api/v1/access_token', data = { 'grant_type': 'client_credentials', 'scope': 'identity tsbread' # space-delimited scope list }, auth = ( 'e0aaV-pQQ_vPpu', # Consumer ID 'f4fJPcr6UbpnBolBn_TI4HZZPKwQkYLvtMgvFiZ7oDEA0n5kDs' # Consumer Secret )) >>> r.status_code 200 >>> print(json.dumps(r.json(), indent=2)) { 'access_token': 'fc92463c2a1753ed1be23c84b0fd42496bbaf45f', 'expires_in': 3600, 'token_type': 'Bearer', 'scope': 'identity tsbread' }
And then add the Authorization: Bearer <ACCESS TOKEN HERE>
header
to your requests:
>>> r2 = requests.get('https://layer7.solutions/api/v1/videos/blacklist/reports', params = { 'type': 'channel_name', 'subject': 'funny videos', 'amount': 5 }, headers = { 'Authorization': r.json()['token_type'] + ' ' + r.json()['access_token'] }) >>> r2.status_code 200 >>> print(json.dumps(r2.json(), indent=2)) { "matter": [ { "subject": "funny videos", "type": "channel_name", "matter_id": "channel_name;funny videos" } ], "listing": [ { "id": 64925062, "removed": false, "action_utc": 1513598213.2133, "subreddit": "videos", "author": "ngochaivp91", "thing_id": "t3_7kkrmd", "thing_title": "Funny videos 2017!Secret of doing stupid actions - HD sex Dino 2017 #3", "thing_data": "", "thing_created": 1513598163, "permalink": "http://reddit.com/7kkrmd", "media_author": "Funny Videos", "media_channel_id": "UCh6EkQQCkxOX_aEIJs0Ftew", "media_link": "https://www.youtube.com/attribution_link?a=vQhiRShsXZc&u=%2Fwatch%3Fv%3DvdnT4kqmP0s%26feature%3Dshare", "media_platform_id": 1, "media_channel_url": null, "media_platform": "YouTube", }, { "id": 64526546, "removed": false, "action_utc": 1513412690.6086, "subreddit": "videos", "author": "Isadoscomedy", "thing_id": "t1_drbtfws", "thing_title": null, "thing_data": "Most funniest video https://youtu.be/PCnw7y_7x2k", "thing_created": 1513412664, "permalink": "http://reddit.com/comments/7k3eeu/-/drbtfws", "media_author": "Most Funny Videos Latest", "media_channel_id": "UCYytxrvf1C5TIN0Macafw4g", "media_link": "https://youtu.be/PCnw7y_7x2k", "media_platform_id": 1, "media_channel_url": null, "media_platform": "YouTube", }, { "id": 64525973, "removed": false, "action_utc": 1513412324.8388, "subreddit": "videos", "author": "Isadoscomedy", "thing_id": "t1_drbtb1e", "thing_title": null, "thing_data": "Are you interested in laughing out your sorrow? Then click here https://youtu.be/S6e1XJcRWVM", "thing_created": 1513412308, "permalink": "http://reddit.com/comments/7k1qia/-/drbtb1e", "media_author": "Most Funny Videos Latest", "media_channel_id": "UCYytxrvf1C5TIN0Macafw4g", "media_link": "https://youtu.be/S6e1XJcRWVM", "media_platform_id": 1, "media_channel_url": null, "media_platform": "YouTube", }, { "id": 64525902, "removed": false, "action_utc": 1513412272.9849, "subreddit": "videos", "author": "Isadoscomedy", "thing_id": "t1_drbta4n", "thing_title": null, "thing_data": "Are you interested in laughing out your sorrow? Then click here https://youtu.be/S6e1XJcRWVM", "thing_created": 1513412241, "permalink": "http://reddit.com/comments/7k3wwc/-/drbta4n", "media_author": "Most Funny Videos Latest", "media_channel_id": "UCYytxrvf1C5TIN0Macafw4g", "media_link": "https://youtu.be/S6e1XJcRWVM", "media_platform_id": 1, "media_channel_url": null, "media_platform": "YouTube", }, { "id": 64525799, "removed": false, "action_utc": 1513412193.3, "subreddit": "videos", "author": "Isadoscomedy", "thing_id": "t1_drbt981", "thing_title": null, "thing_data": "Are you interested in laughing out your sorrow? Then click here https://youtu.be/S6e1XJcRWVM", "thing_created": 1513412174, "permalink": "http://reddit.com/comments/7k28dr/-/drbt981", "media_author": "Most Funny Videos Latest", "media_channel_id": "UCYytxrvf1C5TIN0Macafw4g", "media_link": "https://youtu.be/S6e1XJcRWVM", "media_platform_id": 1, "media_channel_url": null, "media_platform": "YouTube", } ], "amount": 5, "offset": 0, "total": 1297 } >>>
And that's it! And don't forget about the 'expires_in': 3600
part of the
access_token
response. You'll have to fetch a new access token every hour.
Here's a list of all our scopes for ease of copying:
Subreddit Notation
Take note that wherever you see {subreddit}
, whether as part of the path or
as a query parameter value, you can use our
Subreddit Notation
However, wherever you see {srname}
allows only one subreddit.
API Methods // identity
GET:/identity
Returns the current user's username, a boolean value representing whether the user mods at least one subreddit, and some time information about the current user's activity on the layer7.solutions website.
Arguments
None
Example Response
{ "username": "kwwxis", "first_login": 1477958400, "last_login": 1510016101, "last_access": 1513878367 }
GET:/identity/subreddits[/{category}]
Returns the subreddits the current user mods in no particular order.
Arguments
category (optional)
Returns subreddits the current users mods that are in the given category.
Raises UNKNOWN_FIELD
error if unknown category.
detail (optional)
If true
, returns subreddit name to detail map rather
than an array of just subreddit names.
Example Response
[ "pokemon", "CrucibleSherpa", "DestinySherpa", "worldnews", "LifeProTips", "aww", ... ]
GET:/identity/websync_history
Gives a descending history of the current user's moderator history on subreddits that have TSB.
Arguments
limit (optional)
Limit results to a specific number. If this parameter is not present then the entire history will be returned.
Example Response
The moderator
property will always be the username of the
current user. The moderator who performed the action on the current user
is not available for this api method.
[ { "id": 6120, "type": "removemoderator", "subreddit": "Scholar", "moderator": "kwwxis", "new_state": null, "history_utc": 1512520179 }, { "id": 5009, "type": "setpermissions", "subreddit": "Fireteams", "moderator": "kwwxis", "new_state": "config,flair", "history_utc": 1506961057 }, { "id": 4991, "type": "setpermissions", "subreddit": "DestinySherpa", "moderator": "kwwxis", "new_state": "config,flair", "history_utc": 1506904167 }, { "id": 4990, "type": "setpermissions", "subreddit": "CrucibleSherpa", "moderator": "kwwxis", "new_state": "config,flair", "history_utc": 1506904108 }, { "id": 4811, "type": "acceptmoderatorinvite", "subreddit": "aww", "moderator": "kwwxis", "new_state": null, "history_utc": 1506199854 }, { "id": 4809, "type": "removemoderator", "subreddit": "aww", "moderator": "kwwxis", "new_state": null, "history_utc": 1506199854 }, ... ]
API Methods // srprefread or srprefedit
GET:/r/{srname}/settings
Returns the current subreddit settings.
Arguments
action (optional)
get
: get the value for a specific propertyset
: change a property's value. Requiressrprefedit
scope.- Not given: fetch the entire subreddit settings
property (optional)
The property that is the subject of the request.
Required only if the action
parameter is set.
Raises UNKNOWN_FIELD
error if unknown property
value (optional)
The new value. Required only if action
is set
.
Must be one of these values if to be interpreted as true:
t
, true
, 1
, yes
.
All other values will be interpreted as false.
Example Responses
No parameters:
{ "id": 694, "subreddit": "aww", "redditbot_name": "TheSentinel_8", "redditbot_permissions": "posts,flair", "sentinel_enabled": true, "modlog_enabled": true, "modmail_enabled": false, "botban_enabled": true, "domainblacklist_enabled": true, "dirtbag_enabled": true }
?action=get&property=sentinel_enabled
:
{ "property_key": "sentinel_enabled", "property_value": true }
?action=set&property=modmail_enabled&value=f
:
{ "property_key": "modmail_enabled", "property_new_value": false, "property_old_value": true }
API Methods // logsread
GET:/logs/view
Fetches a page from the user's subreddit moderation logs.
Arguments
query (required)
The filter query as a stringified JSON string. To grab a page with no filter, set this value
to empty string or {}
.
The format of this JSON string follows:
{ "tokens": [ // tokens (optional) { "label": "somelabel", // token label (required) "modifier": null, // token modifier (optional, default:null) "values": [ // token values (at least 1 value is required) "somevalue" ] } ] }
The query in the following example will return log entries for sticky
and
removelink
actions in /r/DestinyTheGame and /r/videos.
{ "tokens": [ { "label": "in", "values": [ "destinythegame", "videos" ] }, { "label": "action", "values":[ "removelink", "sticky" ] } ] }
Here is a list of valid labels and modifiers:
-
label: in
Multiple values: allowed
Use this token label to limit your query to specific subreddit(s)
-
label: after
Multiple values: no
Use this label to limit your query to actions preformed after this timestamp. You can use this in conjunction with
before
if you want a specific range. -
label: before
Multiple values: no
Use this label to limit your query to actions preformed before this timestamp. You can use this in conjunction with
after
if you want a specific range. -
label: date
Multiple values: no
Use this label to limit your query to actions between the given timestamp and
timestamp + 86400
-
label: mod
Multiple values: allowed
Use this label to limit your query to a specific set of moderator(s). Do not include the "/u/", just the moderator username.
-
label: action
Multiple values: allowed
Use this label to limit your query to a specific set of mod action types. See this page for a list of valid action types
-
label: reason
Multiple values: no
Search for mod actions whose reason includes the given string in it's reason. The modifier used if no modifier specified is
includes
-
mod: includes-word
Search for reasons containing the given word.
-
mod: includes
Search for reasons containing the given string.
-
mod: starts-with
Search for reasons starting with the given string.
-
mod: ends-with
Search for reasons ending with the given string.
-
mod: full-exact
Search for reasons that exactly match the given string.
-
mod: full-text
Search for reasons that exactly match the given string, ignoring leading and trailing whitespace.
-
mod: regex
Search for reasons that match the given regex.
-
mod: shorter-than
Search for reasons whose length is shorter than the given number in characters.
-
mod: longer-than
Search for reasons whose length is longer than the given number in characters.
You can only include one modifier per token item. But you can use multiple token items. For example, this query will search for reasons longer than 5 characters that also contain "flair":
{ "tokens": [ { "label": "reason", "modifier": "longer-than", "values": [ "5" ] }, { "label": "reason", "values": [ "flair" ] } ] }
-
-
label: author
Multiple values: allowed
Limit your query to actions whose subject user is in the given set of authors. Do not include the "/u/", just the subject username.
-
label: thingid
Multiple values: allowed
Limit your query to actions whose thing ID is in the given set of thing IDs. The thing id should include the
t#_
prefix.
before (optional)
Used for pagination. If this argument is present, fetching will start before the entry with the ID
that matches the value of this argument. Not inclusive of the entry with the ID.
Use before
when going back a page.
after (optional)
Used for pagination. If this argument is present, fetching will start after the entry with the ID
that matches the value of this argument. Not inclusive of the entry with the ID.
Use after
when going forward a page.
If both before
and after
are present, after
will be ignored
and before
will be used.
amount (optional)
The amount of items per page. Max is 100. Default is 25.
Example Response
{ "listing": { { "id": 1517333, // the id to use forbefore
andafter
"thingid": "t3_5pegdn", "mod": "Destiny_Flair_Bot", "author": "BladedAbyss2551", "action": "removelink", "reason": "remove", "permalink": "/r/DestinyTheGame/comments/5pegdn/wrath_of_the_machine_hard_mode_question/", "timestamp": 1485050543, "human_timing": "3 minutes ago", "subreddit": "DestinyTheGame", "modactionid": "ModAction_d090c95c-e046-11e6-9a0a-0e5f443b9416", "thing_title": "Wrath of The Machine Hard Mode Question..." }, { "id": 1517332, "thingid": "t3_5peh16", "mod": "CodeWord_Dirtbag", "author": "SeekonlyJoy", "action": "removelink", "reason": "remove", "permalink": "/r/videos/comments/5peh16/abrahamhicks_avoiding_your_thoughts_esther_hicks/", "timestamp": 1485050489, "human_timing": "4 minutes ago", "subreddit": "videos", "modactionid": "ModAction_b0499a0c-e046-11e6-98fc-0ece270f97e6", "thing_title": "#AbrahamHicks ~ Avoiding your #Thoughts ♥ Esther Hicks #LawofAttraction Best Daily Videos Workshop" }, ... skipping to last item ... { "id": 1517267, "thingid": "t3_5pecaj", "mod": "AutoModerator", "author": "turcois", "action": "removelink", "reason": "[C11.1] Political - Bernie", "permalink": "/r/videos/comments/5pecaj/no_i_will_not_yield/", "timestamp": 1485048882, "human_timing": "30 minutes ago", "subreddit": "videos", "modactionid": "ModAction_f2ccc8c6-e042-11e6-8778-0e18eb2eb5c7", "thing_title": "\"No, I will not yield!\"" } }, "datainfo": { // contains some metadata about 'listing' "sr_count": { // map of # of occurences for each subreddit in 'listing' "DestinyTheGame": 3, "videos": 22 }, "amount": 25, // same as 'amount' received "before": null, // the id of the first item in 'listing' (will be null if at first page) "after": 1517267, // the id of the last item in 'listing' } }
The before
and after
properties in datainfo
are not
copies of the parameters received by the request, but rather the before
and
after
values you should use to traverse to the previous or next page respectively.
If before
is null, then that means there is no previous page.
Errors
INVALID_QUERY