Updating member dates, type, and chapter via business flows
Updating restricted Party properties via the iMIS REST API
Several PartyData.AdditionalAttributes values — JoinDate, PaidThruDate, RenewedThruDate, CustomerTypeCode, and Chapter — cannot be written through the /api/Party endpoint by an external, non-privileged caller. Attempts to set them through AdditionalAttributes return a validation error stating that updating those fields via the API requires staff or system administrator permissions. Same-value writes — where the supplied value matches the currently-persisted value — are short-circuited and never trigger the block, so round-trip GET → modify-other-fields → PUT calls are safe.
These fields can still be updated through their natural business flows: purchasing a dues subscription, assigning a chapter through group membership, or generating a renewal run. The end result on the party record is identical — the path is the one iMIS expects for these changes.
Subscription-based products cannot be added to a cart directly. They must be purchased through a billing cycle. The cart receives the purchase via a three-tier order-line structure. See Purchasing non-dues subscriptions for more information.
This guide lists each flow, the endpoints it uses, the request shapes you need, and the fields that change as a side effect.
Which property → which flow
| Property | Recommended flow |
|---|---|
JoinDate | Join Now workflow (typically the iMIS Join Now iPart) or dues-import package — Flow 4 |
PaidThruDate | Subscription purchase + invoice payment, renewal-run + invoice payment, or dues-import package — Flows 1, 3, 4 |
RenewedThruDate | Subscription purchase, renewal run, or dues-import package — Flows 1, 3, 4 |
CustomerTypeCode | Join Now workflow under a membership-based billing cycle (iMIS Join Now iPart) |
Chapter | Group-membership add under a chapter group — Flow 2 |
Flow 1 — Adding and billing a subscription
Use this flow to add a subscription product to an existing party and bill them for it. This is the simpler of the two purchase-style flows — a single POST creates the subscription, advances its term, and creates an invoice in one call. The invoice can then be paid through any normal channel (the iMIS UI, a cart-payment iPart, or your own integration).
For full enrollment of a brand-new member where you also need JoinDate / CustomerTypeCode to be set automatically, see the iMIS Join Now workflow — that path runs through the cart with a three-tier order line into a membership-based billing cycle and is documented in Adding, modifying, and paying for a subscription and Purchasing non-dues subscriptions. It is out of scope here because the partner audience for that flow is typically the Join Now iPart, not a back-office integration.
Endpoints
| Endpoint | Method | Purpose |
|---|---|---|
/api/Subscription | POST | Create a subscription with BillSubscription: true; returns the new InvoiceId |
/api/InvoiceSummary/{InvoiceId} | GET | Read the resulting invoice |
/api/ComboOrder | POST | Pay the invoice by submitting a ComboOrder that references it |
Step 1 — Create and bill the subscription
POST /api/Subscription
Content-Type: application/json
{
"$type": "Asi.Soa.Commerce.DataContracts.SubscriptionData, Asi.Contracts",
"PartyId": "12345",
"ItemId": "REG",
"BeginDate": "2026-01-01T00:00:00",
"BillToPartyId": "12345",
"BillSubscription": true
}The response is 201 Created and includes the newly-created subscription. Capture:
InvoiceId— the invoice generated for the billBillBegin/BillThrough— the new termBilledAmount— invoice total
Step 2 — Read the resulting invoice
GET /api/InvoiceSummary/{InvoiceId}You'll send the full response back as part of the next step's Invoices collection.
Step 3 — Pay the invoice by submitting a ComboOrder
Submit a ComboOrderData that references the existing invoice. The Order itself has no lines — the work is the payment application against the invoice already on file. The response is 201 Created with the populated ComboOrder.
POST /api/ComboOrder
Content-Type: application/json
{
"$type": "Asi.Soa.Commerce.DataContracts.ComboOrderData, Asi.Contracts",
"Currency": { "$type": "Asi.Soa.Core.DataContracts.CurrencyData, Asi.Contracts", "CurrencyCode": "USD", "DecimalPositions": 2 },
"Order": {
"$type": "Asi.Soa.Commerce.DataContracts.OrderData, Asi.Contracts",
"BillToCustomerParty": { "$type": "Asi.Soa.Commerce.DataContracts.CustomerPartyData, Asi.Contracts", "PartyId": "12345" },
"OriginatorCustomerParty": { "$type": "Asi.Soa.Commerce.DataContracts.CustomerPartyData, Asi.Contracts", "PartyId": "12345" },
"SoldToCustomerParty": { "$type": "Asi.Soa.Commerce.DataContracts.CustomerPartyData, Asi.Contracts", "PartyId": "12345" },
"Currency": { "$type": "Asi.Soa.Core.DataContracts.CurrencyData, Asi.Contracts", "CurrencyCode": "USD", "DecimalPositions": 2 },
"Lines": { "$type": "Asi.Soa.Commerce.DataContracts.OrderLineDataCollection, Asi.Contracts", "$values": [] },
"Delivery": { "$type": "Asi.Soa.Commerce.DataContracts.DeliveryDataCollection, Asi.Contracts", "$values": [] }
},
"Invoices": {
"$type": "Asi.Soa.Commerce.DataContracts.InvoiceSummaryDataCollection, Asi.Contracts",
"$values": [ /* InvoiceSummaryData from step 2 */ ]
},
"Payments": {
"$type": "Asi.Soa.Commerce.DataContracts.RemittanceDataCollection, Asi.Contracts",
"$values": [
{
"$type": "Asi.Soa.Commerce.DataContracts.RemittanceData, Asi.Contracts",
"Amount": {
"$type": "Asi.Soa.Core.DataContracts.MonetaryAmountData, Asi.Contracts",
"Amount": 95,
"Currency": { "$type": "Asi.Soa.Core.DataContracts.CurrencyData, Asi.Contracts", "CurrencyCode": "USD", "DecimalPositions": 2 },
"IsAmountDefined": true
},
"PaymentMethod": { "$type": "Asi.Soa.Commerce.DataContracts.PaymentMethodData, Asi.Contracts", "PaymentMethodId": "CASH", "PaymentType": "Cash" },
"PayorParty": { "$type": "Asi.Soa.Commerce.DataContracts.CustomerPartyData, Asi.Contracts", "PartyId": "12345" },
"ReferenceNumber": "12345"
}
]
}
}
Notes:
Order.Linesis intentionally empty — there's nothing new being bought, you're paying for an invoice that already exists.PaymentMethodonly needsPaymentMethodIdandPaymentType. The tenant's PaymentMethod record (for example,CASH→ Main Checking Account) is resolved from those.ReferenceNumberis intended for a check number or short payment reference.- For a cart-flavored workflow that buys a new item and pays at submit, see Adding, modifying, and paying for a subscription — that path > goes through
POST /api/Cart+POST /api/Cart/_executewith aCartSubmissionRequest, not the simpler ComboOrder POST shown here.
Side effects on the party
When the subscription is created and billed (step 1):
- The party gains a new
Subscriptionrow withBillBegin/BillThroughset to the new term. - An invoice is created for the billed amount.
When the invoice is paid (step 3 returns 201):
- The invoice balance clears.
- The corresponding subscription's
PaidThruadvances to itsBillThrough. - For billable customer types (for example,
M), the party'sPaidThruDateadvances to the subscription'sBillThrough, andRenewedThruDateis updated by the renewal accounting. Non-billable customer types (staff, sysadmin, etc.) won't see these contact-level dates change — subscription-level dates still advance. PaidThruDateandRenewedThruDateonly update when the subscription is the contact's primary fee product for their customer type. A non-primary item (such as a journal or publication) advances its own subscription term but does not move the contact-level date fields.
Flow 2 — Assigning a chapter via group membership
Use this flow to set the party's chapter. Chapter is updated by creating a GroupMember under a group whose GroupId follows the chapter convention (CHAPT/<chapterCode>).
The update has two important rules:
- On add,
Chapteris set only if it is currently empty. - On remove,
Chapteris cleared only if it currently matches the chapter being removed (so removing a non-current chapter membership is a no-op on this field).
Endpoints
| Endpoint | Method | Purpose |
|---|---|---|
/api/GroupMember | POST | Add the party to the chapter group |
/api/GroupMember?EntityId={GroupMemberId} | DELETE | Remove the party from the chapter group |
Add a party to a chapter group
POST /api/GroupMember
Content-Type: application/json
{
"$type": "Asi.Soa.Membership.DataContracts.GroupMemberData, Asi.Contracts",
"Party": {
"$type": "Asi.Soa.Membership.DataContracts.PartySummaryData, Asi.Contracts",
"PartyId": "12345"
},
"Group": {
"$type": "Asi.Soa.Membership.DataContracts.GroupSummaryData, Asi.Contracts",
"GroupId": "CHAPT/EAST"
},
"JoinDate": "2026-01-01T00:00:00",
"IsActive": true,
"MembershipDetails": {
"$type": "Asi.Soa.Membership.DataContracts.GroupMemberDetailDataCollection, Asi.Contracts",
"$values": [
{
"$type": "Asi.Soa.Membership.DataContracts.GroupMemberDetailData, Asi.Contracts",
"Role": {
"$type": "Asi.Soa.Membership.DataContracts.GroupRoleData, Asi.Contracts",
"RoleId": "SUBSCRIPTION:MEMBER"
},
"IsActive": true
}
]
}
}The GroupMember schema is defined in Membership.json under #/definitions/GroupMemberData. Response is 201 Created; the returned GroupMemberId follows the format {GroupId}:{PartyId} (for example, CHAPT/EAST:12345).
Remove a party from a chapter group
The composite GroupMemberId contains both / and :, which the server's URL routing rejects when supplied as part of the path. Pass the identifier as the EntityId query parameter instead:
DELETE /api/GroupMember?EntityId=CHAPT/EAST:12345Side effects on the party
Chapter← the chapter code from the second segment ofGroupId(for example,CHAPT/EAST→EAST).- A corresponding chapter
Subscriptionis created or updated as part of the same operation.
Flow 3 — Generating renewals
Use this flow to bill an existing member for the next term. This is the documented "Generating renewals" path (see Generating renewals) and is what updates RenewedThruDate and (after invoice payment) PaidThruDate for an existing member without going through the cart.
Endpoint
| Endpoint | Method | Purpose |
|---|---|---|
/api/LegacyBillingCycle/{LegacyBillingCycleId} | GET | Look up the billing cycle |
/api/LegacyBilling/_execute | POST | RunIndividual (single party) or Run (bulk) |
Note:
/api/LegacyBilling/_executeis referenced in the developer docs but is not currently published in the OpenAPI swagger. Treat the Generating renewals doc as the source of truth for its general request shape, with the parameter conventions below.
Request shape
/api/LegacyBilling/_execute accepts a GenericExecuteRequest whose Parameters is a positional Collection<object>, not a GenericPropertyDataCollection of named pairs. For RunIndividual the positions are:
[0]— theLegacyBillingDatarequest object[1]— the user/party id (string)
POST /api/LegacyBilling/_execute
Content-Type: application/json
{
"$type": "Asi.Soa.Core.DataContracts.GenericExecuteRequest, Asi.Contracts",
"EntityTypeName": "LegacyBilling",
"OperationName": "RunIndividual",
"Parameters": {
"$type": "System.Collections.ObjectModel.Collection`1[[System.Object, mscorlib]], mscorlib",
"$values": [
{
"$type": "Asi.Soa.Commerce.DataContracts.LegacyBillingData, Asi.Contracts",
"IsRenewal": true,
"RunDate": "2026-01-01T00:00:00",
"EffectiveDate": "2026-01-01T00:00:00",
"BillingCycleId": "Regular Membership Fees",
"BillingRunName": "Renewal — 2026 — Party 12345"
},
"12345"
]
}
}Bulk renewal
Use "OperationName": "Run" with a single Parameters entry — only the LegacyBillingData object — to bill every party eligible for the cycle. Omit the second positional string.
Batch posting
When IndividualBillingPartyId (the trailing string parameter) is supplied, hot-posting behavior for the resulting accounting batch is controlled by the Membership setting "Do not require posting batch for single-member renewals". When that setting is enabled, the batch posts automatically as part of the call and no separate /api/BatchSummary/_execute Post step is required. If the setting is off and you still want automatic hot-posting for an individual run, set UseSelectedAccountingBatch: true on the LegacyBillingCycleData object passed in the request. Bulk runs always produce a batch that must be posted separately via BatchSummary.
Side effects on the party
Once the renewal run completes successfully:
RenewedThruDate← the primary subscription's new bill-through date.- The party's
Subscriptionrows haveBillBegin/BillThroughadvanced to the next term. - An invoice is created for the renewed-term balance.
After the invoice is paid:
PaidThruDate← the subscription's bill-through date.
JoinDate is not changed by a renewal — it is set on the initial purchase.
Flow 4 — Dues-import package
Use this flow when you have an external system of record (legacy back office, third-party CRM, batch dues file) and need to apply per-party paid-through dates directly. The full request shape, async polling pattern (GetPackageStatus / GetPackageResults), batch handling, and validation rules are documented separately — this section only summarizes how the flow relates to the restricted Party properties.
See Importing billing and payment data for the full request bodies, field constraints, and status-enum values.
Endpoint
| Endpoint | Method | Purpose |
|---|---|---|
/api/DuesImportPackage/_execute | POST | ImportPackage, GetPackageStatus, GetPackageResults |
Side effects on the party
Once a package finishes processing (status advances AwaitProcessing → InProcess → Completed):
PaidThruDate←PaidThruDatesupplied on the import row.RenewedThruDate← bill-through date of the subscription created or extended by the import.JoinDate← set on first-time members based on the item's billing options.
Choosing a flow
| Goal | Use |
|---|---|
| Enroll a new member or sell an additional dues product | Flow 1 (Add subscription, Retrieve invoice, Submit ComboOrder) |
| Assign or remove a chapter for a contact | Flow 2 (GroupMember under a CHAPT/... group) |
| Bill an existing member's next term as part of a scheduled run | Flow 3 (LegacyBilling) |
| Bulk-load paid-through dates from an external system of record | Flow 4 (DuesImportPackage) |
Updated 2 days ago
