Team Members
Team members represent the people who have access to your EPD merchant account.
Each team member belongs to your merchant and is assigned a role that controls what they can see and do in the dashboard. Use these endpoints to invite new team members and review who currently has access.
Invitation flow
When you create a team member, EPD sends them an email so they can finish setting up their access. The team member starts in pending status and moves to active after they accept:
- If the email already belongs to an EPD account, the message invites them to join your merchant account.
- Otherwise, the message walks them through creating a password and signing in for the first time.
Permissions
| Endpoint | Required permission |
|---|---|
GET /v1/roles |
team_members:read |
POST /v1/team_members |
team_members:write |
GET /v1/team_members |
team_members:read |
/roles List roles
Returns the roles available within your merchant account, sorted alphabetically by name.
Use this endpoint to discover the per-merchant role_id you pass to POST /v1/team_members.
Expanding permissions
By default each role includes id, name, description, and default_page. Pass ?expand=permissions to also include the underlying permission keys for each role.
Query parameters
string"permissions"Header parameters
string"2026-02-11"Code samples
# List roles
curl https://api.epd.com/v1/roles \
-H "Authorization: Bearer epd_test_sk_xxxx" \
-H "EPD-Version: 2026-02-11"
# Include permissions
curl "https://api.epd.com/v1/roles?expand=permissions" \
-H "Authorization: Bearer epd_test_sk_xxxx" const response = await fetch(
'https://api.epd.com/v1/roles?expand=permissions',
{
headers: {
'Authorization': 'Bearer epd_test_sk_xxxx',
'EPD-Version': '2026-02-11',
},
}
);
const { data } = await response.json();
for (const role of data) {
console.log(role.id, role.name, role.permissions?.length ?? 0);
} import requests
response = requests.get(
'https://api.epd.com/v1/roles',
headers={
'Authorization': 'Bearer epd_test_sk_xxxx',
'EPD-Version': '2026-02-11',
},
params={'expand': 'permissions'},
)
for role in response.json()['data']:
print(role['id'], role['name']) Responses
array[Role]string"/v1/roles"objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]/team_members Create a team member
Adds a new team member to your merchant account and emails them an invitation so they can finish setting up access.
The new member starts in pending status and moves to active after they accept the invitation.
Restrictions
- Each email can only be a member of your merchant once. Re-inviting an email that already has an active or pending membership returns
409 resource_already_exists. phone_numbermust be a US number in E.164 format —+1followed by exactly 10 digits (e.g.,+15551234567).
Discovering role_id
Call GET /v1/roles to look up the role_id you want to assign. You can cache these IDs — they don't change unless a role is renamed or deleted from the dashboard.
Header parameters
string"2026-02-11"string (uuid)"550e8400-e29b-41d4-a716-446655440000"Request body required
string"Jane"string"Doe"string (email)"jane@example.com"string"+15551234567"string (uuid)"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f"Code samples
curl -X POST https://api.epd.com/v1/team_members \
-H "Authorization: Bearer epd_test_sk_xxxx" \
-H "Content-Type: application/json" \
-H "EPD-Version: 2026-02-11" \
-H "X-EPD-Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
-d '{
"first_name": "Jane",
"last_name": "Doe",
"email": "jane@example.com",
"phone_number": "+15551234567",
"role_id": "c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f"
}' const response = await fetch('https://api.epd.com/v1/team_members', {
method: 'POST',
headers: {
'Authorization': 'Bearer epd_test_sk_xxxx',
'Content-Type': 'application/json',
'EPD-Version': '2026-02-11',
'X-EPD-Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
first_name: 'Jane',
last_name: 'Doe',
email: 'jane@example.com',
phone_number: '+15551234567',
role_id: 'c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f',
}),
});
const teamMember = await response.json();
console.log(teamMember.id, teamMember.status); // ..., 'pending' import uuid
import requests
response = requests.post(
'https://api.epd.com/v1/team_members',
headers={
'Authorization': 'Bearer epd_test_sk_xxxx',
'EPD-Version': '2026-02-11',
'X-EPD-Idempotency-Key': str(uuid.uuid4()),
},
json={
'first_name': 'Jane',
'last_name': 'Doe',
'email': 'jane@example.com',
'phone_number': '+15551234567',
'role_id': 'c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f',
}
)
team_member = response.json()
print(team_member['id'], team_member['status']) Responses
string (uuid)"8f9e1c5a-3b2d-4f6e-9a1b-2c3d4e5f6a7b"string (email)"jane@example.com"string"Jane"string"Doe"string"+15551234567"enumpendingactiveblocked"pending"objectstring (uuid)"c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f"string"Manager"string (date-time)"2026-05-08T10:30:00.000Z"string (date-time)"2026-05-08T10:30:00.000Z"objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]/team_members List team members
Returns a paginated list of team members for the authenticated merchant, sorted by creation date (newest first by default).
Pagination
Uses cursor-based pagination. Use starting_after with the last team member's ID to fetch the next page.
GET /v1/team_members?limit=20
GET /v1/team_members?limit=20&starting_after=8f9e1c5a-3b2d-4f6e-9a1b-2c3d4e5f6a7b
Filtering
Filter by membership status with ?status=pending|active|blocked.
Query parameters
integer10string"550e8400-e29b-41d4-a716-446655440000"string"550e8400-e29b-41d4-a716-446655440001"enumpendingactiveblocked"active"Header parameters
string"2026-02-11"Code samples
# List first 20 team members
curl https://api.epd.com/v1/team_members?limit=20 \
-H "Authorization: Bearer epd_test_sk_xxxx" \
-H "EPD-Version: 2026-02-11"
# Only pending invitations
curl "https://api.epd.com/v1/team_members?status=pending" \
-H "Authorization: Bearer epd_test_sk_xxxx" const params = new URLSearchParams({ limit: '20', status: 'active' });
const response = await fetch(
`https://api.epd.com/v1/team_members?${params}`,
{
headers: {
'Authorization': 'Bearer epd_test_sk_xxxx',
'EPD-Version': '2026-02-11',
},
}
);
const { data, has_more, cursors } = await response.json(); import requests
response = requests.get(
'https://api.epd.com/v1/team_members',
headers={
'Authorization': 'Bearer epd_test_sk_xxxx',
'EPD-Version': '2026-02-11',
},
params={'limit': 20, 'status': 'active'},
)
result = response.json()
for member in result['data']:
print(member['email'], member['role']['name']) Responses
array[TeamMember]any"/v1/team_members"objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]objectenuminvalid_request_errorauthentication_errorauthorization_errorrate_limit_erroridempotency_errorprocessing_errorwebhook_errorstring"validation_error"string"Request validation failed"string"email"string"req_a1b2c3d4e5f67890abcdef0123456789"array[object]