Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.zestequity.com/llms.txt

Use this file to discover all available pages before exploring further.

This page walks the canonical happy path for a partner integration. Use it as a checklist when designing your integration’s state machine.

High-level sequence

   Partner UI                Zest Partner API                  Zest Admin / Backend
   ─────────                  ────────────────                  ────────────────────

   1. Submit SPV ───────►  POST /v1/spv-requests


                            spv_request.created ────────────►  Admin reviews


   2. Inform user  ◄──── spv_request.completed  ◄────────  Admin approves
      "SPV is live"                  (materialised refs:
                                      opp / veh / sp / spc)

   3. Onboard      ───────►  POST /v1/investors
      investors                          │
                              investor.created (per row)

   4. Create       ───────►  POST /v1/spvs/{slug}/subscriptions
      subscriptions                       │
                              subscription.created (per row)

   5. Upload       ───────►  POST .../forms (multipart)
      signed form                          │
                              signed_subscription_form.uploaded

   6. Upload       ───────►  POST .../fundings (multipart + amount + ref)
      funding receipt                     │
                              funding_receipt.uploaded


                                     Admin reconciles wire


   7. Notify user  ◄──── subscription.completed  ◄────────  Admin marks Bid Completed
      "Investment is live"

Mermaid alternative

Where the partner waits

Two synchronous gates can take significant wall-clock time:
  1. SPV approval. Between spv_request.created and spv_request.completed there is human review. Plan your UI to surface “pending review” to your operator and rely on the webhook to advance the flow.
  2. Subscription completion. Between funding_receipt.uploaded and subscription.completed Zest reconciles the wire. This is also human-paced.
In both cases, persist your local state machine and react to the corresponding webhook. Don’t poll — every webhook delivery uses the retry schedule and dedup recipe.

Where uploads block each other

Within a single subscription:
  • forms MUST succeed before fundings. Out-of-order uploads return 409 conflict.
  • Both endpoints accept files up to 10 MB and only PDF / JPEG / PNG / WEBP.

Failure handling cheatsheet

FailureWhereWhat to do
Network timeout on a POSTSynchronous requestRetry with the same Idempotency-Key.
409 conflict on Idempotency-KeySynchronous requestEither replay the original body, or generate a fresh key.
400 validation_errorSynchronous requestInspect validationErrors[], fix the row, resubmit.
409 conflict on fundingsSynchronous requestForms haven’t been uploaded yet. Upload form first.
5xx from ZestSynchronous requestExponential backoff, cite errorId if persistent.
Webhook receiptAsyncVerify signature → dedup eventId → process.
Webhook receipt timeoutAsyncZest re-delivers per the retry schedule; idempotency on your side is mandatory.

Suggested data model on the partner side

For each Zest resource you should store, at minimum:
  • spv_request.{slug, status, materialisedRefs} keyed by your local intent id.
  • investors.{partnerInvestorId, zestPersonId} mapping table.
  • subscriptions.{subscriptionSlug, partnerSubscriptionId, personId, spvSlug, status} per investor + SPV.
  • webhook_events.{eventId, eventType, occurredAt} for dedup + audit.