Hoppa till huvudinnehåll

Memlist API Documentation

Authentication​

Memlist uses OAuth 2.0 Client Credentials for API access. All API endpoints are available at:

https://<instance>.memlist.se/api/v3/

Getting Started​

  1. In Memlist, go to the Administratör page and open the API: Nycklar tab
  2. Create a new API key - this gives you a client_id and client_secret
  3. Use these to obtain access tokens as described below

Obtaining an Access Token​

Endpoint: POST /api/v3/access/user/basic

Authentication: HTTP Basic Auth with client_id as username and client_secret as password.

Request​

curl -X POST https://<instance>.memlist.se/api/v3/access/user/basic \
-H "Authorization: Basic <base64(client_id:client_secret)>"

Example (with inline base64 encoding):

curl -X POST https://<instance>.memlist.se/api/v3/access/user/basic \
-H "Authorization: Basic $(echo -n 'your-client-id:your-client-secret' | base64)"

Response​

{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_expires_ts": 1743465600
}
FieldTypeDescription
access_tokenstringJWT token used to authenticate API requests
token_typestringAlways "Bearer"
expires_innumberToken lifetime in seconds
refresh_tokenstringToken used to obtain a new access token without re-authenticating
refresh_expires_tsnumberUnix timestamp when the refresh token expires

Error Responses​

StatusReasonDescription
401Missing or invalid Authorization headerNo Basic auth header provided
401invalid "Basic" credentialsCould not parse client_id and client_secret
401provided client_id and client_secret does not match any recordCredentials not found
429Too Many RequestsRate limit exceeded (max 10 requests per minute)

Using the Access Token​

Include the access token in the Authorization header for all API requests:

curl https://<instance>.memlist.se/api/v3/<endpoint> \
-H "Authorization: Bearer <access_token>"

Example: List members​

curl -X POST https://<instance>.memlist.se/api/v3/member/pagination \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"options": {
"period_id": 3,
"statuses": ["MEMBER", "PENDING_EXIT", "EXITED"]
},
"orderBy": { "created_at": "desc" },
"page": 1,
"limit": 100
}'

Refreshing an Access Token​

When the access token expires, use the refresh token to obtain a new one without re-entering credentials.

Endpoint: POST /api/v3/access/user/oauth/refresh_token

Request​

curl -X POST https://<instance>.memlist.se/api/v3/access/user/oauth/refresh_token \
-H "Content-Type: application/json" \
-d '{
"refresh_token": "eyJhbGciOiJIUzI1NiIs..."
}'

Response​

{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_expires_ts": 1743465600
}

A new refresh token is returned on each refresh (token rotation). Always store and use the latest refresh token.

Error Responses​

StatusReasonDescription
400Missing fieldrefresh_token field not provided
401expiredRefresh token has expired. Re-authenticate with client credentials.
403forbiddenInvalid refresh token
429Too Many RequestsRate limit exceeded (max 20 requests per minute)

Token Lifecycle​

1. Authenticate with client_id + client_secret
POST /access/user/basic
|
v
2. Receive access_token + refresh_token
|
v
3. Use access_token for API calls
Authorization: Bearer <access_token>
|
v
4. When access_token expires (401 "expired")
|
v
5. Use refresh_token to get new tokens
POST /access/user/oauth/refresh_token
|
v
6. Receive new access_token + new refresh_token
(go to step 3)
|
v
7. When refresh_token expires
(go to step 1)

Rate Limits​

EndpointLimit
POST /access/user/basic10 requests per minute per IP
POST /access/user/oauth/refresh_token20 requests per minute per IP

When rate limited, the API returns HTTP 429 Too Many Requests.


Common API Endpoints​

Once authenticated, the following endpoints are available. All requests require the Authorization: Bearer <access_token> header.

Members​

MethodEndpointDescription
POST/member/paginationList members (paginated)
GET/member/{id}Get member by ID
POST/memberCreate member
PUT/member/{id}Update member
DELETE/member/{id}Delete member

Events​

MethodEndpointDescription
GET/events/list?company_id={id}List events for a company
GET/events/{id}Get event by ID
POST/eventsCreate event
PUT/events/{id}Update event
DELETE/events/{id}Delete event

Company​

MethodEndpointDescription
GET/companyGet current company
GET/company/hierarchyGet company hierarchy

Periods​

MethodEndpointDescription
GET/company_periodList company periods

Member Types​

MethodEndpointDescription
GET/membertypeList member types

Properties / Attributes​

MethodEndpointDescription
GET/propertyList properties
MethodEndpointDescription
POST/market/members/searchSearch members with filters

Search Request Body:

{
"filters": {
"member_variables": {
"email": "EXISTS",
"statuses": ["MEMBER"],
"age_from": 18,
"age_to": 65
},
"companies": {
"company_ids": ["abc123"],
"include": "ANY"
},
"events": {
"event_ids": [1, 2],
"include": "ANY"
},
"properties": {
"prop_ids": [10, 20],
"include": "ANY"
}
},
"page": 1,
"limit": 100,
"sort_by": "created_desc",
"search_text": ""
}

Search Response:

{
"members": [ ... ],
"count": 122,
"page": 1,
"limit": 100
}

Error Handling​

All error responses follow this format:

{
"reason": "description of the error"
}

Common HTTP Status Codes​

StatusDescription
200Success
201Created
400Bad request (missing or invalid fields)
401Unauthorized (token expired or missing)
403Forbidden (insufficient permissions)
404Not found
422Invalid token
429Rate limit exceeded
500Internal server error

Handling Token Expiry​

When a token expires, the API returns:

{
"error": "expired",
"context": "user"
}

Your application should catch 401 responses and automatically refresh the token using the refresh endpoint.


Code Examples​

Node.js​

const axios = require('axios');

const BASE_URL = 'https://<instance>.memlist.se/api/v3';
const CLIENT_ID = 'your-client-id';
const CLIENT_SECRET = 'your-client-secret';

let access_token = null;
let refresh_token = null;

async function authenticate() {
const credentials = Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString('base64');
const res = await axios.post(`${BASE_URL}/access/user/basic`, null, {
headers: { Authorization: `Basic ${credentials}` }
});
access_token = res.data.access_token;
refresh_token = res.data.refresh_token;
}

async function refresh() {
const res = await axios.post(`${BASE_URL}/access/user/oauth/refresh_token`, {
refresh_token
});
access_token = res.data.access_token;
refresh_token = res.data.refresh_token;
}

async function api_call(method, path, data) {
try {
const res = await axios({
method,
url: `${BASE_URL}${path}`,
data,
headers: { Authorization: `Bearer ${access_token}` }
});
return res.data;
} catch (err) {
if (err.response?.status === 401) {
await refresh();
return api_call(method, path, data);
}
throw err;
}
}

// Usage
async function main() {
await authenticate();
const members = await api_call('post', '/member/pagination', {
options: { period_id: 3, statuses: ['MEMBER', 'PENDING_EXIT', 'EXITED'] },
orderBy: { created_at: 'desc' },
page: 1,
limit: 100
});
console.log(members);
}

main();

Python​

import requests
import base64

BASE_URL = 'https://<instance>.memlist.se/api/v3'
CLIENT_ID = 'your-client-id'
CLIENT_SECRET = 'your-client-secret'

class MemlistAPI:
def __init__(self):
self.access_token = None
self.refresh_token = None

def authenticate(self):
credentials = base64.b64encode(
f'{CLIENT_ID}:{CLIENT_SECRET}'.encode()
).decode()
res = requests.post(
f'{BASE_URL}/access/user/basic',
headers={'Authorization': f'Basic {credentials}'}
)
res.raise_for_status()
data = res.json()
self.access_token = data['access_token']
self.refresh_token = data['refresh_token']

def refresh(self):
res = requests.post(
f'{BASE_URL}/access/user/oauth/refresh_token',
json={'refresh_token': self.refresh_token}
)
res.raise_for_status()
data = res.json()
self.access_token = data['access_token']
self.refresh_token = data['refresh_token']

def request(self, method, path, **kwargs):
headers = {'Authorization': f'Bearer {self.access_token}'}
res = requests.request(method, f'{BASE_URL}{path}', headers=headers, **kwargs)
if res.status_code == 401:
self.refresh()
headers = {'Authorization': f'Bearer {self.access_token}'}
res = requests.request(method, f'{BASE_URL}{path}', headers=headers, **kwargs)
res.raise_for_status()
return res.json()

# Usage
api = MemlistAPI()
api.authenticate()
members = api.request('POST', '/member/pagination', json={
'options': {'period_id': 3, 'statuses': ['MEMBER', 'PENDING_EXIT', 'EXITED']},
'orderBy': {'created_at': 'desc'},
'page': 1,
'limit': 100
})
print(members)

cURL​

# 1. Authenticate
TOKEN=$(curl -s -X POST https://<instance>.memlist.se/api/v3/access/user/basic \
-H "Authorization: Basic $(echo -n 'client_id:client_secret' | base64)" \
| jq -r '.access_token')

# 2. Make API calls
curl -X POST https://<instance>.memlist.se/api/v3/member/pagination \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"options": {
"period_id": 3,
"statuses": ["MEMBER", "PENDING_EXIT", "EXITED"]
},
"orderBy": { "created_at": "desc" },
"page": 1,
"limit": 100
}'

Support​

For API support, contact your Memlist administrator or reach out at support@memlist.se.