# Generate evidence in seconds (https://docs.chargeflow.io/docs/platforms/eaas/generate-evidence-in-10s)



Evidence-as-a-Service (EaaS) turns dispute data into a polished, bank-ready PDF evidence package in about 30 seconds (up to \~3 minutes). This recipe is a full, copy-paste-runnable flow: call the Generate Evidence API, wait for the `evidence.ready` webhook, then fetch the PDF link.

EaaS is a platform-level integration. Platforms call it on behalf of their merchants. Merchants never call it directly. See [What is EaaS?](https://docs.chargeflow.io/docs/platforms/eaas/introduction).

## Before you start [#before-you-start]

* EaaS must be enabled on your Connect account by your Chargeflow account manager. Without it, every EaaS call returns `403_eaas_not_enabled`. See [What is EaaS?](https://docs.chargeflow.io/docs/platforms/eaas/introduction).
* Get your platform `API Access Key`. Every request sends it in the `x-api-key` header. See [Authentication](https://docs.chargeflow.io/docs/reference/api-fundamentals/authentication).
* Subscribe to the `evidence.ready` and `evidence.error` webhooks in the Connect Developer Hub. See [How It Works](https://docs.chargeflow.io/docs/platforms/eaas/how-it-works).

All requests go to `https://api.chargeflow.io` under the `/public/2025-04-01/` path.

## Steps [#steps]

<Steps>
  <Step>
    ### Call the Generate Evidence API [#call-the-generate-evidence-api]

    `POST /public/2025-04-01/evidence` accepts either an existing Chargeflow `dispute_id` or a full inline dispute object. You do not need to create the dispute separately first. Provide exactly one of the two.

    The dispute must be in `needs_response` status, otherwise the call returns `422_dispute_invalid_state`.

    **Option A: reference an existing dispute:**

    <Tabs items="['curl', 'Node.js', 'Python']">
      <Tab value="curl">
        ```bash title="Terminal"
        curl -X POST https://api.chargeflow.io/public/2025-04-01/evidence \
          -H "x-api-key: YOUR_PLATFORM_API_KEY" \
          -H "Content-Type: application/json" \
          -d '{
            "account_id": "66e6ea9ecd94925a9f8060d9",
            "dispute": {
              "dispute_id": "66e6ea9ecd94925a9f8060d9"
            }
          }'
        ```
      </Tab>

      <Tab value="Node.js">
        ```javascript title="Node.js"
        const res = await fetch('https://api.chargeflow.io/public/2025-04-01/evidence', {
          method: 'POST',
          headers: {
            'x-api-key': process.env.CHARGEFLOW_PLATFORM_API_KEY,
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            account_id: '66e6ea9ecd94925a9f8060d9',
            dispute: { dispute_id: '66e6ea9ecd94925a9f8060d9' },
          }),
        });

        const evidence = await res.json();
        console.log(evidence.id, evidence.status); // ev_..., in_progress
        ```
      </Tab>

      <Tab value="Python">
        ```python title="Python"
        import os, requests

        res = requests.post(
            "https://api.chargeflow.io/public/2025-04-01/evidence",
            headers={"x-api-key": os.environ["CHARGEFLOW_PLATFORM_API_KEY"]},
            json={
                "account_id": "66e6ea9ecd94925a9f8060d9",
                "dispute": {"dispute_id": "66e6ea9ecd94925a9f8060d9"},
            },
        )
        data = res.json()
        ```
      </Tab>
    </Tabs>

    **Option B: submit the dispute data inline:**

    <Tabs items="['curl', 'Node.js', 'Python']">
      <Tab value="curl">
        ```bash title="Terminal"
        curl -X POST https://api.chargeflow.io/public/2025-04-01/evidence \
          -H "x-api-key: YOUR_PLATFORM_API_KEY" \
          -H "Content-Type: application/json" \
          -d '{
            "account_id": "66e6ea9ecd94925a9f8060d9",
            "dispute": {
              "dispute_data": {
                "source_id": "du_123456789",
                "created_at": "2024-02-10T12:00:00Z",
                "reason": "fraud",
                "due_by": "2024-02-20T12:00:00Z",
                "amount": 150.00,
                "currency": "USD",
                "status": "needs_response",
                "transaction": {
                  "source_id": "tx_1234567890",
                  "created_at": "2024-02-08T10:00:00Z",
                  "type": "paid",
                  "amount": 150.00,
                  "currency": "USD"
                }
              }
            }
          }'
        ```
      </Tab>

      <Tab value="Node.js">
        ```javascript title="Node.js"
        const res = await fetch('https://api.chargeflow.io/public/2025-04-01/evidence', {
          method: 'POST',
          headers: {
            'x-api-key': process.env.CHARGEFLOW_PLATFORM_API_KEY,
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            account_id: '66e6ea9ecd94925a9f8060d9',
            dispute: {
              dispute_data: {
                source_id: 'du_123456789',
                created_at: '2024-02-10T12:00:00Z',
                reason: 'fraud',
                due_by: '2024-02-20T12:00:00Z',
                amount: 150.0,
                currency: 'USD',
                status: 'needs_response',
                transaction: {
                  source_id: 'tx_1234567890',
                  created_at: '2024-02-08T10:00:00Z',
                  type: 'paid',
                  amount: 150.0,
                  currency: 'USD',
                },
              },
            },
          }),
        });
        const data = await res.json();
        ```
      </Tab>

      <Tab value="Python">
        ```python title="Python"
        import os, requests

        res = requests.post(
            "https://api.chargeflow.io/public/2025-04-01/evidence",
            headers={"x-api-key": os.environ["CHARGEFLOW_PLATFORM_API_KEY"]},
            json={
                "account_id": "66e6ea9ecd94925a9f8060d9",
                "dispute": {
                    "dispute_data": {
                        "source_id": "du_123456789",
                        "created_at": "2024-02-10T12:00:00Z",
                        "reason": "fraud",
                        "due_by": "2024-02-20T12:00:00Z",
                        "amount": 150.00,
                        "currency": "USD",
                        "status": "needs_response",
                        "transaction": {
                            "source_id": "tx_1234567890",
                            "created_at": "2024-02-08T10:00:00Z",
                            "type": "paid",
                            "amount": 150.00,
                            "currency": "USD",
                        },
                    }
                },
            },
        )
        data = res.json()
        ```
      </Tab>
    </Tabs>

    The API responds immediately with `in_progress`. Generation is asynchronous, so the PDF is not in this response.

    ```json title="Response"
    {
      "id": "ev_abc123456789",
      "account_id": "acct_9876543210",
      "ext_account_id": "ext_acct_54321",
      "dispute": "dp_1122334455",
      "created_at": "2025-07-29T14:35:00Z",
      "status": "in_progress",
      "file_url": null,
      "file_version": 1
    }
    ```

    <Callout title="Note">
      Store the `id` as your persistent reference to this evidence package. The `id` is permanent; the
      `file_url` is temporary and expires 7 days after it is issued. See [Privacy &
      Security](https://docs.chargeflow.io/docs/platforms/eaas/compliance).
    </Callout>
  </Step>

  <Step>
    ### Wait for the evidence.ready webhook [#wait-for-the-evidenceready-webhook]

    Do not poll in a tight loop. Chargeflow pushes the result to your webhook endpoint when the PDF is ready (`evidence.ready`) or if generation fails (`evidence.error`). Generation typically completes in about 30 seconds, with a maximum of around 3 minutes.

    `evidence.ready` payload:

    ```json title="Webhook payload"
    {
      "event": {
        "id": "evt_XXXXXXXXXXXXXXXX",
        "type": "evidence.ready",
        "created_at": "2025-07-29T12:34:56Z"
      },
      "evidence": {
        "id": "ev_abc123456789",
        "account_id": "acct_9876543210",
        "ext_account_id": "ext_acct_54321",
        "dispute": "dp_1122334455",
        "created_at": "2025-07-29T14:35:00Z",
        "status": "completed",
        "file_url": "https://cdn.chargeflow.io/evidence/ev_abc123456789/v2/evidence.pdf",
        "file_version": 1
      }
    }
    ```

    Acknowledge with a `2XX` quickly, then download or store the PDF asynchronously.

    ```javascript title="Node.js"
    app.post('/webhook', express.json(), (req, res) => {
      const event = req.body;
      res.json({ received: true }); // acknowledge first

      if (event.event?.type === 'evidence.ready') {
        const { id, file_url } = event.evidence;
        // Download the PDF and submit it to your PSP
        saveEvidencePdf(id, file_url);
      }

      if (event.event?.type === 'evidence.error') {
        // event.error_code and event.error_message explain what failed
        console.error(event.error_code, event.error_message);
      }
    });
    ```

    The `evidence.error` payload includes `error_code` and `error_message`, for example `422_dispute_invalid_state` with `"Dispute status must be needs_response"`. See [How It Works](https://docs.chargeflow.io/docs/platforms/eaas/how-it-works) for both payload shapes.
  </Step>

  <Step>
    ### Fetch the latest evidence link [#fetch-the-latest-evidence-link]

    The download link expires 7 days after it is issued. If you need a fresh link later, read the evidence record by its `id` with `GET /public/2025-04-01/evidence/{evidenceId}`.

    <Tabs items="['curl', 'Node.js', 'Python']">
      <Tab value="curl">
        ```bash title="Terminal"
        curl -X GET https://api.chargeflow.io/public/2025-04-01/evidence/ev_abc123456789 \
          -H "x-api-key: YOUR_PLATFORM_API_KEY"
        ```
      </Tab>

      <Tab value="Node.js">
        ```javascript title="Node.js"
        const res = await fetch('https://api.chargeflow.io/public/2025-04-01/evidence/ev_abc123456789', {
          headers: { 'x-api-key': process.env.CHARGEFLOW_PLATFORM_API_KEY },
        });

        const evidence = await res.json();
        console.log(evidence.status, evidence.file_url, evidence.file_version);
        ```
      </Tab>

      <Tab value="Python">
        ```python title="Python"
        import os, requests

        res = requests.get(
            "https://api.chargeflow.io/public/2025-04-01/evidence/ev_abc123456789",
            headers={"x-api-key": os.environ["CHARGEFLOW_PLATFORM_API_KEY"]},
        )
        data = res.json()
        ```
      </Tab>
    </Tabs>

    The response carries the current `status`, `file_url`, and `file_version`:

    ```json title="Response"
    {
      "id": "ev_abc123456789",
      "account_id": "acct_9876543210",
      "ext_account_id": "ext_acct_54321",
      "dispute": "dp_1122334455",
      "created_at": "2025-07-29T14:35:00Z",
      "status": "completed",
      "file_url": "https://cdn.chargeflow.io/evidence/ev_abc123456789/v2/evidence.pdf",
      "file_version": 1
    }
    ```
  </Step>

  <Step>
    ### Regenerate when new data arrives (optional) [#regenerate-when-new-data-arrives-optional]

    While the dispute is still in `needs_response`, you can regenerate the package to fold in new data such as tracking, fulfillment, or added communication logs. Call the same Generate Evidence endpoint again. Each regeneration increments `file_version`.

    <Tabs items="['curl', 'Node.js', 'Python']">
      <Tab value="curl">
        ```bash title="Terminal"
        curl -X POST https://api.chargeflow.io/public/2025-04-01/evidence \
          -H "x-api-key: YOUR_PLATFORM_API_KEY" \
          -H "Content-Type: application/json" \
          -d '{
            "account_id": "66e6ea9ecd94925a9f8060d9",
            "dispute": { "dispute_id": "66e6ea9ecd94925a9f8060d9" }
          }'
        ```
      </Tab>

      <Tab value="Node.js">
        ```javascript title="Node.js"
        const res = await fetch('https://api.chargeflow.io/public/2025-04-01/evidence', {
          method: 'POST',
          headers: {
            'x-api-key': process.env.CHARGEFLOW_PLATFORM_API_KEY,
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            account_id: '66e6ea9ecd94925a9f8060d9',
            dispute: { dispute_id: '66e6ea9ecd94925a9f8060d9' },
          }),
        });
        const data = await res.json();
        ```
      </Tab>

      <Tab value="Python">
        ```python title="Python"
        import os, requests

        res = requests.post(
            "https://api.chargeflow.io/public/2025-04-01/evidence",
            headers={"x-api-key": os.environ["CHARGEFLOW_PLATFORM_API_KEY"]},
            json={
                "account_id": "66e6ea9ecd94925a9f8060d9",
                "dispute": {"dispute_id": "66e6ea9ecd94925a9f8060d9"},
            },
        )
        data = res.json()
        ```
      </Tab>
    </Tabs>

    <Callout type="warn" title="Warning">
      If a call returns `409_generation_in_progress`, do not retry. Wait for the `evidence.ready` or
      `evidence.error` webhook before taking further action.
    </Callout>
  </Step>

  <Step>
    ### Report the outcome [#report-the-outcome]

    When the dispute resolves (won or lost), share the outcome with Chargeflow so the AI keeps improving win rates across your merchants. There is no public endpoint for this yet.

    <ComingSoon href="/docs/platforms/eaas/generate-and-regenerate">
      A public Report Outcome endpoint is not available yet. For now, contact your Chargeflow account
      manager for the preferred method of submitting outcome data for your integration.
    </ComingSoon>
  </Step>
</Steps>

## Next steps [#next-steps]

<Cards>
  <Card title="Generate & Regenerate Evidence" href="/docs/platforms/eaas/generate-and-regenerate">
    The full API reference and error codes.
  </Card>

  <Card title="How It Works" href="/docs/platforms/eaas/how-it-works">
    Connect account setup and the evidence.ready / evidence.error payloads.
  </Card>

  <Card title="Privacy & Security" href="/docs/platforms/eaas/compliance">
    Link expiry and data handling.
  </Card>
</Cards>
