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
- Contact your Memlist administrator to generate API credentials
- You will receive a
client_idandclient_secret - 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
}
| Field | Type | Description |
|---|---|---|
access_token | string | JWT token used to authenticate API requests |
token_type | string | Always "Bearer" |
expires_in | number | Token lifetime in seconds |
refresh_token | string | Token used to obtain a new access token without re-authenticating |
refresh_expires_ts | number | Unix timestamp when the refresh token expires |
Error Responses
| Status | Reason | Description |
|---|---|---|
| 401 | Missing or invalid Authorization header | No Basic auth header provided |
| 401 | invalid "Basic" credentials | Could not parse client_id and client_secret |
| 401 | provided client_id and client_secret does not match any record | Credentials not found |
| 429 | Too Many Requests | Rate 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 https://<instance>.memlist.se/api/v3/member \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
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
| Status | Reason | Description |
|---|---|---|
| 400 | Missing field | refresh_token field not provided |
| 401 | expired | Refresh token has expired. Re-authenticate with client credentials. |
| 403 | forbidden | Invalid refresh token |
| 429 | Too Many Requests | Rate 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
| Endpoint | Limit |
|---|---|
POST /access/user/basic | 10 requests per minute per IP |
POST /access/user/oauth/refresh_token | 20 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
| Method | Endpoint | Description |
|---|---|---|
| GET | /member | List members |
| GET | /member/{id} | Get member by ID |
| POST | /member | Create member |
| PUT | /member/{id} | Update member |
| DELETE | /member/{id} | Delete member |
Events
| Method | Endpoint | Description |
|---|---|---|
| GET | /events/list?company_id={id} | List events for a company |
| GET | /events/{id} | Get event by ID |
| POST | /events | Create event |
| PUT | /events/{id} | Update event |
| DELETE | /events/{id} | Delete event |
Company
| Method | Endpoint | Description |
|---|---|---|
| GET | /company | Get current company |
| GET | /company/hierarchy | Get company hierarchy |
Periods
| Method | Endpoint | Description |
|---|---|---|
| GET | /company_period | List company periods |
Member Types
| Method | Endpoint | Description |
|---|---|---|
| GET | /membertype | List member types |
Properties / Attributes
| Method | Endpoint | Description |
|---|---|---|
| GET | /property | List properties |
Search
| Method | Endpoint | Description |
|---|---|---|
| POST | /market/members/search | Search 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
| Status | Description |
|---|---|
| 200 | Success |
| 201 | Created |
| 400 | Bad request (missing or invalid fields) |
| 401 | Unauthorized (token expired or missing) |
| 403 | Forbidden (insufficient permissions) |
| 404 | Not found |
| 422 | Invalid token |
| 429 | Rate limit exceeded |
| 500 | Internal 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('get', '/member');
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('GET', '/member')
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 https://<instance>.memlist.se/api/v3/member \
-H "Authorization: Bearer $TOKEN"
Support
For API support, contact your Memlist administrator or reach out at support@memlist.se.