Sub-Accounts API

Sub-Accounts API

Overview

The Sub-Accounts feature enables SaaS companies to programmatically manage multiple client integrations under one master account. Instead of requiring each of your customers to create their own PSRESTful account, you can create and manage sub-accounts on their behalf, providing seamless PromoStandards API access through your platform.

Use Case Example: SaaS Platform Integration

Scenario: You run a SaaS platform that provides promotional products ordering capabilities to your customers.

Without Sub-Accounts:

  • Each customer needs their own PSRESTful account
  • Customers manage their own API keys
  • No centralized control or visibility
  • Complex onboarding process

With Sub-Accounts:

  1. Your platform has one parent account (Enterprise plan)
  2. Create a sub-account for each of your customers
  3. Generate API keys for each sub-account
  4. Map sub-accounts to your customers via external_customer_id
  5. Make PromoStandards API calls on behalf of your customers
  6. Track usage and manage access centrally

Getting Started

Prerequisites

Parent Account Requirements:

  • Enterprise plan
  • Sub-accounts feature enabled (contact us to help setup your account accordingly)
  • Cannot itself be a sub-account (no nested sub-accounts)

Authentication:

  • OAuth2 Bearer Token OR API Key
  • Public API keys are NOT supported for sub-accounts endpoints

Base URL

All endpoints are prefixed with:

https://api.psrestful.com/extra/v2/subaccounts

Authentication Methods

Option 1: OAuth2 (Recommended for web applications)

Authorization: Bearer eyJhbGciOiJSUzI1NiIs...

Option 2: API Key (Recommended for server-to-server)

X-API-Key: your-api-key-here

API Endpoints

1. List Sub-Accounts

Retrieve all sub-accounts for your parent account.

Endpoint:

GET /extra/v2/subaccounts/

Permission: Parent account members only

Query Parameters:

ParameterTypeRequiredDefaultDescription
include_inactivebooleanNofalseInclude soft-deleted sub-accounts

Example Request:

curl -X GET "https://api.psrestful.com/extra/v2/subaccounts/?include_inactive=false" \
  -H "X-API-Key: your-api-key-here"

Response: 200 OK

{
  "count": 2,
  "results": [
    {
      "id": 123,
      "name": "ACME Corp - Client A",
      "external_customer_id": "mkf_12345",
      "organization_contact_name": "John Doe",
      "organization_contact_email": "john@acme.com",
      "account_notes": "Large distributor in TX",
      "is_active": true,
      "api_keys_count": 2,
      "created_at": "2025-01-15T10:30:00Z",
      "modified_on": "2025-01-20T14:45:00Z",
      "created_by": "admin@yourplatform.com"
    }
  ]
}

Response Fields:

FieldTypeDescription
countintegerTotal number of sub-accounts
resultsarrayList of sub-account objects
idintegerUnique sub-account identifier
namestringSub-account display name
external_customer_idstring/nullYour internal customer/client ID
organization_contact_namestring/nullContact person name
organization_contact_emailstring/nullContact person email
account_notesstring/nullInternal notes
is_activebooleanActive status (false = soft deleted)
api_keys_countintegerNumber of API keys for this sub-account
created_atdatetimeISO 8601 timestamp
modified_ondatetimeISO 8601 timestamp
created_bystring/nullEmail of creator or “API Key”

Errors:

  • 403 Forbidden - Not authenticated or not a parent account member

2. Create Sub-Account

Create a new sub-account under your parent account.

Endpoint:

POST /extra/v2/subaccounts/

Permission: Parent account members only

Request Body:

FieldTypeRequiredMax LengthDescription
namestringYes255Sub-account display name
external_customer_idstringYes255Your internal customer ID (must be unique)
organization_contact_namestringNo255Contact person name
organization_contact_emailstringNo-Valid email address
account_notesstringNo-Internal notes

Example Request:

curl -X POST "https://api.psrestful.com/extra/v2/subaccounts/" \
  -H "X-API-Key: your-api-key-here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "ACME Distributors",
    "external_customer_id": "mkf_client_789",
    "organization_contact_email": "admin@acme.com",
    "account_notes": "Enterprise customer - high volume"
  }'

Response: 201 Created

{
  "id": 456,
  "name": "ACME Distributors",
  "external_customer_id": "mkf_client_789",
  "organization_contact_name": null,
  "organization_contact_email": "admin@acme.com",
  "account_notes": "Enterprise customer - high volume",
  "is_active": true,
  "parent_account": null,
  "created_at": "2025-11-23T10:30:00Z",
  "modified_on": "2025-11-23T10:30:00Z",
  "created_by": "admin@yourplatform.com",
  "modified_by": "admin@yourplatform.com"
}

What’s Inherited from Parent:

  • selected_plan - Subscription plan level

Automatic Settings:

  • allow_sub_accounts = false (sub-accounts cannot create their own sub-accounts)
  • is_active = true

Errors:

  • 403 Forbidden - Parent account doesn’t have permission to create sub-accounts
  • 400 Bad Request - Duplicate external_customer_id within your sub-accounts
  • 400 Bad Request - Validation errors (missing required fields, invalid format)

3. Get Sub-Account Details

Retrieve details for a specific sub-account.

Endpoint:

GET /extra/v2/subaccounts/{sub_account_id}/

Permission: Parent account members OR sub-account members

Path Parameters:

ParameterTypeRequiredDescription
sub_account_idintegerYesSub-account ID

Example Request:

curl -X GET "https://api.psrestful.com/extra/v2/subaccounts/456/" \
  -H "X-API-Key: your-api-key-here"

Response: 200 OK

{
  "id": 456,
  "name": "ACME Distributors",
  "external_customer_id": "mkf_client_789",
  "organization_contact_name": null,
  "organization_contact_email": "admin@acme.com",
  "account_notes": "Enterprise customer - high volume",
  "is_active": true,
  "parent_account": {
    "id": 1,
    "name": "Your Platform Account"
  },
  "created_at": "2025-11-23T10:30:00Z",
  "modified_on": "2025-11-23T10:30:00Z",
  "created_by": "admin@yourplatform.com",
  "modified_by": "admin@yourplatform.com"
}

Errors:

  • 403 Forbidden - You don’t have access to this sub-account
  • 404 Not Found - Sub-account not found

4. Update Sub-Account

Update metadata for an existing sub-account.

Endpoint:

PATCH /extra/v2/subaccounts/{sub_account_id}/

Permission: Parent account members only (sub-account members cannot update)

Path Parameters:

ParameterTypeRequiredDescription
sub_account_idintegerYesSub-account ID

Request Body: (all fields optional)

FieldTypeMax LengthDescription
namestring255Sub-account display name
external_customer_idstring255Your internal customer ID
organization_contact_namestring255Contact person name
organization_contact_emailstring-Valid email address
account_notesstring-Internal notes

Example Request:

curl -X PATCH "https://api.psrestful.com/extra/v2/subaccounts/456/" \
  -H "X-API-Key: your-api-key-here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "ACME Distributors (Updated)",
    "account_notes": "Now our largest customer"
  }'

Response: 200 OK

Returns the updated sub-account object (same structure as create response).

Important:

  • Only metadata can be updated (not plan, parent relationship, or is_active)
  • modified_on timestamp is automatically updated
  • modified_by field is automatically set to current user or “API Key”

Errors:

  • 403 Forbidden - Only parent account members can update sub-accounts
  • 404 Not Found - Sub-account not found
  • 400 Bad Request - Duplicate external_customer_id

5. Delete Sub-Account

Soft delete a sub-account (sets is_active=false).

Endpoint:

DELETE /extra/v2/subaccounts/{sub_account_id}/

Permission: Parent account members only

Path Parameters:

ParameterTypeRequiredDescription
sub_account_idintegerYesSub-account ID

Example Request:

curl -X DELETE "https://api.psrestful.com/extra/v2/subaccounts/456/" \
  -H "X-API-Key: your-api-key-here"

Response: 204 No Content

Important:

  • This is a soft delete - data is retained
  • Sub-account is_active is set to false
  • API keys remain in database but should not be used
  • Can be retrieved with include_inactive=true query parameter
  • Cannot be undone via API (contact support to restore)

Errors:

  • 403 Forbidden - Only parent account members can delete sub-accounts
  • 404 Not Found - Sub-account not found

6. List Sub-Account API Keys

Retrieve all API keys for a sub-account.

Endpoint:

GET /extra/v2/subaccounts/{sub_account_id}/api-keys/

Permission: Parent account members OR sub-account members

Path Parameters:

ParameterTypeRequiredDescription
sub_account_idintegerYesSub-account ID

Query Parameters:

ParameterTypeRequiredDefaultDescription
include_parent_managedbooleanNotrueInclude keys created by parent account

Example Request:

curl -X GET "https://api.psrestful.com/extra/v2/subaccounts/456/api-keys/" \
  -H "X-API-Key: your-api-key-here"

Response: 200 OK

{
  "count": 2,
  "results": [
    {
      "key": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
      "active": true,
      "public": false,
      "managed_by_parent": true,
      "created_at": "2025-11-23T10:30:00Z",
      "created_by": "admin@yourplatform.com",
      "age_in_days": 7
    }
  ]
}

Response Fields:

FieldTypeDescription
keystring32-character hexadecimal API key
activebooleanWhether key is active
publicbooleanWhether this is a public API key
managed_by_parentbooleanTrue if created by parent account
created_atdatetimeISO 8601 timestamp
created_bystring/nullEmail of creator or “API Key”
age_in_daysintegerDays since creation

Errors:

  • 403 Forbidden - You don’t have access to this sub-account
  • 404 Not Found - Sub-account not found

7. Create API Key for Sub-Account

Generate a new API key for a sub-account.

Endpoint:

POST /extra/v2/subaccounts/{sub_account_id}/api-keys/

Permission: Parent account members OR sub-account members

Path Parameters:

ParameterTypeRequiredDescription
sub_account_idintegerYesSub-account ID

Request Body:

FieldTypeRequiredDefaultDescription
publicbooleanNofalseWhether this is a public API key

Example Request:

curl -X POST "https://api.psrestful.com/extra/v2/subaccounts/456/api-keys/" \
  -H "X-API-Key: your-api-key-here" \
  -H "Content-Type: application/json" \
  -d '{
    "public": false
  }'

Response: 201 Created

{
  "key": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
  "active": true,
  "public": false,
  "managed_by_parent": true,
  "created_at": "2025-11-23T10:30:00Z",
  "created_by": "admin@yourplatform.com",
  "age_in_days": 0
}

Important:

  • API keys are 32-character hexadecimal strings (cryptographically secure)
  • Keys are shown in plaintext only at creation - store them securely
  • managed_by_parent is automatically set:
    • true if created by parent account member
    • false if created by sub-account member
  • This flag determines deletion permissions (see endpoint 8)

Errors:

  • 403 Forbidden - You don’t have access to this sub-account
  • 404 Not Found - Sub-account not found

8. Delete API Key

Delete an API key for a sub-account.

Endpoint:

DELETE /extra/v2/subaccounts/{sub_account_id}/api-keys/{api_key}/

Permission: Depends on managed_by_parent flag (see below)

Path Parameters:

ParameterTypeRequiredDescription
sub_account_idintegerYesSub-account ID
api_keystringYesThe API key to delete (32-char hex string)

Example Request:

curl -X DELETE "https://api.psrestful.com/extra/v2/subaccounts/456/api-keys/a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6" \
  -H "X-API-Key: your-api-key-here"

Response: 204 No Content

Permission Rules:

API Key TypeWho Can Delete
managed_by_parent=trueOnly parent account members
managed_by_parent=falseParent account members OR sub-account members

Important:

  • This is a hard delete (permanently removes the key)
  • Deleted keys cannot be recovered
  • Applications using the deleted key will receive 403 Forbidden errors

Errors:

  • 403 Forbidden - You don’t have permission to delete this API key
  • 404 Not Found - API key not found

Permissions & Access Control

Permission Matrix

ActionParent Account MembersSub-Account Members
List sub-accounts✅ Yes (all)❌ No
Create sub-account✅ Yes❌ No
View sub-account✅ Yes✅ Yes (own only)
Update sub-account✅ Yes❌ No
Delete sub-account✅ Yes❌ No
List API keys✅ Yes✅ Yes (own only)
Create API key✅ Yes (managed_by_parent=true)✅ Yes (managed_by_parent=false)
Delete parent-managed key✅ Yes❌ No
Delete non-parent-managed key✅ Yes✅ Yes

Access Control Rules

Parent Account Members:

  • Full access to all sub-accounts
  • Can create, read, update, delete sub-accounts
  • Can manage all API keys (including parent-managed)

Sub-Account Members:

  • Access only to their own sub-account
  • Cannot modify sub-account metadata
  • Can create their own API keys (managed_by_parent=false)
  • Cannot delete parent-managed API keys

Business Rules

Sub-Account Creation Requirements

Your parent account must meet these requirements:

  1. Enterprise Plan

  2. Feature Enabled

    • allow_sub_accounts = true
    • Contact support to enable this feature
  3. Not a Sub-Account

    • Parent account cannot itself be a sub-account
    • No nested sub-accounts allowed

Validation Rules

  1. Unique External Customer ID

    • external_customer_id must be unique within your sub-accounts
    • Different parent accounts can reuse the same ID
    • Use this to map to your internal customer/client IDs
  2. Whitespace Trimming

    • Leading/trailing whitespace is automatically removed from:
      • name
      • external_customer_id
  3. Email Validation

    • organization_contact_email must be a valid email format

Inheritance Rules

Sub-accounts automatically inherit these fields from the parent:

FieldDescription
selected_planSubscription plan level (Free, Standard, Premium, Enterprise)

Sub-accounts cannot have:

FieldValueReason
allow_sub_accountsAlways falseNo nested sub-accounts

Rate Limiting

  • Sub-accounts inherit the parent’s selected_plan
  • Rate limits apply to each sub-account independently
  • Parent usage does NOT count against sub-account limits
  • Sub-account usage does NOT count against parent limits

Complete Integration Example

Scenario: Marketfuel Creates Sub-Account for Client

Step 1: Authenticate with Parent Account

# Store your parent account API key securely
PARENT_API_KEY="your-parent-account-api-key"

Step 2: Create Sub-Account

curl -X POST "https://api.psrestful.com/extra/v2/subaccounts/" \
  -H "X-API-Key: $PARENT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "ACME Distributors",
    "external_customer_id": "mkf_client_789",
    "organization_contact_email": "admin@acme.com",
    "account_notes": "Created via Marketfuel integration"
  }'

Response:

{
  "id": 456,
  "name": "ACME Distributors",
  "external_customer_id": "mkf_client_789",
  ...
}

Step 3: Generate API Key for Sub-Account

# Save the sub_account_id from step 2
SUB_ACCOUNT_ID=456
 
curl -X POST "https://api.psrestful.com/extra/v2/subaccounts/$SUB_ACCOUNT_ID/api-keys/" \
  -H "X-API-Key: $PARENT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "public": false
  }'

Response:

{
  "key": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
  "active": true,
  "public": false,
  "managed_by_parent": true,
  ...
}

Step 4: Store Mapping in Your Database

# Example: Store in your platform's database
marketfuel_clients = {
    "mkf_client_789": {
        "name": "ACME Distributors",
        "psrestful_sub_account_id": 456,
        "psrestful_api_key": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
    }
}

Step 5: Use Sub-Account API Key for PromoStandards Requests

# When ACME makes a request through Marketfuel,
# use their sub-account API key
 
SUB_ACCOUNT_API_KEY="a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
 
curl -X GET "https://api.psrestful.com/v2/products?supplier=pcna&productId=1234" \
  -H "X-API-Key: $SUB_ACCOUNT_API_KEY"

Result:

  • Request is authenticated as sub-account (id=456)
  • Usage is tracked under ACME’s sub-account
  • Rate limits apply to ACME’s sub-account independently

Error Handling

Error Response Format

All errors return JSON with a detail field:

{
  "detail": "Error message describing what went wrong"
}

HTTP Status Codes

CodeMeaningCommon Causes
200OKRequest succeeded
201CreatedResource created successfully
204No ContentDeletion succeeded (no response body)
400Bad RequestValidation error, duplicate external_customer_id
401UnauthorizedInvalid or missing authentication token
403ForbiddenAuthenticated but insufficient permissions
404Not FoundSub-account or API key not found
429Too Many RequestsRate limit exceeded

Common Errors and Solutions

Error: “Parent account doesn’t have permission to create sub-accounts”

HTTP Status: 403 Forbidden

Causes:

  • Parent account doesn’t have allow_sub_accounts=true
  • Parent account is not Premium/Enterprise plan
  • Parent account is itself a sub-account

Solution:

  • Upgrade to Premium or Enterprise plan
  • Contact support to enable sub-accounts feature
  • Ensure you’re using a parent account, not a sub-account

Error: “Sub-account with external_customer_id ‘xxx’ already exists”

HTTP Status: 400 Bad Request

Cause:

  • Another sub-account under the same parent already uses this external_customer_id

Solution:

  • Use unique IDs for each sub-account
  • Check existing sub-accounts: GET /extra/v2/subaccounts/
  • Update the ID or use a different identifier

Error: “You don’t have access to this sub-account”

HTTP Status: 403 Forbidden

Causes:

  • Using wrong API key (not parent or sub-account)
  • User is not a member of sub-account or parent account

Solution:

  • Verify you’re using the correct API key
  • Ensure API key belongs to parent account or the specific sub-account
  • Check sub-account ID is correct

Error: “Only parent account members can update sub-accounts”

HTTP Status: 403 Forbidden

Cause:

  • Attempting to update using sub-account credentials

Solution:

  • Use parent account API key or OAuth token
  • Sub-account members can only view, not modify

Error: “Only parent account can delete parent-managed API keys”

HTTP Status: 403 Forbidden

Cause:

  • Attempting to delete a managed_by_parent=true key without parent permissions

Solution:

  • Use parent account credentials to delete parent-managed keys
  • Sub-account members can only delete keys they created (managed_by_parent=false)

Best Practices

1. Managing External Customer IDs

Use Your Internal IDs:

{
  "external_customer_id": "your_platform_customer_id_123"
}

Benefits:

  • Easy mapping between your customers and sub-accounts
  • Quick lookups in your database
  • Consistent with your existing system

Example:

# Map your customer ID to sub-account
def get_psrestful_api_key(customer_id):
    mapping = database.query(
        "SELECT psrestful_api_key FROM customer_integrations "
        "WHERE customer_id = %s", customer_id
    )
    return mapping['psrestful_api_key']

2. API Key Security

Store Securely:

  • Never commit API keys to version control
  • Use environment variables or secure vaults (AWS Secrets Manager, HashiCorp Vault)
  • Encrypt keys in your database

Rotate Regularly:

# Example: Rotate API key
def rotate_api_key(sub_account_id, old_key):
    # Create new key
    new_key = create_api_key(sub_account_id)
 
    # Update your systems to use new key
    update_customer_api_key(customer_id, new_key)
 
    # Delete old key
    delete_api_key(sub_account_id, old_key)

Use HTTPS:

  • Always use HTTPS for API calls
  • Never send API keys over unencrypted connections

3. Handling Soft-Deleted Sub-Accounts

Check Active Status:

# Before using cached API key
sub_account = get_sub_account(sub_account_id)
if not sub_account['is_active']:
    raise Exception("Sub-account has been deleted")

Query with Include Inactive:

# Retrieve all sub-accounts including deleted
curl "https://api.psrestful.com/extra/v2/subaccounts/?include_inactive=true" \
  -H "X-API-Key: your-api-key"

4. Error Handling in Production

Implement Retry Logic:

import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry
 
def create_session():
    session = requests.Session()
    retry = Retry(
        total=3,
        backoff_factor=1,
        status_forcelist=[429, 500, 502, 503, 504]
    )
    adapter = HTTPAdapter(max_retries=retry)
    session.mount('https://', adapter)
    return session
 
# Use session for API calls
session = create_session()
response = session.get(
    "https://api.psrestful.com/extra/v2/subaccounts/",
    headers={"X-API-Key": api_key}
)

5. Monitoring and Logging

Track API Usage:

import logging
 
logger = logging.getLogger(__name__)
 
def track_api_call(customer_id, endpoint, status_code):
    logger.info(
        f"API call: customer={customer_id}, "
        f"endpoint={endpoint}, status={status_code}"
    )

Monitor Rate Limits:

  • Track 429 responses
  • Alert when approaching limits
  • Consider implementing client-side rate limiting

Frequently Asked Questions

Can sub-accounts create their own sub-accounts?

No. Sub-accounts always have allow_sub_accounts=false. Only parent accounts can create sub-accounts.

Can I change which account is the parent?

No. The parent-child relationship cannot be changed after creation. You would need to create a new sub-account under a different parent.

What happens to API keys when I delete a sub-account?

API keys remain in the database but should not be used. The sub-account is soft-deleted (is_active=false), and authentication with its API keys should be treated as invalid in your application.

Can I restore a deleted sub-account?

Deleted sub-accounts cannot be restored via API. Contact support if you need to restore a deleted sub-account.

How do I know if an API key was created by the parent or sub-account?

Check the managed_by_parent field when listing API keys. true means parent created it, false means sub-account created it.

Do sub-accounts have their own billing?

No. All usage across sub-accounts rolls up to the parent account for billing purposes.

Can I transfer ownership of a sub-account to another parent?

No. Sub-accounts cannot be transferred between parents. Create a new sub-account under the new parent.


Support

For additional help:


Last Updated: November 2025 API Version: v2