Knowing when the member is done

The iframe tells the embedding page when a member finishes filing. Use it to close the frame, refresh your own view, and keep the dispute's id.

Without it the frame simply sits on a confirmation screen and your app has no idea anything happened.

Where messages are sent

The frame posts to the origins you registered with Casap, and only those. Each one must be https — an origin we cannot parse, or one sent over plain http, is dropped when your configuration loads, and no message is delivered to it.

Give us every origin you embed from, in each environment. Adding one later is a configuration change on our side, not something you can do from the page.

The message

{
  "event": "CASAP_DISPUTE_INTAKE_COMPLETED",
  "payload": {
    "status": "completed",
    "disputeId": "<dispute id>",
    "completedAt": "2026-09-28T19:05:12.000Z"
  }
}

One message is sent per dispute created. A submission covering two transactions that become two disputes sends two messages, so treat them as a stream rather than a single completion signal.

Listening for it

window.addEventListener("message", (event) => {
  if (event.origin !== "https://disputes.casaphq.com") return;
  if (event.data?.event !== "CASAP_DISPUTE_INTAKE_COMPLETED") return;

  const { disputeId, completedAt } = event.data.payload;
  // Close the frame, refresh your view, store disputeId.
});

Always check event.origin before you trust a message. Any page on the web can post to your window, so a listener that skips that check will act on whatever it is sent. Compare against the Casap origin for the environment you are embedding — Casap gives you the exact value during onboarding.

What to do with the dispute id

Keep it. It is the same id the Get Dispute Status endpoint takes, and the one that appears on the webhook Casap sends when the dispute changes. Storing it at this point is what lets you tie the member's action to everything that follows.