Summary and recommendation
AfterShip exposes a versioned Members API at https://api.aftership.com/admin/2022-01/memberships supporting list, create, get, update (role only), and delete operations. Authentication is via API key (header: as-api-key); HMAC-SHA256 SignString and RSA key pair methods are also supported. OAuth 2.0 is restricted to AfterShip Partner Program apps and is not available for standard direct integrations.
The API enforces a rate limit of 10 requests/second per organization, returning HTTP 429 on breach, with rate limit values surfaced in response headers. Pagination uses offset-based page/limit params with a default page size of 100 and a maximum of 200. There is no SCIM endpoint; SCIM is not publicly documented for any AfterShip plan.
API quick reference
| Has user API | Yes |
| Auth method | API Key (header: as-api-key); also supports HMAC-SHA256 SignString and RSA key pair (RSA_SIGN_PSS_2048_SHA256). OAuth 2.0 available for Partner Program apps only. |
| Base URL | Official docs |
| SCIM available | No |
| SCIM plan required | Enterprise |
Authentication
Auth method: API Key (header: as-api-key); also supports HMAC-SHA256 SignString and RSA key pair (RSA_SIGN_PSS_2048_SHA256). OAuth 2.0 available for Partner Program apps only.
Setup steps
- Log in to your AfterShip account at the organization admin portal.
- Navigate to Settings > API Keys.
- Click 'Create an API key' and follow the instructions to generate your key.
- Include the key in all API requests as the header: as-api-key:
. - For SignString auth: construct the SignString, retrieve the API secret, compute HMAC-SHA256, and base64-encode the result.
- For RSA auth: generate an RSA key pair, upload the public key (key.pem) to the AfterShip Organization portal, and sign requests using RSA_SIGN_PSS_2048_SHA256 with the private key.
- For OAuth 2.0 (Partner Program only): register app in Partner Dashboard, implement authorization code flow, obtain access_token (expires 30 days), use header as-access-token for requests.
Required scopes
| Scope | Description | Required for |
|---|---|---|
| N/A (API Key auth) | API Key authentication does not use named scopes; access is org-wide based on the key. | All Members API endpoints when using API Key or SignString auth |
| OAuth scopes (Partner Program only) | OAuth scopes are requested per-app during the Partner Program OAuth flow; specific scope names for Members API are not publicly listed in official docs. | OAuth-based Partner app access to Members API |
User object / data model
| Field | Type | Description | On create | On update | Notes |
|---|---|---|---|---|---|
| id | string | Unique identifier of the membership record. | system-generated | immutable | Required, >= 1 character. |
| organization.id | string | Unique identifier of the organization the membership belongs to. | derived from authenticated org context | immutable | Required. |
| account.id | string | Unique identifier of the AfterShip account being added as a member. | required | immutable | Required, >= 1 character. |
| account.email | string | Email address of the account. Must already be registered with AfterShip. | required | not updatable | Required on create. The invited user must have a pre-existing AfterShip account. |
| role.code | string | Role code assigned to the member within the organization. Must be unique per account per organization. | required | updatable via PATCH | Only one role per account per organization is supported. Role permissions must be configured via AfterShip support team. |
Core endpoints
List memberships
- Method: GET
- URL:
https://api.aftership.com/admin/2022-01/memberships - Watch out for: Returns all memberships for the authenticated organization. Supports page and limit query params.
Request example
curl -X GET https://api.aftership.com/admin/2022-01/memberships \
-H 'as-api-key: YOUR_API_KEY' \
-H 'Content-Type: application/json'
Response example
{
"meta": {"code": 200},
"data": {
"memberships": [{"id": "mem_123", "account": {"id": "acc_1", "email": "user@example.com"}, "role": {"code": "member"}}],
"pagination": {"page": 1, "limit": 100, "total": 1}
}
}
Create membership (invite member)
- Method: POST
- URL:
https://api.aftership.com/admin/2022-01/memberships - Watch out for: The invited email must already be registered with AfterShip. Invitation goes through an email verification flow. Only one role per account per org is supported.
Request example
curl -X POST https://api.aftership.com/admin/2022-01/memberships \
-H 'as-api-key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"account": {"email": "user@example.com"}, "role": {"code": "member"}}'
Response example
{
"meta": {"code": 201},
"data": {
"membership": {"id": "mem_456", "account": {"id": "acc_2", "email": "user@example.com"}, "role": {"code": "member"}}
}
}
Get membership by ID
- Method: GET
- URL:
https://api.aftership.com/admin/2022-01/memberships/{id} - Watch out for: Returns 404 if the membership ID does not exist in the authenticated organization.
Request example
curl -X GET https://api.aftership.com/admin/2022-01/memberships/mem_123 \
-H 'as-api-key: YOUR_API_KEY'
Response example
{
"meta": {"code": 200},
"data": {
"membership": {"id": "mem_123", "account": {"id": "acc_1", "email": "user@example.com"}, "role": {"code": "member"}}
}
}
Update membership by ID
- Method: PATCH
- URL:
https://api.aftership.com/admin/2022-01/memberships/{id} - Watch out for: Only the role.code field is updatable. Role permissions must be pre-configured by contacting AfterShip support.
Request example
curl -X PATCH https://api.aftership.com/admin/2022-01/memberships/mem_123 \
-H 'as-api-key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"role": {"code": "admin"}}'
Response example
{
"meta": {"code": 200},
"data": {
"membership": {"id": "mem_123", "role": {"code": "admin"}}
}
}
Delete membership by ID
- Method: DELETE
- URL:
https://api.aftership.com/admin/2022-01/memberships/{id} - Watch out for: Removes the member from the organization. The underlying AfterShip account is not deleted.
Request example
curl -X DELETE https://api.aftership.com/admin/2022-01/memberships/mem_123 \
-H 'as-api-key: YOUR_API_KEY'
Response example
{
"meta": {"code": 200},
"data": {}
}
Get roles
- Method: GET
- URL:
https://api.aftership.com/admin/2022-01/roles - Watch out for: The 'owner' role is the default highest-privilege role. Custom role permissions require contacting AfterShip support to configure.
Request example
curl -X GET https://api.aftership.com/admin/2022-01/roles \
-H 'as-api-key: YOUR_API_KEY'
Response example
{
"meta": {"code": 200},
"data": {
"roles": [{"code": "owner"}, {"code": "admin"}, {"code": "member"}]
}
}
Rate limits, pagination, and events
- Rate limits: 10 requests/second per organization for the Members API. Exceeding the limit returns HTTP 429 (TooManyRequests). Rate limit values are returned in API response headers.
- Rate-limit headers: Yes
- Retry-After header: No
- Rate-limit notes: Rate limit headers are included in every API response. No plan-tiered rate limits documented for the Members API specifically. HTTP 429 is returned on breach.
- Pagination method: offset
- Default page size: 100
- Max page size: 200
- Pagination pointer: page / limit
| Plan | Limit | Concurrent |
|---|---|---|
| All plans | 10 requests/second per organization | 0 |
- Webhooks available: Yes
- Webhook notes: AfterShip supports webhooks for tracking and shipping events. Webhook requests include an HMAC-SHA256 signature header (aftership-hmac-sha256 for Tracking, am-webhook-signature for Shipping) for verification. Multiple webhook URLs can be registered. No webhook events are documented specifically for membership/user changes.
- Alternative event strategy: Poll the GET /memberships endpoint to detect membership changes, as no membership-specific webhook events are documented.
- Webhook events: tracking.update (Tracking API), shipment.update (Shipping API), return.update (Returns API)
SCIM API status
- SCIM available: No
- SCIM version: Not documented
- Plan required: Enterprise
- Endpoint: Not documented
Limitations:
- No public SCIM documentation found in official AfterShip docs.
- SSO (SAML 2.0) with JIT provisioning is available on the Enterprise plan via Okta and Entra ID.
- Must contact AfterShip vendor for any enterprise provisioning features.
Common scenarios
Three primary automation scenarios are supported by the Members API.
To provision a member, first confirm the target email is already registered with AfterShip (the API cannot create net-new accounts), retrieve available role codes via GET /roles, then POST to /memberships with the email and role code - the user receives an email verification before the membership activates.
To update a member's role, GET /memberships to resolve the membership ID, then PATCH /memberships/{id} with the new role. code; note that custom roles must be pre-configured by AfterShip support before they can be assigned programmatically.
To deprovision, DELETE /memberships/{id} removes the user from the organization without deleting their underlying AfterShip account; because no membership-specific webhook events exist, downstream systems must poll GET /memberships to detect removals.
For teams requiring broader identity lifecycle automation, Stitchflow operates as an MCP server with ~100 deep IT/identity integrations, enabling orchestration across AfterShip and the rest of the stack without building point-to-point polling logic.
Provision a new team member
- Ensure the target user already has an AfterShip account registered with their email.
- Call GET https://api.aftership.com/admin/2022-01/roles to retrieve available role codes.
- Call POST https://api.aftership.com/admin/2022-01/memberships with the user's email and desired role code.
- The user receives an email verification; membership is active after confirmation.
Watch out for: If the email is not pre-registered with AfterShip, the POST will fail. You cannot create a net-new AfterShip account via the Members API.
Update a member's role
- Call GET https://api.aftership.com/admin/2022-01/memberships to find the membership ID for the target user.
- Call PATCH https://api.aftership.com/admin/2022-01/memberships/{id} with the new role code in the request body.
- Confirm the updated role in the response.
Watch out for: Custom roles beyond the defaults must be pre-configured by AfterShip support before they can be assigned via API.
Deprovision (remove) a member
- Call GET https://api.aftership.com/admin/2022-01/memberships to locate the membership ID for the user to remove.
- Call DELETE https://api.aftership.com/admin/2022-01/memberships/{id} to remove the membership.
- Verify removal by calling GET https://api.aftership.com/admin/2022-01/memberships and confirming the user is no longer listed.
Watch out for: Deleting a membership only removes the user from the organization; it does not delete their AfterShip account. There are no webhook notifications for this event, so downstream systems must poll to detect deprovisioning.
Why building this yourself is a trap
Several non-obvious constraints can break integrations built against the AfterShip Members API. The invited user's email must be pre-registered with AfterShip; a POST to /memberships for an unregistered email will fail, meaning provisioning flows must include an account-existence check or a manual pre-registration step.
Only one role per account per organization is supported, so multi-role or tiered access patterns are not achievable. Custom role codes cannot be created or modified via API - they require a support ticket to AfterShip, introducing an out-of-band dependency in any automated provisioning pipeline.
The legacy API key header (aftership-api-key) was deprecated in version 2023-10; integrations using the old header against the current versioned base URL will fail silently or return auth errors. Finally, there are no webhook events for membership changes, making real-time deprovisioning detection impossible without a polling implementation - a meaningful gap for compliance-sensitive offboarding workflows.
Automate AfterShip workflows without one-off scripts
Stitchflow builds and maintains identity workflows for your exact setup. We cover every app, including the ones without APIs, and run deterministic trigger-to-report workflows with human approvals where they matter.