Stitchflow
Mailjet logo

Mailjet User Management API Guide

API workflow

How to automate user lifecycle operations through APIs with caveats that matter in production.

UpdatedMar 11, 2026

Summary and recommendation

Mailjet's REST API (v3) exposes a contact management layer, not a platform user management layer. Admin sub-users (Manager, Designer roles) cannot be provisioned or deprovisioned via the API - that is UI-only. The API operates on marketing contacts: create, update, list, delete, and list-subscription operations against the /contact and /listrecipient resources.

Authentication is HTTP Basic Auth using an API Key and Secret Key pair; the Full Access key scope is required for write operations. SCIM 2.0 is not available on any documented plan, so identity graph synchronization must be built on top of the REST contact endpoints directly.

API quick reference

Has user APIYes
Auth methodHTTP Basic Auth (API Key as username, Secret Key as password)
Base URLOfficial docs
SCIM availableNo
SCIM plan requiredNot available on any documented plan

Authentication

Auth method: HTTP Basic Auth (API Key as username, Secret Key as password)

Setup steps

  1. Log in to Mailjet account and navigate to Account Settings > API Keys.
  2. Copy the API Key (public) and Secret Key (private).
  3. Encode credentials as Base64 string: base64(API_KEY:SECRET_KEY).
  4. Pass as Authorization header: 'Authorization: Basic '.
  5. For Send API v3.1, use the same credentials against https://api.mailjet.com/v3.1/send.

Required scopes

Scope Description Required for
Full Access Read and write access to all API resources including contacts, lists, and account settings. Creating, updating, and deleting contacts and contact lists
Read Only Read-only access to all API resources. Listing and retrieving contacts and contact data
Send Restricted key allowing only email sending via Send API. Transactional email sending only; not sufficient for user management

User object / data model

Field Type Description On create On update Notes
ID integer Unique Mailjet-assigned contact identifier. auto-generated immutable Used as path parameter for single-contact operations.
Email string Contact's email address. Must be unique per account. required not updatable via standard endpoint; use /contact/{id}/changeaddress Primary identifier for contacts.
Name string Display name of the contact. optional optional
IsExcludedFromCampaigns boolean Whether the contact is excluded from marketing campaigns (unsubscribed globally). optional, defaults to false optional Setting to true is equivalent to a global unsubscribe.
CreatedAt datetime (ISO 8601) Timestamp when the contact was created. auto-generated immutable
LastActivityAt datetime (ISO 8601) Timestamp of the contact's last activity. auto-generated auto-updated
DeliveredCount integer Number of messages delivered to this contact. auto-generated read-only
UnsubscribedAt datetime (ISO 8601) Timestamp when the contact unsubscribed. null read-only
UnsubscribedBy string Source that triggered the unsubscribe. null read-only
ContactListID integer ID of the contact list the contact belongs to (used in list-contact operations). required for list subscription optional Managed via /listrecipient endpoint.
IsUnsubscribed boolean Whether the contact is unsubscribed from a specific list. optional optional List-level unsubscribe, distinct from IsExcludedFromCampaigns.
Properties (custom) object (key-value) Custom contact properties defined via /contactmetadata. Values set via /contactdata. optional optional Property names must be pre-defined via the contactmetadata resource before use.

Core endpoints

List contacts

  • Method: GET
  • URL: https://api.mailjet.com/v3/REST/contact
  • Watch out for: Default page size is 10; set Limit up to 1000 for bulk retrieval. Total reflects full count across pages.

Request example

GET /v3/REST/contact?Limit=10&Offset=0
Authorization: Basic <base64>

Response example

{
  "Count": 2,
  "Data": [
    {"ID": 1, "Email": "a@example.com", "Name": "Alice", "IsExcludedFromCampaigns": false}
  ],
  "Total": 2
}

Get single contact

  • Method: GET
  • URL: https://api.mailjet.com/v3/REST/contact/{contact_ID|email}
  • Watch out for: Can look up by numeric ID or email address. Email must be URL-encoded if it contains special characters.

Request example

GET /v3/REST/contact/abc@example.com
Authorization: Basic <base64>

Response example

{
  "Count": 1,
  "Data": [
    {"ID": 42, "Email": "abc@example.com", "Name": "Bob", "IsExcludedFromCampaigns": false}
  ],
  "Total": 1
}

Create contact

  • Method: POST
  • URL: https://api.mailjet.com/v3/REST/contact
  • Watch out for: Creating a contact does not subscribe them to any list. A separate POST to /listrecipient is required to add them to a contact list.

Request example

POST /v3/REST/contact
Content-Type: application/json

{"Email": "new@example.com", "Name": "New User", "IsExcludedFromCampaigns": false}

Response example

{
  "Count": 1,
  "Data": [
    {"ID": 99, "Email": "new@example.com", "Name": "New User", "IsExcludedFromCampaigns": false}
  ],
  "Total": 1
}

Update contact

  • Method: PUT
  • URL: https://api.mailjet.com/v3/REST/contact/{contact_ID}
  • Watch out for: Mailjet uses PUT (full replacement of editable fields), not PATCH. Email address cannot be changed via this endpoint.

Request example

PUT /v3/REST/contact/99
Content-Type: application/json

{"Name": "Updated Name", "IsExcludedFromCampaigns": true}

Response example

{
  "Count": 1,
  "Data": [
    {"ID": 99, "Email": "new@example.com", "Name": "Updated Name", "IsExcludedFromCampaigns": true}
  ],
  "Total": 1
}

Delete contact

  • Method: DELETE
  • URL: https://api.mailjet.com/v3/REST/contact/{contact_ID}
  • Watch out for: Deletion is subject to GDPR data deletion rules. Mailjet may retain anonymized statistical data. Deleted contacts cannot be recovered.

Request example

DELETE /v3/REST/contact/99
Authorization: Basic <base64>

Response example

HTTP 204 No Content

Bulk upsert contacts (async)

  • Method: POST
  • URL: https://api.mailjet.com/v3/REST/contact/managemanycontacts
  • Watch out for: Returns a JobID immediately; operation is asynchronous. Poll GET /contact/managemanycontacts/{JobID} to check completion status.

Request example

POST /v3/REST/contact/managemanycontacts
Content-Type: application/json

{"Contacts": [{"Email": "a@x.com", "Name": "A"}, {"Email": "b@x.com"}], "ContactsLists": [{"ListID": 5, "Action": "addnoforce"}]}

Response example

{
  "Count": 1,
  "Data": [{"JobID": 12345}],
  "Total": 1
}

Add/remove contact from list

  • Method: POST
  • URL: https://api.mailjet.com/v3/REST/listrecipient
  • Watch out for: To remove a contact from a list, use DELETE /listrecipient/{ID} or set IsUnsubscribed=true to unsubscribe without removing.

Request example

POST /v3/REST/listrecipient
Content-Type: application/json

{"ContactID": 99, "ListID": 5, "IsUnsubscribed": false}

Response example

{
  "Count": 1,
  "Data": [{"ID": 201, "ContactID": 99, "ListID": 5, "IsUnsubscribed": false}],
  "Total": 1
}

Get/set contact custom properties

  • Method: PUT
  • URL: https://api.mailjet.com/v3/REST/contactdata/{contact_ID}
  • Watch out for: Custom property names must be pre-created via POST /contactmetadata before values can be set. Property names are case-sensitive.

Request example

PUT /v3/REST/contactdata/99
Content-Type: application/json

{"Data": [{"Name": "department", "Value": "Engineering"}]}

Response example

{
  "Count": 1,
  "Data": [{"ContactID": 99, "Data": [{"Name": "department", "Value": "Engineering"}]}],
  "Total": 1
}

Rate limits, pagination, and events

  • Rate limits: Mailjet enforces rate limits per API key. Limits vary by plan and endpoint type. The REST API (contact management) has separate limits from the Send API.
  • Rate-limit headers: Yes
  • Retry-After header: No
  • Rate-limit notes: Exact rate limit header names are not publicly documented in detail. Bulk contact import via /contact/managemanycontacts is asynchronous and subject to separate job-based limits. Exceeding limits returns HTTP 429.
  • Pagination method: offset
  • Default page size: 10
  • Max page size: 1000
  • Pagination pointer: Limit and Offset query parameters (e.g., ?Limit=100&Offset=0)
Plan Limit Concurrent
Free 200 requests/minute on REST API 0
Essential 300 requests/minute on REST API 0
Premium 300 requests/minute on REST API 0
Custom/Enterprise Negotiated higher limits 0
  • Webhooks available: Yes
  • Webhook notes: Mailjet provides Event API (webhooks) for email delivery events. These are not user-management webhooks but can be used to track contact-level events such as unsubscribes, bounces, and spam complaints to keep external user records in sync.
  • Alternative event strategy: Poll GET /contact or GET /eventcallbackurl for contact state changes. Use /contact/managemanycontacts job polling for bulk operation status.
  • Webhook events: sent, open, click, bounce, spam, unsub, blocked, error

SCIM API status

  • SCIM available: No
  • SCIM version: Not documented
  • Plan required: Not available on any documented plan
  • Endpoint: Not documented

Limitations:

  • Mailjet does not document a SCIM 2.0 endpoint in any official developer or help center documentation.
  • SAML SSO is available on Premium 100k+ and Custom plans but SCIM provisioning is not offered.
  • User provisioning must be handled via the REST Contact API or manual processes.

Common scenarios

Three core provisioning patterns are supported by the API. For single-contact provisioning: POST /v3/REST/contact to create the record, then POST /v3/REST/listrecipient to subscribe - contact creation alone does not add the contact to any list.

For bulk operations: POST /v3/REST/contact/managemanycontacts with a Contacts array and ContactsLists array.

this returns a JobID immediately and must be polled via GET /v3/REST/contact/managemanycontacts/{JobID} until Status is 'Completed' or 'Error' - the operation is fully asynchronous and large imports can take several minutes.

For deprovisioning: use PUT /v3/REST/contact/{ID} with IsExcludedFromCampaigns=true for global suppression, DELETE /v3/REST/listrecipient/{ID} for list-scoped removal, or DELETE /v3/REST/contact/{ID} for GDPR erasure - note that Mailjet may retain anonymized aggregate statistics after deletion.

Provision a new contact and subscribe to a list

  1. POST /v3/REST/contact with Email and Name to create the contact record.
  2. Note the returned contact ID from the response Data[0].ID.
  3. POST /v3/REST/listrecipient with ContactID and ListID to subscribe the contact to the target list.
  4. Optionally PUT /v3/REST/contactdata/{ID} to set custom property values.

Watch out for: Creating a contact does not automatically subscribe them to any list. Both steps are required. If the contact already exists, POST /contact returns the existing record without error (idempotent by email).

Bulk import and subscribe contacts

  1. POST /v3/REST/contact/managemanycontacts with a Contacts array and ContactsLists array specifying ListID and Action ('addnoforce' or 'addforce').
  2. Capture the JobID from the response.
  3. Poll GET /v3/REST/contact/managemanycontacts/{JobID} until Status is 'Completed' or 'Error'.
  4. On error, inspect the Error field in the job response for per-contact failure details.

Watch out for: The job is asynchronous; do not assume completion immediately after POST. Large imports may take several minutes. 'addnoforce' skips already-subscribed contacts; 'addforce' re-subscribes them.

Unsubscribe / deprovision a contact

  1. To globally suppress: PUT /v3/REST/contact/{ID} with IsExcludedFromCampaigns=true.
  2. To remove from a specific list: GET /v3/REST/listrecipient?ContactID={ID}&ListID={ListID} to find the listrecipient ID, then DELETE /v3/REST/listrecipient/{listrecipient_ID}.
  3. For GDPR erasure: DELETE /v3/REST/contact/{ID} to remove the contact record.

Watch out for: IsExcludedFromCampaigns=true suppresses all campaigns but does not remove the contact from lists. Full deletion via DELETE removes the contact but Mailjet may retain anonymized aggregate statistics.

Why building this yourself is a trap

Several non-obvious behaviors create integration risk. The API uses PUT semantics, not PATCH - omitting optional fields on update may reset them to defaults. Email addresses are immutable after contact creation via the standard PUT endpoint; a separate undocumented endpoint exists but is not reliably supported.

Custom contact properties must be pre-defined via POST /contactmetadata before any values can be written via /contactdata - skipping this step returns a 400 error with no clear remediation hint. Rate limit responses return HTTP 429 with no documented Retry-After header, so callers must implement exponential backoff independently.

Finally, the identity graph implication: because Mailjet contacts are marketing records rather than identity objects, any external identity graph integration must treat the Mailjet contact ID as a secondary identifier and reconcile on email address, which is unique per account but cannot be updated post-creation through the standard API surface.

Automate Mailjet workflows without one-off scripts

Stitchflow builds and maintains end-to-end IT automation across your SaaS stack, including apps without APIs. Built for exactly how your company works, with human approvals where they matter.

Every app coverage, including apps without APIs
60+ app integrations plus browser automation for apps without APIs
IT graph reconciliation across apps and your IdP
Less than a week to launch, maintained as APIs and admin consoles change
SOC 2 Type II. ~2 hours of your team's time

UpdatedMar 11, 2026

* Details sourced from official product documentation and admin references.

Keep exploring

Related apps

Abnormal Security logo

Abnormal Security

API Only
AutomationAPI only
Last updatedMar 2026

Abnormal Security is an enterprise email security platform focused on detecting and investigating threats such as phishing, account takeover (ATO), and vendor email compromise. It does not support SCIM provisioning, which means every app in your stack

ActiveCampaign logo

ActiveCampaign

API Only
AutomationAPI only
Last updatedFeb 2026

ActiveCampaign uses a group-based permission model: every user belongs to exactly one group, and all feature-area access (Contacts, Campaigns, Automations, Deals, Reports, Templates) is configured at the group level, not per individual. The default Adm

ADP logo

ADP

API Only
AutomationAPI only
Last updatedFeb 2026

ADP Workforce Now is a mid-market to enterprise HCM platform that serves as the HR source of record for employee data — payroll, benefits, time, and talent. User access is governed by a hybrid permission model: predefined security roles (Security Maste