---
title: "Org Creation Fields"
slug: org-creation
section: Portals
group: Host Portal
status: stable
description: "Sponsor-side contract for capturing program-type-specific fields at Partner Organization creation, aligned with the Host Portal Camp Overview update contract"
last-updated: 2026-10-07
---

# Org Creation Fields

Sponsor-side contract for capturing program-type-specific fields at Partner Organization creation, aligned with the Host Portal Camp Overview update contract

> **Sibling to the Camp Overview update contract**
>
> This page specifies the sponsor-side create-org contract for program-type-specific fields. The matching update-time contract — GET / PATCH /api/partner/host/overview — is documented separately and uses the same direct-column vs. metadata JSONB split, the same merge-on-write / omit-unset-on-read convention, and the same camp-only field gating. The two contracts are designed to read as one bundle: whatever can be set at create time can also be edited later via PATCH, and nothing can be edited via PATCH that the create path does not understand.

## Scope & Purpose

When a sponsor creates a Partner Organization in Globus and links it to a program (e.g. a camp program), the create-org call must accept — and persist — the same program-type-specific field set that the Host Portal Camp Overview later exposes for editing. Without that, a camp org could only ever be filled in after creation, leaving the record partial and forcing sponsor staff to round-trip through the Host Portal for data they already had at creation. This page closes that gap and pins the program-model-type → field-set rule across the platform.

> **Pattern, then camp**
>
> This spec defines the pattern (program model type drives the extra field set) and fully specifies camp as the worked example. The other program model types (work & travel, teach, intern) reuse the same pattern but their concrete field sets are out of scope here and will be specced in follow-ups.

## Sponsor Org-Creation Flow

Sponsor staff create a Partner Organization through the Globus admin UI (or the equivalent API). The flow has three phases for the purposes of this spec:

### Program Selection → Program Model Type

Brand + Program + Season uniquely identifies a Program Register entry. Each program in the register carries a programModelType (camp, work & travel, teach, intern) — see Program Register &rarr; Program Identity & Metadata . The selected program model type is the single input that decides which program-type-specific fields the create form must collect.

### Program Model Type → Field Set Rule

> **One model type, one field set**
>
> Each program model type owns exactly one create-time field set. Camp owns the camp field set below. Other model types own their own sets (out of scope here). A partner organization created against a camp program must only accept the camp field set, and a partner organization created against a non-camp program must reject the camp-only metadata keys with a 422 validation error (see Camp-Only Field Gating). This is the same gating rule the PATCH overview contract enforces on the update side.

### Account Manager (Optional)

Sponsor staff may optionally pick an Account Manager (AM) at create time. The field is nullable; leaving it blank creates the org in the Unassigned state — no audit row, no history-ledger row, no notification — identical to today's post-create flow when no AM is chosen. Picking an AM at create time fires the same downstream side effects as the post-create assignment path, so a sponsor doesn't need to round-trip through the host-management surface for an org whose AM is already known.

Persisted Columns

- partner_organizations.account_manager_user_id — nullable FK to the chosen staff user.
- partner_organizations.account_manager_assigned_at — timestamp stamped when the AM was set.
- An append-only host_organization_assignment_history row capturing the initial assignment, written in the same transaction as the org row.
> **Side effects when an AM is set at creation**
>
> Choosing an AM at create time fires exactly the same downstream side effects as the post-create assignment path: Writes an audit row host_organization.account_manager.assigned against entityType: host_organization, paired with the history-ledger row above. Fires the staff-targeted in-app notification host.account_manager_assigned to the newly-assigned AM, post-commit. Leaving accountManagerUserId unset at creation writes no assignment audit row, no history-ledger row, and no notification — the org enters Unassigned and waits for a later assignment. AM is orthogonal to the contact-person block: an AM is a Globus staff user, the contact person belongs to the host org.

Source of truth for the AM data model, state machine (Unassigned / Assigned / Reassigned), audit vocabulary, notification, and Parent/Children inheritance carve-out: Host Governance &rarr; Host Account Manager Assignment . Nothing in this section overrides that model — the create path simply reuses it.

### Contact Person (Captured at Creation)

Every host org must be created with a primary contact person. This is a required four-field block at creation — sponsor staff cannot defer it to a later Host Portal session because the contact is what makes the new org reachable for verification, agreement issuance, and the first host-user invitation. The fields persist into the host contacts directory as the primary contact for the org — not a new table; see the existing host contacts spec.

| API Field | Required at Creation? | Notes |
| --- | --- | --- |
| contactName | | Full name of the primary contact at the host org. |
| contactEmail | | Syntactically valid email. Used by sponsor staff for outreach and as the default invite address for the first host-user invitation. |
| contactPhone | | Free-form phone string. Trimmed; empty/whitespace-only rejected. |
| contactTitle | | Role or job title at the host org (e.g. Camp Director, Owner, Operations Manager). |

Persistence: the four fields write through to the existing host contacts directory as the org's primary contact row (no new table is introduced). Hosts can add additional contacts post-creation via the Host Portal Contacts surface; only the primary contact is collected at create time, and it cannot be left blank. The contact person is independent of any Account Manager (sponsor staff user) and any future host-portal user accounts the contact may later be invited to.

> **Creation-time emails share the agreement-derived branding rule**
>
> The emails the create flow triggers — host.profile_created to the host admin and the first host.user_invited to the auto-provisioned admin — resolve their brand through the same server-side rule as every later host email: the host's applicable host agreement's Agreement Library brand scope (see Notification Model → Agreement-Derived Brand Resolution (Wild Packs)). When a Wild Packs agreement is already applicable at first send, those emails render under Wild Packs branding. When no host agreement exists yet at enqueue time, the resolver records a default-fallback brand decision (using the correct existing brand context, never guessing Wild Packs) on the outbox row; later sends re-resolve per enqueue once the agreement is in place. The create-time Brand + Program + Season selection does not itself select email branding.

## Parent Organization (Optional)

Host organizations may belong to a parent organization — e.g. a camp group that owns several camps, or an employer HQ that owns several site locations. This step is offered between Identity & Scope and the Program-Type Field Set. It is always optional; the vast majority of host orgs have no parent. See Partner Organizations &rarr; Parent / Child Hierarchy for the data model, single-level rule, and audit events.

### Parent Picker & What Gets Recorded

active
### Governance Inheritance at Creation

> **Inheritance is per-field and opt-in — never automatic**
>
> Linking a parent does not inherit anything by itself. For each inheritable field, the child carries an explicit boolean toggle. With the toggle off (the default) the child uses its own value. With the toggle on, the child reads through to the parent’s live value and the child’s local value is treated as overridden. Per-field toggle semantics, snapshot-on-disable behavior, and the full audit event set live in Partner Organizations &rarr; Inheritance Surfacing on Existing Panels .

The optional governanceInheritance object accepted at creation has a fixed shape:

`governanceInheritance: s active operating agreement contacts: boolean, // inherit the parent` 
Any flag may be set independently. Omitting the object is identical to . Unknown keys are rejected (see validation below). Setting any flag to true requires parentOrganizationId to be set in the same request; setting a flag whose corresponding source on the parent is empty (e.g. agreement: true when the parent has no active operating agreement) is rejected.

### Parent-Link Validation Errors

The create-org endpoint validates the parent and inheritance fields before persisting and returns 422 Unprocessable Entity with a per-field error envelope on failure.

| Error Code | Trigger |
| --- | --- |
| parent_organization_not_found | parentOrganizationId references no existing partner_organizations row. |
| parent_organization_is_self | parentOrganizationId equals the org being created (always impossible at create-time because the new id is server-assigned, but documented here so the same rule on PATCH covers the change-parent flow). |
| parent_organization_has_parent | Referenced parent has its own parent_organization_id set — the single-level (max depth 1) hierarchy rule is violated. |
| governance_inheritance_requires_parent | Any governanceInheritance flag set to true without parentOrganizationId in the same payload. |
| governance_inheritance_unknown_key | governanceInheritance object contains a key that is not agreement, contacts, or documents. |
| governance_inheritance_parent_field_empty | A flag is true but the corresponding source on the parent is empty (e.g. agreement: true with no active operating agreement on the parent). |

> **Route correction.** The create endpoint is `POST /api/admin/partners/organizations` (plural `partners`, then `organizations`). Earlier revisions of this page wrote `POST /api/admin/partner-organizations`, which is **not** a registered route — the only endpoint under that prefix is `POST /api/admin/partner-organizations/:id/activate` (`server/routes/adminPartnerOrgActivation.ts`), which is the separate activation gate, not the create call.

Example Request (Parent-Linked, Camp)

`POST /api/admin/partners/organizations name / Camp Pinecrest — North Site / address / 12 Pine Ridge Rd / city / Bethel / state / ME / postalCode / 04217 / country / US / brandId / programId / seasonId / contactName / Dana Whitfield / contactEmail / dana@pinecrest.example / contactPhone / +1-207-555-0142 / contactRole / Camp Director / accountManagerUserId / parentOrganizationId / governanceInheritance` 
Example Response (201)

`id / status / pending_verification / parentOrganizationId / governanceInheritance` 
## Camp Field Set

For programModelType = "camp", the create-org call accepts the field set below. The split between direct columns on partner_organizations and the metadata JSONB column is identical to the Camp Overview update contract.

### Direct Columns on partner_organizations

| API Field | Required at Creation? | Notes |
| --- | --- | --- |
| field | | notes |

_(row above is a template, repeated for each data row)_

### Metadata JSONB Fields

These fields are camp-specific and live inside the metadata JSONB column on partner_organizations. Globus merges them into the API response so they appear as flat, top-level fields on the Host Portal Camp Overview — the create-org call accepts them at the same top level.

| API Field | Required at Creation? | Notes |
| --- | --- | --- |
| field | | notes |

_(row above is a template, repeated for each data row)_

### Legacy-Value Backfill (Historical)

> **Backfill script (one-shot reconciler)**
>
> A one-shot reconciler, `server/scripts/reconcileCampMetadataEnums.ts`, audits camp hosts' campType and campStyle values against the enums above, maps non-conforming values to the closest allowed value and, only with `--apply`, writes the mapped values back to `partner_organizations.metadata`; unmappable rows are flagged for manual review and left untouched. It is a dry run by default and writes no audit entry. The script is still in the repo, and the API boundary rejects legacy values at write time — the mapping tables below are kept as historical reference for what was rewritten.

campType mapping

| Legacy value | New value |
| --- | --- |
| residential / resident / sleepaway | Overnight |
| day / daycamp | Day |
| mixed / hybrid / combined / both | Both |

Case-insensitive; values already inside the enum pass through unchanged.

campStyle mapping (free-text → array)

| Legacy value | New value |
| --- | --- |
| traditional / classic | Traditional |
| boys / all-boys | All-Boys |
| girls / all-girls | All-Girls |
| coed / co-ed / mixed | Co-Ed |
| lgbtq / lgbtq+ / inclusive | LGBTQ+ Inclusive |
| rustic / wilderness / outdoor | Rustic |
| nonprofit / not-for-profit | Non-profit |
| religious / faith / faith-based / christian / jewish / catholic | Religious Affiliation |
| special-needs / adaptive / therapeutic | Special Needs |

Legacy single strings split on , ; | / then mapped element-wise; duplicates collapsed.

### Required at Creation vs. Deferrable

The agreed minimum field set at creation is seven items: org name, the linked Program (already required via Identity & Scope), the primary address (street + city + state + postalCode + country), and the four Contact Person fields. Everything else — including irsEinNumber, accountManagerUserId, and every Camp metadata field — is optional at creation.

Required at creation (7)

name / program (via Identity & Scope) / address (street + city + state + postalCode + country) / contactName / contactEmail / contactPhone / contactRole
These are the minimum identity + locatability + contactability fields needed to land the org in Pending Verification.

Optional at creation

irsEinNumber (deferrable; pre-activation gate unchanged) / accountManagerUserId (deferrable; assigned later via the host-management surface) / description / yearEstablished / website / capacity / every Camp metadata field (camperAgeRange, seasonDates, accreditation, video, campType, campStyle, J-1 counts, staff training, background checks, etc.)
Sponsor staff can leave these empty at creation; the host (or sponsor) fills them in via PATCH /api/partner/host/overview or the dedicated sponsor-side surfaces. Activation gate: irsEinNumber can be deferred at creation but must be present before the host org can move from pending_verification to active — see Host Governance &rarr; Pending Verification &rarr; Active Transition .

## JSONB Conventions (Create + PATCH)

> **Identical to the PATCH overview contract**
>
> The four conventions below apply identically to the create-org call and to PATCH /api/partner/host/overview. Anything that holds for one holds for the other.

### Merge-on-Write

On create, only the metadata keys explicitly supplied in the request body are written into the metadata JSONB column. Globus must not populate unset metadata keys with null placeholders — an unset key is absent from the JSONB document, not stored as null. On subsequent PATCHes the same merge-on-write rule applies, so partial updates never wipe unrelated metadata fields.

### Omit-Unset-on-Read

On GET /api/partner/host/overview, unset metadata fields are omitted from the response — they are not returned as null. This keeps the response shape clean and prevents the Host Portal from rendering stale or placeholder values for fields the org has never set.

### Unrecognized Fields Ignored (Forward-Compat Only)

Any field in the create-org request body that is completely unknown to the system (i.e. not a direct column and not in the registered metadata vocabulary for any program model type) is silently ignored. Recognized-but-not-applicable keys — metadata keys defined for another program model type — are rejected, not ignored; see Camp-Only Field Gating for the exact rule. This mirrors the PATCH overview rule and protects forward compatibility: clients that send fields a future model type adds will not break against an older Globus version.

### Camp-Only Field Gating

> **Camp-only metadata keys are camp-only — rejected on non-camp**
>
> Every metadata JSONB key listed in the Metadata JSONB Fields table above — camperAgeRange, seasonDates, accreditation, videoEmbedCode, campType, campStyle, numberOfJ1Counselors, numberOfJ1SupportStaff, minMaxAgeForCounselors, staffTraining, and backgroundChecks — is only meaningful for programModelType = "camp". For non-camp model types these keys are rejected on both create and PATCH with a 422 Unprocessable Entity validation error citing each offending key — they are never written to metadata. This mirrors the PATCH overview rule from the Host Portal Camp Overview spec (#177) and gives a single unambiguous, testable contract on both surfaces.

Distinction vs. fully-unknown keys: a key the system has never heard of (e.g. a future field added by a newer client) is silently ignored per the rule above; a recognized key that is not applicable to the selected program model type (e.g. campType on a Work & Travel org) is rejected. Forward compatibility is preserved; cross-model contamination is not.

## Validation Rules (Shared with PATCH)

These validation rules apply to whichever fields are supplied at creation; deferred fields are not validated until they are first set. The same rules apply to PATCH /api/partner/host/overview so that a value rejected at create time would also be rejected via PATCH.

| Field | Rule |
| --- | --- |
| field | rule |

_(row above is a template, repeated for each data row)_

## Audit & Event Behavior at Creation

### Org-Created Event & Audit

On successful creation, Globus writes:

### host.profile_created Interaction

> **Creation with description + website does NOT fire host.profile_created**
>
> The host.profile_created event defined for the Camp Overview update contract fires only on the first PATCH that transitions both description and website from empty to set. Creating an org with both populated at create time does not count as that transition: the create path records the partner.organization.created audit entry (and no host.profile_created audit record). This keeps host.profile_created as an unambiguous “the host first completed their profile” signal and avoids firing it twice for the same org. If both fields are deferred at creation and later filled in via a single PATCH, that PATCH fires host.profile_created per the Camp Overview contract.

## Open Questions

The following items could not be resolved purely from the source inputs and need a sponsor product decision before Globant implements:

s narrative camp season window and is not the same as the Globus Season record
## FAQ

## Cross-References
