SMAO API Documentation
Organizations

Create organization and initial owner invitation

Creates a new customer organization under the specified partner (MSP), creates its owner invitation record, and attempts to send the invitation email.

What happens:

  1. The organization is created with the selected plan and linked to the partner via partnerId.
  2. The organization is marked as partner-managed - no Stripe billing is set up for the customer.
  3. An invitation record is created for owner.email. Email delivery is best-effort.
  4. Once the owner accepts, they have full product access but cannot manage billing or subscriptions.

The externalCustomerId must be unique across all your organizations (not just per partner).

POST
/organizations
AuthorizationBearer <token>

Long-lived distributor API key scoped to a channel partner on the shared smao instance.

In: header

organization
owner
externalCustomerIdstring

Your unique customer identifier on the distributor side.

Length1 <= length <= 255
externalContractId?string|null

Optional contract identifier on the distributor side.

Lengthlength <= 255
partnerIdstring

ID of the partner (MSP) this organization belongs to. Must reference an active partner.

Match^[a-fA-F0-9]{24}$
plan

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X POST "https://api.smao.ai/api/distributor/v1/organizations" \  -H "Content-Type: application/json" \  -d '{    "organization": {      "name": "Acme GmbH",      "timezone": "Europe/Berlin"    },    "owner": {      "email": "[email protected]",      "firstName": "Alice",      "lastName": "Müller"    },    "externalCustomerId": "SYN-4711",    "partnerId": "665abc123def456789012345",    "plan": {      "slug": "advanced",      "commitment": "monthly"    }  }'
{
  "status": "success",
  "organization": {
    "id": "69c175970f3e28310926a1aa",
    "name": "Acme GmbH",
    "industry": "IT Services",
    "timezone": "Europe/Berlin",
    "channelPartner": "acme",
    "externalCustomerId": "SYN-4711",
    "externalContractId": "CON-2026-0001",
    "partnerId": "665abc123def456789012345",
    "ownerEmail": "[email protected]",
    "createdAt": "2026-03-23T17:17:11.605Z",
    "plan": {
      "id": "6967b1c7138bed3e7f6bf7e6",
      "slug": "advanced",
      "name": "Advanced",
      "commitment": "monthly",
      "currency": "EUR",
      "baseFee": 6900
    }
  },
  "owner": {
    "email": "[email protected]",
    "firstName": "Alice",
    "lastName": "Müller",
    "role": "admin",
    "status": "invited",
    "source": "distributor-api",
    "invitationId": "69c175970f3e28310926a1bb",
    "expiresAt": "2026-03-30T17:17:11.814Z"
  }
}
{
  "status": "error",
  "errorCode": "INVALID_DATE_RANGE",
  "message": "from and to must be valid YYYY-MM-DD values"
}
{
  "status": "error",
  "errorCode": "INVALID_DATE_RANGE",
  "message": "from and to must be valid YYYY-MM-DD values"
}
{
  "status": "error",
  "errorCode": "INVALID_DATE_RANGE",
  "message": "from and to must be valid YYYY-MM-DD values"
}
{
  "status": "error",
  "errorCode": "INVALID_DATE_RANGE",
  "message": "from and to must be valid YYYY-MM-DD values"
}

{
  "status": "error",
  "errorCode": "RATE_LIMITED",
  "message": "Too many requests for this API key."
}
{
  "status": "error",
  "errorCode": "INVALID_DATE_RANGE",
  "message": "from and to must be valid YYYY-MM-DD values"
}

{
  "status": "error",
  "errorCode": "RATE_LIMIT_UNAVAILABLE",
  "message": "Rate limit storage is unavailable. Try again shortly."
}