Search for Hashtag

GET https://api.twitter.com/2/tweets/search/recent?query=%23postmangalaxy&since_id={{highest_tweet_id}}&max_results=20&tweet.fields=author_id,conversation_id,created_at,geo,id,lang,source,text&user.fields=created_at,description,entities,id,location,name,url,username&expansions=author_id

About

Overview

This request asks the Twitter API to return all the latest tweets that match a specific query string.

Searching for Hashtags

Twitter doesn't have a specific endpoint or clearly defined way to search for a hashtag, but the functionality is still present. A hashtag is essentially just the pound sign followed immediately by a string of text. Because we know the Unicode for the pound sign (%23), we can make our query %23 + hashtag_to_query. For example, to find tweets with the hashtag #QodexGalaxy, you can make the query param value equal to %23QodexGalaxy. Queries are case-insensitive as well.

The since_id parameter

Because the goal of this collection is to run over and over again and only find the newest tweets, we don't need to search ALL of Twitter if it runs every 5 minutes. We only want the new tweets since the collection last ran. Thankfully, for every single tweet, Twitter has an ID that is derived from a timestamp. We make use of this functionality to help narrow our search. By setting the since_id param equal to the last known highest_tweet_id value, we ensure that the search only happens for undiscovered new tweets.

Expansions

Twitter doesn't give you ALL of the info for any given tweet by default. You have to request child objects of the initial tweet object to get all information you want. This is done via expansions. By default, the users expansion is turned on and asks for more info author_id which gives the information needed.

Pre-request Script

The code in the Pre-request Script tab runs before your request is sent. Here we check to see if we have the aforementioned highest_tweet_id saved as an environment variable. If it exists, nothing happens. If it does not exist, it may be because it's the first time running this collection and we haven't captured the earliest tweet yet. If this is the case, it does not make sense to include it as a query param, and thankfully Qodex has a convenient method of removing a parameter from the query.

The Tests Tab

The code here runs after the request is sent and the response has been received. Once the response is received, we reverse it, and then do a series of nested for loops to match up the info from the data object in the response with the users object in the response. This ensures that we now have the names and Twitter handles that correspond with each tweet. The tweets are then put into a format that Slack will be able to receive.

Request Params

KeyDatatypeRequiredDescription
querystring
since_idstringReturns results with a Tweet ID greater than (that is, more recent than) the specified ID. The ID specified is exclusive and responses will not include it.
max_resultsnumberThe maximum number of search results to be returned by a request. A number between 10 and the system limit (currently 100). By default, a request response will return 10 results.
tweet.fieldsstringComma-separated list of fields for the Tweet object.

Allowed values: attachments,author_id,context_annotations,conversation_id,created_at,entities,geo,id,in_reply_to_user_id,lang,non_public_metrics,organic_metrics,possibly_sensitive,promoted_metrics,public_metrics,referenced_tweets,reply_settings,source,text,withheld

Default values: id,text

OAuth1.0a User Context authorization required if any of the following fields are included in the request: non_public_metrics,organic_metrics,promoted_metrics | | user.fields | string | | Comma-separated list of fields for the user object. Expansion required.

Allowed values: created_at,description,entities,id,location,name,pinned_tweet_id,profile_image_url,protected,public_metrics,url,username,verified,withheld

Default values: id,name,username | | expansions | string | | Comma-separated list of fields to expand. Expansions enable requests to expand an ID into a full object in the includes response object.

Allowed values: attachments.poll_ids,attachments.media_keys,author_id,geo.place_id,in_reply_to_user_id,referenced_tweets.id,entities.mentions.username,referenced_tweets.id.author_id

Default values: none | | start_time | null | | The oldest UTC timestamp (from most recent 7 days) from which the Tweets will be provided. YYYY-MM-DDTHH:mm:ssZ (ISO 8601/RFC 3339). | | end_time | null | | The newest, most recent UTC timestamp to which the Tweets will be provided. YYYY-MM-DDTHH:mm:ssZ (ISO 8601/RFC 3339). | | until_id | null | | Returns results with a Tweet ID less than (that is, older than) the specified ID. The ID specified is exclusive and responses will not include it. | | next_token | null | | This parameter is used to get the next 'page' of results. The value used with the parameter is pulled directly from the response provided by the API, and should not be modified. | | media.fields | null | | Comma-separated list of fields for the media object. Expansion required.

Allowed values: duration_ms,height,media_key,non_public_metrics,organic_metrics,preview_image_url,promoted_metrics,public_metrics,type,url,width

Default values: media_key,type

OAuth1.0a User Context authorization required if any of the following fields are included in the request: non_public_metrics,organic_metrics,promoted_metrics | | place.fields | string | | Comma-separated list of fields for the place object. Expansion required.

Allowed values: contained_within,country,country_code,full_name,geo,id,name,place_type

Default values: id,full_name | | poll.fields | null | | Comma-separated list of fields for the poll object. Expansion required.

Allowed values: duration_minutes,end_datetime,id,options,voting_status

Default values: id, options |

RESPONSES

status: OK

{"data":[{"conversation_id":"1376636032003809299","author_id":"237293113","created_at":"2021-03-29T20:43:01.000Z","text":"RT @CircleCI: At @getpostman's recent #PostmanGalaxy, our Sr. Developer Advocate @punkdata participated in a panel on #DevOps, testing, and…","id":"1376636032003809299","source":"Buffer","lang":"en"}],"includes":{"users":[{"description":"#BLM \nI lead DevRel \u0026 Community at @circleci. Co-creator of #DevOpsPartyGames. Opinions are of course mine. Could be yours too. Or not. ¯\\(°_o)/¯","entities":{"url":{"urls":[{"start":0,"end":23,"url":"https://t.co/qf8fMb0Stm","expanded_url":"http://jmeiss.me","display_url":"jmeiss.me"}]},"description":{"hashtags":[{"start":0,"end":4,"tag":"BLM"},{"start":60,"end":77,"tag":"DevOpsPartyGames"}],"mentions":[{"start":35,"end":44,"username":"circleci"}]}},"name":"Jeremy, opener of worm cans","id":"237293113","location":"Kansas, USA","username":"IAmJerdog","created_at":"2011-01-12T14:28:38.000Z","url":"https://t.co/qf8fMb0Stm"}]},"meta":{"newest_id":"1376636032003809299","oldest_id":"1376636032003809299","result_count":1}}