Skip to content
Integration Recovery
INTEGRATION DRIFT & REPAIR API

A field added to a response is free. The same field required on a request rejects every call.

Send two observations of a third-party integration (response schema, auth requirements, webhook payloads, rate-limit headers) and get every change classified breaking, degraded or safe, with an ordered repair plan for the ones that break you. Severity turns on direction: whether your client produces the value or the provider does. Get that backwards and a drift report is noise, which is why people turn them off.

Free tier: 200 integration checks/month Paid from $199/month No card to run the demo
Live drift check Ready

Runs the same engine the paid endpoint uses. Nothing is stored and no key is needed.

Press “Check this integration” to call the live API.
The problem

The change is in someone else's repository.

Nothing in your codebase moved. Your tests pass, because they run against fixtures you wrote. The provider tightened a field, renamed a key, halved a limit: and the first thing you learn about it is a support ticket.

A changelog is not a diff, and a diff is not an answer

Some providers publish a changelog. Some publish an OpenAPI file. Diffing two of those gives you two hundred lines in which every change carries equal weight, so somebody has to read all of them to find the four that matter. That reading happens once, in the week the migration is announced, and never again.

The same key lives on both sides of the same call

status is in the request and in the response. A tool that treats a field as a field is wrong about half of them: it flags the harmless additions and stays quiet about the response field your parser dereferences. Noise in one direction, silence in the other.

The worst failures do not raise anything

A withdrawn webhook event throws no exception. A renamed X-RateLimit-Remaining reads as absent, which looks exactly like unlimited headroom, so the client speeds up. Nothing is logged, because from your process's point of view nothing happened.

What it costs

Three ways a contract change reaches production before you do.

None of these are bugs in your code, and none of them are caught by your test suite. They are all decisions someone else made and shipped.

  • Rejected
    A field that became required

    The provider adds one mandatory parameter. Every call you make is refused from the moment their change deploys, and the error names a field that has never appeared in your code. Fixing it is ten minutes; noticing it took the length of an outage.

  • Silent
    A webhook that simply stops

    An event is retired. No delivery, no failure, no retry, nothing in the dead-letter queue: the notifications just end. Your state goes stale at whatever rate that entity changes, and the first report is a customer describing something that should have updated days ago.

  • Throttled
    A limit cut you had no way to see

    The published limit drops and the throttle headers are renamed at the same time. Your client reads the old header, gets nothing, treats it as no constraint, and keeps its pace. The 429s start at your busiest hour, which is exactly when the retry storm is worst.

What it computes

Direction first, then severity, then the repair.

You supply the two snapshots: from an OpenAPI file, a recorded response, the provider's own docs. The engine does not crawl anything, call the provider, or ask a model what a clause means. It compares what you give it and says what it means for a client pointed in a particular direction.

OutputWhat it answersWhy a plain diff gets it wrong
directionWhether your client produces the value or the provider does.A diff has no notion of who writes a field, so it cannot tell the two cases apart.
severityBreaking, degraded or safe, per change.The same edit is a rejected call on a request and free data on a response.
verdictcompatible, degraded or broken, for the integration as a whole.A list of changes is not a decision; a queue needs one.
repairPlanAn ordered remediation per breaking and degraded change, with parameters.A diff stops at “this changed”.
autoApplicableWhether a step may run unattended.Confidence and safety are different questions, and merging them is how bad patches get applied.
rateLimitWhether your observed volume still fits, by how much it misses, and the exact backoff.Two limits in different windows are not comparable without exact integer arithmetic.

Two snapshots Direction Severity Verdict Repair plan Into your CI

  • 01

    Direction is structural

    Request fields are outbound, response fields and webhook payloads are inbound. It is not a flag you can set wrongly: it comes from where the field sits in the snapshot, so the classification cannot be argued with.

  • 02

    Every asymmetry, both ways round

    A removed enum value is breaking on what you send and a dead branch on what you read. A widened type is safe outbound and breaking inbound; a narrowed one is the reverse. A nullable response dereferences to null; a nullable request is a restriction lifted.

  • 03

    Renames, only when they cannot be wrong

    receipt_url and receiptUrl pair up when the names match once case and punctuation are stripped, the types and nullability match, and the pairing is one-to-one. Anything looser stays two changes: a wrong rename does not fail, it reads the wrong value.

  • 04

    Missing usage never buys a lower severity

    Tell it which scopes your token holds, which events you subscribe to and how much traffic you send, and it can rule changes out. Leave those out and it will not: a new scope stays breaking, and a reduced limit stays degraded rather than safe.

  • 05

    A plan you apply in order

    Auth first: nothing else is testable without a working credential. Then routing, then what you send, then what you read, then webhooks, then throughput. Each step carries an integer confidence and a flag for whether it may run unattended.

  • 06

    Limits in exact integers

    100 per minute against 5,000 per hour is compared by cross-multiplying integers, never by dividing into a float. Permitted volume is floored, the pacing interval is rounded up, and both round the way that fails closed.

Example output

Seven changes. Five break you. One of them is free.

The payload in the demo panel, as returned by POST /v1/checks. Note the two field_added entries: statement_descriptor on the request is breaking, network_code on the response is safe. Same code, opposite direction, opposite answer.

{
  "verdict": "broken",
  "summary": { "total": 7, "breaking": 5, "degraded": 1, "safe": 1 },
  "changes": [
    { "code": "scope_added",         "direction": "outbound", "severity": "breaking", "target": "charges:read" },
    { "code": "enum_value_removed",  "direction": "outbound", "severity": "breaking", "target": "currency" },
    { "code": "field_added",         "direction": "outbound", "severity": "breaking", "target": "statement_descriptor" },
    { "code": "field_renamed",       "direction": "inbound",  "severity": "breaking", "target": "receipt_url" },
    { "code": "rate_limit_reduced",  "direction": "outbound", "severity": "breaking", "target": "rateLimit" },
    { "code": "enum_value_added",    "direction": "inbound",  "severity": "degraded", "target": "status" },
    { "code": "field_added",         "direction": "inbound",  "severity": "safe",     "target": "network_code" }
  ],
  "repairPlan": {
    "autoApplicable": 3, "requiresHuman": 3, "fullyAutomatic": false, "minConfidence": 20,
    "steps": [
      { "order": 1, "phase": "auth",            "action": "request_scope",       "confidence": 90, "autoApplicable": false },
      { "order": 2, "phase": "outbound_schema", "action": "replace_enum_value",  "confidence": 35, "autoApplicable": false },
      { "order": 3, "phase": "outbound_schema", "action": "add_default_value",   "confidence": 20, "autoApplicable": false },
      { "order": 4, "phase": "inbound_schema",  "action": "map_renamed_field",   "confidence": 95, "autoApplicable": true  },
      { "order": 5, "phase": "inbound_schema",  "action": "handle_unknown_enum", "confidence": 85, "autoApplicable": true  },
      { "order": 6, "phase": "throughput",      "action": "add_backoff",         "confidence": 95, "autoApplicable": true  }
    ]
  },
  "rateLimit": {
    "direction": "reduced", "willExceed": true,
    "permittedInObservedWindow": 600, "excessRequests": 200, "headroomPct": 0,
    "minIntervalMs": 100,
    "backoff": { "initialDelayMs": 100, "multiplier": 2, "maxDelayMs": 1000, "maxAttempts": 5 }
  }
}

Three of six steps can run unattended

Reading a renamed field, adding a default branch for an unknown enum value and pacing requests are all mechanical: they cannot lose information, change what you store, or weaken a check. Choosing a statement_descriptor is none of those things, so it gets a human and a confidence of 20.

200 requests over, not “near the limit”

800 observed against a limit that permits 600 in the same window. The excess is a count, the pacing interval is 100ms rounded up, and both come from integer arithmetic on the two rates: no float ever holds a limit.

You supply the snapshots

Integration Recovery does not crawl the provider, replay your traffic, or ask a model what a schema means. You send two observations you already have, and the same pair always produces the same bytes: so the result can be diffed, stored and asserted on in CI.

This service is newly launched. We publish no uptime percentage, customer count, logo wall or certification claim until we have the operating history to support one. The output is a classification of the two snapshots you supply and a proposed remediation; applying a repair is your decision, and the autoApplicable flag exists so that decision can be made in code.

How it works

Three calls to put drift detection in your pipeline

  • Snapshot the contract

    Turn whatever you have (an OpenAPI file, a recorded response, the provider's docs page) into endpoints, auth, webhooks and a rate limit. Store the result next to your integration code. That stored snapshot is the previous for every later run.

  • Check on every build

    POST the stored snapshot and a fresh one. Fail the build on verdict: "broken", open a ticket on "degraded", and do nothing on "compatible". One unit per integration check, up to 50 in a call.

  • Apply what is safe, route what is not

    Every repair carries autoApplicable, an integer confidence and machine-readable parameters. Apply the mechanical ones in order; send the rest to the person who knows what the field means, with the reason already written.

Rules the engine never bends

Direction, and refusing to guess

  • Direction is structural. Request fields are outbound, response fields and webhook payloads inbound. There is no flag to get wrong.
  • Missing usage data never lowers a severity. Without heldScopes a new scope is breaking; without subscribedEvents a withdrawn event is breaking; without observedVolume a reduced limit is degraded, not safe.
  • An omitted section is unobserved, not empty. If one snapshot lists endpoints and the other omits the key, that section is skipped with a warning. An explicit [] means you looked and found none: and does report every removal.
  • A rename is claimed only when it cannot be wrong. Ambiguity falls back to a removal plus an addition, which is noisier and never wrong.
  • Rates are compared by integer cross-multiplication. Permitted volume floors, the pacing interval rounds up. Both fail closed.
  • Sunset dates are whole UTC days. A deadline that shifts an hour across a DST boundary is a missed deadline.
  • A swapped snapshot pair is refused, not analysed. Backwards, every classification inverts and nothing downstream could tell.
  • Output is deterministic and nothing is stored. Same two snapshots, same instant, same bytes.
Developer integration

Small surface, versioned, OpenAPI-first

Authenticate with Authorization: Bearer <key>. Every error returns a stable code and a requestId you can quote, and validation failures name the exact field in details.path.

POST/v1/keysPublic. Emails a one-time claim token to the address you give it. No key is returned on this call, proving the mailbox is what stops anyone minting a key on your account.
POST/v1/keys/claimPublic. Spends the emailed token and returns the key, shown once: 200 integration checks a month, no card.
POST/v1/checksOne check or up to 50. Billed one unit per integration check.
POST/v1/demo/checkPublic. Real engine, capped at 5 endpoints and 60 fields. No key required.
GET/v1/drift-typesPublic. Every drift code and repair action, with its severity in each direction.
curl -X POST https://integrationrecovery-api.com/v1/checks \
  -H "Authorization: Bearer $INTEGRATION_RECOVERY_KEY" \
  -H "content-type: application/json" \
  -d '{"check":{"integrationId":"acme-payments-prod",
        "provider":"northwind-payments",
        "previous":{"endpoints":[{"method":"POST","path":"/v1/charges",
          "request":[{"path":"amount","type":"integer","required":true}]}]},
        "current":{"endpoints":[{"method":"POST","path":"/v1/charges",
          "request":[{"path":"amount","type":"integer","required":true},
                     {"path":"statement_descriptor","type":"string",
                      "required":true}]}]}}}'
Pricing

Priced per integration check, capped so a CI loop can’t surprise you

One unit is one integration checked: two snapshots compared, however many endpoints, webhooks and fields they describe. Every plan includes an allowance, then a per-unit overage that is hard-capped per billing period: your worst-case bill is the base price plus the cap, never more.

Developer
$199 /month
  • 5,000 integration checks included
  • $0.08 per additional integration check
  • Overage capped at $400 per period
  • Full API access, Python and TypeScript SDKs
Start with this plan
Scale
$4,999 /month
  • 300,000 integration checks included
  • $0.03 per additional integration check
  • Overage capped at $10,000 per period
  • Full API access, Python and TypeScript SDKs
Start with this plan
Enterprise
$10,000+ /month
  • 1,200,000 integration checks included
  • $0.01 per additional integration check
  • Overage capped at $20,000 per period
  • Full API access, Python and TypeScript SDKs
Contact sales

Free tier: 200 integration checks per month, no card. Prices in USD, billed monthly. Payment is processed by Square through our shared billing platform; card details never touch this site.

What counts as an integration check?
One pair of snapshots compared, in one call. A check covering forty endpoints and a hundred fields is one unit; a batch of fifty checks is fifty. A request rejected by validation or by quota costs nothing: the whole batch is reserved before any comparison runs, so an over-quota call is refused rather than half-served.
Does it call the provider, or read my code?
Neither. You send two observations you already hold: generated from an OpenAPI file, a recorded response, or the provider's documentation. The service makes no outbound requests and has no access to your repository or your traffic. Every endpoint is stateless: nothing about your integrations is retained.
Why is a field added to a response not breaking?
Because your client does not have to send it, and a JSON reader ignores keys it does not know. The same field added as required to a request is a rejected call on every request you make. The direction determines the answer, and it is structural: request fields go under request, response fields under response. That single distinction is what separates a usable report from a wall of noise.
Are the repairs applied for me?
No. Each repair is machine-readable: an action, ordered parameters, an integer confidence and an autoApplicable flag: so your own tooling can apply the mechanical ones. autoApplicable is true only when applying the step cannot lose information, cannot change what your system stores, and cannot weaken a security check. A signature-scheme change is never auto-applicable, however confident the diagnosis, because a verifier wrong in the permissive direction accepts forgeries.
What happens if I don't send usage?
You still get every change classified, but nothing gets ruled out. Without heldScopes a newly required scope stays breaking; without subscribedEvents a withdrawn webhook event stays breaking; without observedVolume a reduced rate limit is reported as degraded rather than safe. Each of those adds a warning naming the field that would have settled it. Missing data never buys a lower severity.
Can I evaluate it before paying?
Yes. The demo at the top of this page is the real engine with no key at all, capped at five endpoints and sixty fields. The free tier is 200 integration checks a month against the full authenticated surface, with no card.

Find the break before your provider ships it.

The free tier is 200 integration checks a month, no card. Create a key, post two snapshots, and the response tells you which changes break you and in what order to fix them.

One email address, no password, no card. Prefer the terminal? The same key, in two calls:

curl -X POST https://integrationrecovery-api.com/v1/keys \
  -H "content-type: application/json" \
  -d '{"email":"you@company.com","name":"Evaluation key","source":{"source":"web","medium":"landing"}}'

# 202 Accepted. A one-time token is emailed to that address — spend it,
# and the response carries the key, shown once.

curl -X POST https://integrationrecovery-api.com/v1/keys/claim \
  -H "content-type: application/json" \
  -d '{"token":"<token from the email>"}'