Account and Sub-account Scope
Account scope
An access token authenticates requests for its Account. Where the current
contract supports it, omitting X-SubAccount-Id uses that Account scope.
Account management and API-key management happen in the authenticated Mailhub
application; they are not public integration endpoints.
Optional Sub-account scope
X-SubAccount-Id can optionally narrow a supported request to an authorized
Sub-account. The Sub-account must belong to the authenticated Account. Keep a
workflow in one consistent scope, and do not reuse an identifier in another
scope without verified access.
The effect is operation-specific, not a universal scope switch. For the carrier operations — requesting Rates and buying a Label — the selected Sub-account can narrow the carriers available to it, so a Rate you expect may be absent when the header is sent. It does not change pricing, and it does not decide which resources you may reach: that is enforced by Account ownership on every operation. See Work with Sub-accounts for the per-operation matrix.
This documentation uses Sub-account consistently.
Verified operation behavior
This table shows the documented behavior for each operation; the header is never a requirement for token exchange, refresh, or revoke.
| Operation | Method and path | Header effect | What the caller should do |
|---|---|---|---|
| Login | POST /api/v1/auth/token | Optional: validates the selected Sub-account for token exchange but does not persist that scope in either returned token. | Use only when the token exchange itself needs that validation; do not rely on it to scope later requests. |
| Refresh token | POST /api/v1/auth/token/refresh | The operation does not read the header; a well-formed value does not change behavior. | Omit it; do not use it to establish request scope. |
| Logout | POST /api/v1/auth/token/revoke | The operation does not read the header; a well-formed value does not change behavior. | Omit it; do not use it to establish request scope. |
| Cancel shipping label | DELETE /api/v1/labels/{labelId} | Sending X-SubAccount-Id does not change the behavior of this operation. | Omit it; do not rely on it to scope this operation. |
| Download shipping label | GET /api/v1/labels/{labelId}/download | Sending X-SubAccount-Id does not change the behavior of this operation. | Omit it; do not rely on it to scope this operation. |
| List orders | GET /api/v1/orders | Optional: filters the Order list to the selected Sub-account. | Send it when listing that Sub-account; omit it to use the authenticated Account context. |
| Create an Order | POST /api/v1/orders | Optional: tags the newly created Order and its Shipments with the selected Sub-account. | Send it only when creating in that Sub-account. |
| Get order by ID | GET /api/v1/orders/{orderId} | Sending X-SubAccount-Id does not change the behavior of this operation. | Omit it; do not rely on it to scope this operation. |
| Updates order status. | PATCH /api/v1/orders/{orderId}/status | Sending X-SubAccount-Id does not change the behavior of this operation. | Omit it; do not rely on it to scope this operation. |
| Create shipping label | POST /api/v1/shipments/{shipmentId}/labels | Optional: evaluates the request against the selected Sub-account, which can narrow the carriers available to it. It does not change pricing and does not restrict resource access. | Send it when the request should use that Sub-account’s carrier availability; omit it to use the authenticated Account context. |
| Get shipment rates | POST /api/v1/shipments/{shipmentId}/rates | Optional: evaluates the request against the selected Sub-account, which can narrow the carriers available to it. It does not change pricing and does not restrict resource access. | Send it when the request should use that Sub-account’s carrier availability; omit it to use the authenticated Account context. |
| Create an Order with Rates | POST /api/v2/orders | Optional: tags the newly created Order and its Shipments with the selected Sub-account. | Send it only when creating in that Sub-account. |
Errors to correct, not retry unchanged
A malformed header value, a Sub-account that is not owned by the Account, an inactive or unauthorized scope, or a resource not found in the selected scope requires client action. Correct the value or scope before retrying. Do not infer a status or error code beyond the current API response.
Examples
Use the Account scope by omitting the optional header:
curl -s "${MAILHUB_API_BASE_URL}/api/v1/orders" \
-H "Authorization: Bearer ${MAILHUB_ACCESS_TOKEN}"
Use a verified Sub-account scope on a supported create request:
curl -s -X POST "${MAILHUB_API_BASE_URL}/api/v1/orders" \
-H "Authorization: Bearer ${MAILHUB_ACCESS_TOKEN}" \
-H "X-SubAccount-Id: ${MAILHUB_SUBACCOUNT_ID}" \
-H "Content-Type: application/json" \
--data @order.json
For a multi-step workflow, consult Work with Sub-accounts at each step. Do not infer that a scope used while creating an Order automatically affects later Rate or Label operations.
For token exchange, refresh, and revoke, do not add X-SubAccount-Id merely
to establish scope; those operations do not use it as request scope.