Authentication
Meetup uses access tokens to authenticate GraphQL requests. If you do not have a token or if your token is expired, please go to OAuth2 Server Flow to create or manage your tokens.
To authenticate the requests, set the Authorization HTTP header in your requests.
Header | Value |
---|---|
Authorization | Bearer {YOUR_TOKEN} |
To verify that your token is working, run the following command in the terminal:
query='query { self { id name } }'
curl -X POST https://api.meetup.com/gql \
-H 'Authorization: Bearer {YOUR_TOKEN}' \
-H 'Content-Type: application/json' \
-d @- <<EOF
{"query": "$query"}
EOF
You should see a response similar to the example below if your token works correctly. If not, please go to OAuth2 Server Flow to create or refresh your token.
{
"data":{
"self":{
"id":1234,
"name":"Cool Developer"
}
}
}
Querying with GraphQL
GraphQL queries return JSON with only the fields you specify. For example, the following invokes the event query with the eventId as an argument. The query returns the title, description, and date from an event.
Example: Basic query
Query
query {
event(id: "276754274") {
title
description
dateTime
}
}
Response
{
"data": {
"event": {
"title": "API test",
"description": "API test description",
"dateTime": "2021-03-15T09:52:53+09:00"
}
}
}
Example: Variables
Variables simplify GraphQL queries and mutations by letting you pass data like you do for arguments to a function. Variables begin with $ and are defined in JSON format.
Basic example with variables
query ($eventId: ID) {
event(id: $eventId) {
title
description
dateTime
}
}
Variables
{ "eventId": "276754274" }
Equivalent curl command
query='query($eventId: ID) {
event(id: $eventId) {
title
description
dateTime
}
}
'
variables='{
"eventId": "276754274"
}'
query="$(echo $query)"
curl -X POST https://api.meetup.com/gql \
-H 'Authorization: Bearer {YOUR_TOKEN}' \
-H 'Content-Type: application/json' \
-d @- <<EOF
{"query": "$query", "variables": "$variables"}
EOF
Example: Pagination
Retrieving large collections of data takes a long time and is resource intensive. Because of this, we recommend using pagination. Pagination is the process of dividing the records in results into smaller sets or pages. Meetup GraphQL uses cursor-based pagination.
Cursor-based pagination works by returning an identifier or cursor to a specific record in the dataset. Meetup GraphQL uses the endCursor field in the pageInfo object as the reference to the last record in the page. On subsequent requests, passing along the endCursor value and size as arguments tells GraphQL to return results after the given cursor.
First, let’s get the first 3 groups of Pro Network and get the endCursor of the pageInfo object. The default page size is 20, so to get the first 3 you need to specify it in the first argument.
Query
query ($urlname: String!) {
proNetworkByUrlname(urlname: $urlname) {
groupsSearch(input: {first: 3}) {
count
pageInfo {
endCursor
}
edges {
node {
id
name
}
}
}
}
}
Variables
{ "urlname": "YOUR_NETWORK_URLNAME" }
Response
{
"data": {
"proNetworkByUrlname": {
"groupsSearch": {
"count": 15,
"pageInfo": {
"endCursor": "[['1524147138299'],['28214336']]"
},
"edges": [
{
"node": {
"id": "33662217",
"name": "Kharkiv Adventure Meetup Group"
}
},
{
"node": {
"id": "29968188",
"name": "L0t$ of $pecial Ch@r@cters *.* 👻"
}
},
{
"node": {
"id": "28214336",
"name": "Testing it out"
}
}
]
}
}
}
}
To fetch the next set of records, copy the endCursor value and use it as after the argument value. The following example includes both fields and uses query variables to pass their values as arguments. The $itemsNum variable is required, and is used to specify the number of results to return.
Query
query ($urlname: String!, $itemsNum: Int!, $cursor: String!) {
proNetworkByUrlname(urlname: $urlname) {
groupsSearch(input: {first: $itemsNum, after: $cursor}) {
count
pageInfo {
endCursor
}
edges {
node {
id
name
}
}
}
}
}
Variables
{
"urlname": "YOUR_NETWORK_URLNAME",
"itemsNum": 3,
"cursor": "[['1524147138299'],['28214336']]"
}
Example: Collecting a list of groups in your network
To get a list of all groups from your network, first you need to get a Pro Network by ID or by urlname. Then, use the groupsSearch subquery.
Query
query($urlname: String!) {
proNetworkByUrlname(urlname: $urlname) {
groupsSearch(filter: {}, input: { first: 2 }) {
count
pageInfo {
endCursor
}
edges {
node {
id
name
urlname
memberships {
count
}
}
}
}
}
}
Variables
{ "urlname": "YOUR_NETWORK_URLNAME" }
Response
{
"data": {
"proNetworkByUrlname": {
"groupsSearch": {
"count": 15,
"pageInfo": {
"endCursor": "[['1524147138299'],['28214336']]"
},
"edges": [
{
"node": {
"id": "33662217",
"name": "Kharkiv Adventure Meetup Group",
"urlname": "Kharkiv-Adventure-Meetup-Group",
"memberships": {
"count": 4
}
}
},
{
"node": {
"id": "28214336",
"name": "Testing it out",
"urlname": "meetup-pro-test-group",
"memberships": {
"count": 34
}
}
}
]
}
}
}
In addition, you can search groups by different filter params which can be added to the input object
Example: Collecting list of upcoming events from the Pro Network
You can filter for upcoming events by calling the eventsSearch subquery and setting the status filter.
Query
query($urlname: String!) {
proNetworkByUrlname(urlname: $urlname) {
eventsSearch(filter: { status: UPCOMING }, input: { first: 3 }) {
count
pageInfo {
endCursor
}
edges {
node {
id
title
dateTime
}
}
}
}
Variables
{ "urlname": "YOUR_NETWORK_URLNAME" }
Response
{
"data": {
"proNetworkByUrlname": {
"groupsSearch": {
"count": 15,
"pageInfo": {
"endCursor": "[['1524147138299'],['28214336']]"
},
"edges": [
{
"node": {
"id": "33662217",
"name": "Kharkiv Adventure Meetup Group",
"urlname": "Kharkiv-Adventure-Meetup-Group",
"memberships": {
"count": 4
}
}
},
{
"node": {
"id": "28214336",
"name": "Testing it out",
"urlname": "meetup-pro-test-group",
"memberships": {
"count": 34
}
}
}
]
}
}
}
}
In addition, you can search groups by different filter params which can be added to the input object
Example: Collecting event information
Use the event query and filter to fetch Event details.
Query
query($eventId: ID!) {
event(id: $eventId) {
title
eventUrl
description
dateTime
duration
host {
id
name
}
images {
id
baseUrl
preview
}
group {
id
name
urlname
}
tickets {
edges {
node {
id
user {
name
}
createdAt
}
}
}
}
}
Variables
{
"$eventId": "EVENT_ID"
}
Response
{
"data": {
"event": {
"title": "Nastya's network event (test) 2",
"eventUrl": "https://beta2.dev.meetup.com:8000/Whiskey-Wednesdays/events/277543160",
"description": "let's test it",
"dateTime": "2023-01-31T15:00-07:00",
"duration": "PT1H",
"host": {
"id": "240771416",
"name": "Vadim Vlasenko (test)"
},
"images": [
{
"id": "495693322",
"baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
"preview": null
}
],
"group": {
"id": "6622782",
"name": "Whiskey Wednesdays 3",
"urlname": "Whiskey-Wednesdays"
},
"tickets": {
"edges": [
{
"node": {
"id": "1870061534!chp",
"user": {
"name": "Vadim Vlasenko (test)"
},
"createdAt": "2021-05-31T13:11:34.522+03:00[Europe/Moscow]"
}
}
]
}
}
}
}
In addition, you can get other fields from the Event object
Example: Collecting RSVP information
To fetch RSVP information for upcoming events, you first call the eventSearch query to get the list of upcoming events. Then, retrieve their RSVP details.
Query
query($urlname: String!) {
proNetworkByUrlname(urlname: $urlname) {
eventsSearch(filter: { status: UPCOMING }, input: { first: 3 }) {
count
pageInfo {
endCursor
}
edges {
node {
id
tickets {
edges {
node {
id
user {
name
email
}
createdAt
}
}
}
}
}
}
}
}
Variables
{
"urlname": "YOUR_NETWORK_URLNAME"
}
Response
{
"data": {
"proNetworkByUrlname": {
"eventsSearch": {
"count": 12,
"pageInfo": {
"endCursor": "[['1654383600000'],['264247573']]"
},
"edges": [
{
"node": {
"id": "278461755!chp",
"tickets": {
"edges": [
{
"node": {
"id": "1874780639!chp",
"user": {
"name": "test test (test)",
"email": "email@meetup.com"
},
"createdAt": "2021-05-28T15:25:02.910Z[UTC]"
}
}
]
}
}
},
{
"node": {
"id": "278450119!chp",
"tickets": {
"edges": [
{
"node": {
"id": "1874730763!chp",
"user": {
"name": "test test",
"email": "email@meetup.org"
},
"createdAt": "2021-05-28T15:25:02.900Z[UTC]"
}
}
]
}
}
},
{
"node": {
"id": "278000838!chp",
"tickets": {
"edges": [
{
"node": {
"id": "1872396589!chp",
"user": {
"name": "test test",
"email": "email@meetup.com"
},
"createdAt": "2021-05-28T15:25:02.901Z[UTC]"
}
}
]
}
}
}
]
}
}
}
}
You can check other fields from the Ticket object if you need
Example: Collecting RSVP registration answers
RSVP registration answers for a given event can be retrieved by using the rsvpSurveys query.
Query
query($urlname: String!, $eventId: ID!) {
proNetworkByUrlname(urlname: $urlname) {
rsvpSurveys(filter: { events: [$eventId]}) {
count
edges {
node {
id
answers {
question
answer
}
}
}
}
}
}
Variables
{
"urlname": "YOUR_NETWORK_URLNAME"
"$eventId": "EVENT_ID"
}
Response
{
"data": {
"proNetworkByUrlname": {
"rsvpSurveys": {
"count": 1,
"edges": [
"id": "2780087650838",
"answers": [
{
"question": "Some question",
"answer": "Some answer"
},
{
"question": "Another question",
"answer": "Another answer"
}
]
]
}
}
}
}
In addition, you can get other fields from the response object
Publishing with GraphQL
While GraphQL queries are used to fetch data, mutations modify records. They can be used to insert, update, or delete data.
Example: Publishing a new event
Events are typically drafted and reviewed before being published for the community to see. This example shows how to create a draft and publish the event. Please check the input schema for more detailed information.
Mutation
mutation($input: CreateEventInput!) {
createEvent(input: $input) {
event {
id
}
errors {
message
code
field
}
}
}
Variables
{
"input": {
"groupUrlname": "GROUP_URLNAME",
"title": "EVENT_TITLE",
"description": "EVENT_DESCRIPTION",
"startDateTime": "EVENT_STARTTIME",
"venueId": "EVENT_VENUE_ID",
"duration": "EVENT_DURATION",
"publishStatus": "DRAFT"
}
}
Response
{
"data": {
"createEvent": {
"event": {
"id": "278472065!chp"
},
"errors": []
}
}
}
Once you have the event drafted and ready to be published, run the following mutation
Mutation
mutation($input: EventEventInput!) {
editEvent(input: $input) {
event {
id
}
errors {
message
code
field
}
}
}
Variables
{
"input": {
"eventId": "EVENT_ID",
"publishStatus": "PUBLISHED"
}
}
Response
{
"data": {
"editEvent": {
"event": {
"id": "278472065!chp"
},
"errors": []
}
}
}
Example: Uploading an image
Uploading images consists of 2 parts. Creating a placeholder with a file name and then uploading the binary to our system.
First, create a placeholder for the image in the system by invoking the uploadImage
mutation.
Mutation
mutation($input: ImageUploadInput!) {
uploadImage(input: $input) {
uploadUrl
image {
id
baseUrl
preview
}
imagePath
}
}
Variables
{
"input": {
"groupId": GROUP_ID,
"photoType": GROUP_PHOTO,
"fileName": IMAGE_FILENAME,
"contentType": JPEG
}
}
Response
{
"data": {
"uploadImage": {
"uploadUrl": "{upload link}",
"image": {
"id": "496557439",
"baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/",
"preview": null
},
"imagePath": ""
}
}
}
The response contains an uploadUrl
where you can upload the image content-type using Postman, curl, or other similar application. The ID
value can be used as reference to other queries or in other mutations such as modifying an event.
Example: Editing an event
Please check the input object description for other fields which can be edited.
Mutation
mutation($input: EditEventInput!) {
editEvent(input: $input) {
event {
id
}
errors {
message
code
field
}
}
}
Variables
{
"input": {
"eventId": "EVENT_ID",
"description": "EVENT_DESCRIPTION",
"howToFindUs": ”EVENT_LOCATION_HINT”,
"featuredPhotoId": PHOTO_ID
}
}
Response
{
"data": {
"editEvent": {
"event": {
"id": "278472065!chp"
},
"errors": []
}
}
}
Working with Photos
The Meetup API provides access to the various photos associated with members, events, and groups. You can access these photos with the Image object. The Image object provides you with the flexibility to choose the size and type of image you would like to display. We currently support JPG and WEBP image formats.
Example: Event photo
Query
query($eventId: ID!) {
event(id: $eventId) {
id
images {
id
baseUrl
}
}
}
Variables
{ "eventId": "283013941" }
Response
{
"data": {
"event": {
"id": "283013941!chp",
"images": [
{
"id": "501175080",
"baseUrl": "https://secure-content.meetupstatic.com/images/classic-events/"
}
]
}
}
}
In the above example, you can access the featured event photo as the first image in the images array. You will receive a list of Image objects in the array. Then you can concatenate the baseUrl and Id of any given image with the desired width, height, and type of the image you desire.
As an example, here are two variations of valid photo links from the above response:
Rate Limiting
The Meetup API aims to provide consistent responsiveness and equal quality of service for all its consumers. In order to do so, we limit the frequency at which the API will produce successful responses to a single client.
The API currently allows you to have 500 points in your queries every 60 seconds. Clients that issue too many requests in a short period of time will receive an error message in their response. The error will display which query has caused you to be rate-limited along with the time when your limit will be reset.
{
"errors": [
{
"message": "Too many requests, please try again shortly.",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"event"
],
"extensions": {
"code": "RATE_LIMITED",
"consumedPoints": 500,
"resetAt": "2021-12-12T18:37:51.644Z"
}
}
],
"data": null
}
This response indicates that you are making requests too quickly. If you receive one of these errors, you should adjust the frequency of your requests by adding a pause between them.