> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reconifyhq.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Reconify's API reference is read-only for customer data. Do not invent endpoints or authentication behavior beyond the OpenAPI contract.
> The public OpenAPI document contains only the documented external /v2 contract.

# Enrich events with provider data

> Connect a payment provider so Reconify checks the payment itself.

Your systems report what they believe happened. A payment integration lets Reconify ask
the provider directly, then keep both answers as separate evidence on the same operation.
Agreement corroborates the outcome. Disagreement opens a mismatch finding, which is the
case your own logs cannot surface.

<Info>
  Payment integrations currently track the `payment_to_wallet` flow. Reconify polls the
  provider after your event arrives, so integrations neither create payments nor receive
  provider webhooks.
</Info>

## How provider checks work

The check runs in four steps, all of them outside your HTTP request:

<Steps>
  <Step title="Configure a connection">
    In the dashboard, **Integrations** holds one entry per provider, each with a
    `sandbox` or `live` environment and its own credentials. Reconify gives the
    integration an opaque reference such as `int_01J9XSTRIPE01`.
  </Step>

  <Step title="Send the payment event">
    A `payment.initiated` event carrying the integration reference and a provider lookup
    value starts the tracking. Reconify accepts the event without waiting for the
    provider.
  </Step>

  <Step title="Reconify checks the provider">
    A background worker looks up the transaction and normalizes the provider response.
  </Step>

  <Step title="The evidence lands on the operation">
    A successful lookup adds `payment.succeeded` provider evidence. A known negative
    status adds `payment.failed` provider evidence. Your own events stay separate and
    immutable throughout.
  </Step>
</Steps>

<img src="https://mintcdn.com/reconify/Jfsy-BiGfPU9ut1l/images/api/provider-check.svg?fit=max&auto=format&n=Jfsy-BiGfPU9ut1l&q=85&s=a87d2db261f9d4c0ed19e28f86d4c3a3" alt="A user payment event stored as durable evidence while the provider tracker looks the transaction up, producing either normalized provider evidence, a pending retry, or a provider issue, then a corroborated outcome or a mismatch finding." width="1184" height="298" data-path="images/api/provider-check.svg" />

Timing follows the flow's deadline. For `payment_to_wallet`, the monitoring deadline is
five minutes after `occurred_at`, and provider tracking continues through a two-minute
grace period after that before it stops. A provider result inside the grace period
resolves an open finding as `resolved_late`.

Five outcomes are possible, and each one leaves you with a different next move:

| Provider result                                     | Reconify records                                   | Your next move                                                 |
| --------------------------------------------------- | -------------------------------------------------- | -------------------------------------------------------------- |
| Success                                             | `payment.succeeded` provider evidence              | Continue monitoring the wallet credit.                         |
| Known failure                                       | `payment.failed` provider evidence                 | Investigate the failed payment through your business workflow. |
| Pending                                             | No terminal evidence yet, and polling continues    | Wait for the next check or inspect the operation.              |
| Timeout, auth error, rate limit, or unmapped status | A provider issue, and no synthetic payment failure | Fix the integration, then retry tracking where available.      |
| User event disagrees with provider evidence         | Both sources remain, and a mismatch can open       | Compare event times, amounts, references, and provider status. |

## Connect a provider

An organization owner or admin configures the connection in the dashboard, with provider
credentials for the environment they intend to track. Saved credentials go to Supabase
Vault, and the dashboard never returns a secret value afterwards.

The optional dashboard test runs after the integration is saved. A connection-only test
checks the configuration, and supplying a sample transaction ID or reference also checks
the lookup and the status mapping. Running a test changes nothing about the integration's
state.

Health and active state are two separate signals:

| Dashboard state                   | Meaning                                                           |
| --------------------------------- | ----------------------------------------------------------------- |
| Active                            | New events start provider tracking.                               |
| Inactive                          | New tracking is blocked, and existing events remain stored.       |
| Not connected                     | No successful provider check has established health yet.          |
| Connected                         | The latest provider check succeeded.                              |
| Auth failed, Timeout, or Degraded | Reconify needs a credential, network, rate-limit, or mapping fix. |

<Warning>
  A provider's `sandbox` setting selects the provider's environment. It creates no Reconify
  sandbox, so submitted events remain immutable evidence in your real organization.
</Warning>

## Add the lookup value

The provider lookup identity travels in the event's `data` object.
`provider_transaction_id` is the first choice wherever the provider returns one, and
`provider_reference` covers the adapters that support reference lookup.

| Provider    | Supported lookup value                                |
| ----------- | ----------------------------------------------------- |
| Stripe      | `provider_transaction_id` for a PaymentIntent ID      |
| Paddle      | `provider_transaction_id` or `provider_reference`     |
| Paystack    | `provider_transaction_id` or `provider_reference`     |
| Flutterwave | `provider_transaction_id` or `provider_reference`     |
| FedaPay     | `provider_transaction_id`                             |
| Manual      | The value used by the endpoint template you configure |

Numeric provider identifiers travel as strings, which means
`"provider_transaction_id": "123456"` rather than `"provider_transaction_id": 123456`.

The event otherwise follows the ordinary event contract. `integration_ref` is the single
field that asks Reconify to poll a configured integration, and its value is the opaque
reference from the integration detail page. The `provider` field is descriptive context
and selects nothing.

<CodeGroup>
  ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl --fail-with-body -sS -X POST "https://api.reconifyhq.com/v2/events" \
    -H "Authorization: Bearer $RECONIFY_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "id":"evt_01J3Y0M8VJQ5W1R3E4J4K7N8Z8",
      "flow":"payment_to_wallet",
      "type":"payment.initiated",
      "occurred_at":"2026-01-01T12:00:00Z",
      "amount":"1000",
      "currency":"XOF",
      "reference":"order-123",
      "entity_id":"wallet_123",
      "data":{
        "integration_ref":"int_01J9XSTRIPE01",
        "provider_transaction_id":"pi_3P8x2K..."
      }
    }'
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  const result = await client.ingestion.ingestMonitoringEvents({
    body: {
      events: [
        {
          id: "evt_01J3Y0M8VJQ5W1R3E4J4K7N8Z8",
          flow: "payment_to_wallet",
          type: "payment.initiated",
          occurred_at: new Date().toISOString(),
          amount: "1000",
          currency: "XOF",
          reference: "order-123",
          entity_id: "wallet_123",
          data: {
            integration_ref: "int_01J9XSTRIPE01",
            provider_transaction_id: "pi_3P8x2K...",
          },
        },
      ],
    },
  });
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  from datetime import datetime, timezone

  from reconify.models import (
      MonitoringBatchRequest,
      MonitoringEvent,
      MonitoringEventData,
  )

  result = client.ingestion.ingest_monitoring_events(
      MonitoringBatchRequest(
          events=[
              MonitoringEvent(
                  id="evt_01J3Y0M8VJQ5W1R3E4J4K7N8Z8",
                  flow="payment_to_wallet",
                  type="payment.initiated",
                  occurred_at=datetime.now(timezone.utc),
                  amount="1000",
                  currency="XOF",
                  reference="order-123",
                  entity_id="wallet_123",
                  data=MonitoringEventData(
                      integration_ref="int_01J9XSTRIPE01",
                      provider_transaction_id="pi_3P8x2K...",
                  ),
              )
          ]
      )
  )
  ```
</CodeGroup>

The immediate response is an ingestion receipt, not the provider result:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "results": [
    { "index": 0, "status": "accepted", "event_id": "evt_01J3Y0M8VJQ5W1R3E4J4K7N8Z8" }
  ]
}
```

`accepted` means Reconify stored the event. The provider outcome appears later, on the
operation in the dashboard or through an event read.

<Warning>
  An event without `integration_ref` is an ordinary user event and starts no provider check.
  An invalid or inactive reference still stores the event, blocks tracking, and fabricates
  no payment failure. A `payment.initiated` event that carries an integration reference must
  also carry `provider_transaction_id` or `provider_reference`, or ingestion rejects it.
</Warning>

## When the provider check degrades

A timeout, authentication failure, rate limit, or unmapped status is a provider issue.
Reconify never converts one into a synthetic `payment.failed`, because provider checks are
evidence rather than authority over your events.

Recovery runs through the integration, never through the original event:

1. The saved integration in the dashboard shows its latest health reason and environment.
2. Expired or incorrect credentials get replaced, and the endpoint gets confirmed.
3. The status mapping gets extended to cover the provider value that went unmapped.
4. The optional test, run with a safe provider-side identifier, confirms the fix.

Resending the original user event under a new ID solves nothing here and creates a second
piece of user evidence.

## Configure a manual integration

The **Manual** provider covers a payment system that exposes an HTTPS lookup endpoint
without a built-in adapter. Five values define it in the dashboard:

* **Endpoint** is an HTTPS `GET` URL that carries `{provider_transaction_id}` or
  `{provider_reference}` where the lookup value belongs.
* **Authentication** is none, bearer, basic, or custom headers. Secret values are stored
  separately from the non-secret configuration.
* **Status path** is the JSON path holding the provider status, such as `payment.status`.
* **Status mappings** translate provider values into `success`, `failure`, or `pending`.
* **Optional response paths** map the provider transaction ID, reference, amount, and
  currency when the response carries them.

For example, an endpoint configured as
`https://payments.example.com/v1/transactions/{provider_reference}` could return:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "payment": {
    "status": "paid",
    "id": "txn_123",
    "amount": "1000",
    "currency": "XOF"
  }
}
```

That response needs a status path of `payment.status`, `paid` mapped to `success`, and a
mapping for every other value the system returns. An unmapped value becomes a provider
issue rather than an outcome.

<Warning>
  Manual integrations accept HTTPS only, do not follow redirects, do not call private or
  loopback addresses, and bound the response body. The endpoint stays publicly reachable
  without carrying credentials in the URL.
</Warning>

## What comes next

Two pages cover what happens around the provider evidence.

<Columns cols={2}>
  <Card title="Go live" icon="clipboard-check" href="/guides/production-checklist">
    Identity, retries, security, and observability before launch.
  </Card>

  <Card title="Monitoring model" icon="activity" href="/concepts/overview">
    How events become operations and findings.
  </Card>
</Columns>
