Errors & Reason Codes

The refusals a private markets integration has to handle, what each one means, and what the investor should do about it.

📘

Integrating through Apex AscendOS?

The product guidance on this page applies to you. The endpoints, fields and statuses are Monark's; use the AscendOS equivalents listed in Building on Apex AscendOS.

Most of what goes wrong in a private markets integration is not a bug — it is a business rule refusing a subscription for a reason the investor can act on. This page lists those refusals with their verbatim messages, so you can recognise them and say something useful rather than showing a generic error.

How Errors Are Returned

The private markets API returns a plain RFC 7807 problem response carrying an HTTP status and a human-readable message, and nothing else:

{
  "detail": "Investment amount is lower than the minimum commitment amount. Min amount - 25000",
  "status": 400
}

Important: The private markets endpoints carry no machine-readable reason code. There is no reasonCode or statusReasonCode field to switch on. The HTTP status and the detail string are all you get, which is why the messages below are quoted verbatim — they are what your code has to recognise.

Show the message to the investor. It names the specific limit that was hit, and most of them are correctable without anyone contacting support.

Branch on the response body, not only on the HTTP status code. A 201 from a create endpoint means the request was processed; always read the body back.

Creating a Transaction

Request shape

These are caught before any business rule runs. They indicate a bug in your integration, not an investor problem.

MessageCause
Specify exactly one of InvestorId or AccountId.Both were sent, or neither. They are mutually exclusive.
ExternalAccountNumber can only be used with InvestorId.externalAccountNumber was sent alongside accountId.
Must exclusively specify either Amount Shares or Amount Reserved Dollars.Both were sent, or neither.
Amount Reserved Dollars is required when Side is SubscriptionA subscription was sent without a dollar amount.
Transfer Direction can only be specified when Side is TransfertransferDirection must be null on every other side.
Side Transfer is only supported for RegisteredFund target asset type.Transfers do not apply to SPVs.
Only Subscription orders are currently supported. Side '<side>' is not supported.An SPV transaction used a side other than Subscription. SPV positions cannot be redeemed.

Field limits that will also refuse the request: amountReservedDollars must be greater than zero with at most 2 decimal places; amountShares greater than zero with at most 6 decimal places; referenceId and externalAccountNumber at most 100 characters.

Business rules

These are the ones your UI should anticipate and explain.

MessageWhat it meansWhat the investor should do
Investment amount is lower than the minimum commitment amount. Min amount - <amount>Below the SPV's minCommitmentAmount, and more than the minimum still remains unallocatedIncrease the amount to at least the minimum
Investment amount is lower than the minimum commitment amount and not equal to the remaining dollar allocation. Remaining - <amount>Less than the minimum is left in the raise, so the last investor has to take exactly what remainsEnter exactly the remaining allocation
Investment amount is greater than the remaining dollar allocation. Remaining - <amount>The raise cannot absorb the amountReduce the amount to the remaining allocation or below
No seats remaining for the SPV.The SPV has reached its 99-investor limit. It can be seat-closed while dollars remainNothing — the offering is closed to new investors. Show it as closed, not as an error

Validate the first three in your own UI before submitting, using minCommitmentAmount and remainingDollarAllocation from the SPV. The seat limit can be anticipated from numberOfSeatsRemaining, but treat the response as authoritative.

Important: These rules are checked twice — once when the transaction is created, and again when its last action completes and the subscription is signed. A pending transaction consumes no allocation and no seat, so a subscription that was accepted at create time can still be refused on the way to Processing if another investor filled the raise first. Handle a late failure, not only an immediate one: the transaction will land in Failed, and the cash you reserved has to be released.

Accreditation

A transaction is refused where the investor's accreditation is missing, expired or explicitly not applicable.

MessageWhat it means
Accreditation not setNo accreditation status has been recorded
Accreditation has expiredThe status is more than 12 months old. Accreditation must be refreshed annually
Investor is not accreditedThe status is NOT_APPLICABLE and the offering does not permit non-accredited investors

NOT_SPECIFIED is the one status that keeps an investor usable without an accreditation date — it means "not collected yet" rather than "not accredited". See Accreditation.

Completing a Transaction Action

HTTPMessageCause
400Could not complete the action as the status is not pending. Current status: CompleteThe action was already completed. Treat this as success and move on — it is the expected result of a double submit
404—The action does not exist, or its transaction belongs to another partner
400Could not resolve the transaction account owners.A questionnaire action could not resolve the investor behind the transaction

A Questionnaire action refuses completion until its answers have been submitted. Post the answers to /primary/v1/questionnaire-answer first, then complete the action normally. The bulk route, PUT /primary/v2/transaction-action/transaction/{id}/complete-all, skips actions it cannot complete rather than failing the batch — so check the remaining actions afterwards rather than assuming the batch cleared them all.

Authentication

HTTPCause
401No Authorization header, an unrecognised key, or an expired key. Keys carry an expiry and stop working at it
403The key authenticated but lacks the role for the endpoint
404Frequently means "not yours" rather than "does not exist". A partner key can only see its own investors and their transactions, so another partner's record reads as missing

Retrying Safely

POST requests accept an optional IdempotencyKey header, cached for 24 hours. Send one on every transaction submission, and reuse the same key when retrying after a timeout — the cached response is returned instead of a second subscription being created.

Send a unique referenceId as well. It is your own identifier rather than a retry guard, and it is what lets you find a transaction again: GET /primary/v2/transaction filtered by referenceId will tell you whether a submission landed, which is the fallback if a retry happens outside the 24-hour idempotency window.

Next Steps


Did this page help you?