FAQ
Getting started
How do we apply?
At fieldproof.fluxusforge.in/apply/
— organisation details, contacts, how you want to send cases (push / pull /
CSV), payment preference and states, verified by email OTP. You get a tracking
link (/apply/status/?token=…). After ops review your organisation code is
assigned, your integration settings are captured (webhook URL + events,
payment mode and artefacts, optional IP allowlist / pull config) and a
sandbox key is issued. Full flow: onboarding.
Can we integrate without building anything?
Yes — CSV: send a file with the documented headers
(Loan No, Customer Name, Mobile, Address, City, State, Pincode,
Latitude, Longitude, Due Amount, …) and Fieldproof ops upload it for
you. Webhooks or the poll API can be added later without redoing ingestion,
and your team can follow cases in the
organisation dashboard from day one.
Who can log in to the organisation dashboard? Any organisation connected to Fieldproof — push, pull or CSV. Ask your integration contact for access: Fieldproof grants your first user (normally an Owner) and shares the URL, and Owners add colleagues as Owner, Member (view, edit case data, assign partners) or Viewer (read-only). Sign-in is your work email plus a 6-digit code we email you — there are no passwords. Each user sees only your organisation's cases and payments. See organisation dashboard.
We can't receive webhooks (corporate network). Are we stuck?
No — the poll API (GET /cases/updates)
returns the identical event envelopes by cursor, oldest first, and includes
all event types regardless of your webhook subscription. Many
organisations start polling and add webhooks later.
How do we test on the sandbox?
Use your test key against https://alpha-gig.fluxusforge.in. There are no
simulated field agents on the sandbox: assignment, visit and Mode A
verification events are driven by the Fieldproof team on request. Everything
else you can drive yourself — push and ?dryRun=1, POST /webhooks/test,
delivery replay, the poll feed, recall, and (Mode B) payments/confirm, which
does emit payment.collected / case.closed. POST /debug/echo-signature
(sandbox only) shows you the exact canonical string we computed when a
signature will not match. See sandbox.
Is there a reference implementation we can run? Yes — the "org-simulator" (Node) is distributed by the integration team on request; ask [email protected]. It is not a public download.
What changes at go-live?
Production is configured again from scratch — webhook URL, mint URL and
auth header, QR / bank details, IP allowlist; nothing carries over from the
sandbox. Then a live key is issued and you switch the base URL to
https://gig.fluxusforge.in. Checklist: go-live.
Sending cases
Why are the borrower's coordinates mandatory?
Field collection is location-driven. We use the coordinates to offer the case
to the nearest partners, for the check-in geofence at the door, and for
distance-based partner pay. A pin worked out from a pincode can be kilometres
from the house, which sends a partner to the wrong place. So every row — push,
pull, CSV or a dashboard edit — needs borrower.address.line1, city,
state, pincode and the real latitude / longitude of that address
(decimal degrees, at least 4 decimal places, 6 recommended; send them as
strings so trailing zeros survive). Your coordinates become the case pin and
are never overwritten by our geocoding; the one exception is a pin a partner
verified on site, which is kept on later re-pushes unless the address itself
changes. One coordinate pair used for rows in different pincodes within
the same batch or file is rejected (every row sharing it) as a default or
office location. Every rule and error message:
data contract.
We don't have coordinates for every borrower yet. What can we do?
Ask [email protected] about a coordinate grace period. Fieldproof
sets it per organisation, optionally with an end date. During grace, rows with
both coordinates missing — empty, or a placeholder such as NA, N/A,
null or - — (and/or a missing line1, city or state) still import — we place the case from the pincode / street address as before
— and come back in warnings[] (summary.warned counts the rows with warnings). Until our
geocoding has located the street address, such a case is "Approximate" and is
not offered to partners. Half a pair or a malformed value is always an error,
even in grace, and grace ends automatically at its end date. Without a grace
period (the default) a row without coordinates is a per-row error. Run
?dryRun=1 on your full export to see where you stand.
Can the same loan be sent twice?
Safely, yes. Re-sending a row for an existing active case updates it in
place (outstanding, DPD, address…), and an identical batch that was already
committed is a no-op (idempotentReplay: true) — unless a loan in it has
no live case (collected, closed or recalled, or its row was rejected and it
never got one), or your coordinate
grace period has started or ended since: then the batch is processed normally
(and a loan without a live case gets a fresh case). Two things to know: omitted
loan.dpd / loan.lateCharges reset to 0 on a re-push, and if the previous
case had closed (collected or closed_unrecovered) a re-push opens a
fresh case with a new caseId and sequence restarting at 1. Within one
batch, send each loan once: if the same sourceLoanNumber appears twice,
the first row is kept and every later duplicate is reported as a per-row
error (visible on a dry run) — see the
data contract.
What does fullSnapshot: true actually do?
It declares "this batch is my complete open book". Active cases absent
from it are flagged for ops review (snapshot_dropped) — they are not
closed automatically, and you only see the count in
summary.flaggedNeedsReview. A loan whose row was rejected for a data error
still counts as present; only loans missing from the batch are flagged. It must be a single batch (a chunked
snapshot would flag everything missing from each chunk); use it daily or
weekly, never for incremental pushes. It is never applied in pull mode.
What if a borrower pays us directly while a case is active?
Call POST /cases/{loan}/recall (push API). The
case closes as closed_unrecovered with reason: "recalled", the assigned
partner is told to stop, and a case.closed event is emitted. Recall is
idempotent — a second call returns alreadyClosed: true. Your daily
fullSnapshot: true push is the safety net for recalls you missed: cases you
no longer send are surfaced to ops for review.
Our loan numbers contain /. Does that work in GET /cases/{loan}?
Yes — percent-encode the path segment (/api/v1/partner/cases/LN%2F001) and
sign the encoded path exactly as sent. See
signing requests.
Receiving updates
Our webhook sequences have gaps (1 → 4). Did we lose events?
No. sequence counts every event type on the case, including types you
are not subscribed to, so default subscribers (case.received,
payment.collected, case.closed) legitimately see gaps. Apply any event
whose sequence is greater than your watermark for that case, never wait for
a gap to fill, and reconcile with GET /cases/{loan} if you want certainty.
Never skip a payment.collected because of ordering — book it (it is
idempotent on eventId / reference) and gate only your case-state fields.
Because sequence restarts at 1 for a fresh case, key your watermark on
(sourceLoanNumber, caseId) or reset it when you see case.received.
Details: updating your LMS.
Will you alert us if our webhooks start failing or our key gets locked?
No. The platform alerts Fieldproof's internal ops, not your technical
contact. Watch your own side: GET /webhooks/deliveries?status=exhausted
(delivery log), GET /health, and your
client's 401 / 429 rates.
We missed some webhooks during an outage.
Deliveries retry over ≈31 hours (0s, 30s, 2m, 10m, 1h, 6h, 24h), then park
as exhausted. Delivery-log rows are kept for 30 days, but
POST /webhooks/deliveries/{eventId}/replay rebuilds the delivery from the
event store, so any event from the last ≈13 months can be replayed (with
an active callback). After 20 consecutive failures
the callback is suspended and probed every 15 minutes; it recovers
automatically and drains the backlog oldest-first. And the poll API always has
the full stream by cursor.
Can we change our webhook URL later?
Yes — ask the Fieldproof team, who set it in your organisation's
Integrations configuration (there is no self-serve API for webhook settings
yet). Sandbox and production URLs are configured separately. Fire
POST /webhooks/test afterwards to see the ping land. Events emitted
while no callback was configured are in the poll feed and can also be
replayed to the new callback on demand.
Can we receive more event types than the default three?
Yes — case.assigned and visit.completed are opt-in via the Fieldproof
team. The poll API already returns every type without any change to your
subscription.
A payment.collected amount differs from what the partner said was collected.
The event carries the operator-verified amount (Mode A — it may differ
from the partner's claim, and a rejected proof emits nothing), the amount
you confirmed (Mode B), or the amount the Fieldproof collection team
recorded on the case (mode: "other" when the recorded mode is outside the
documented list, for example IMPS). Trust the event. In GET /cases/{loan},
visits[].amountCollected before verification is the partner's unverified
claim.
How fresh is GET /cases/{loan}?
It reads the current case record, which is updated before the corresponding
event is written — so it reflects at least every event already emitted to you.
It prefers the active case for that loan, otherwise the most recent one, and
includes the last 20 visits.
Payments
Do you collect cash?
No. Borrowers pay on your rails only (how money flows);
the partner app removes the cash option on your cases entirely and
payments/confirm rejects mode: "cash".
What happens on a partial payment?
- Mode B (your gateway): you confirm the amount; the case stays
in_progress, detaches from the partner and re-enters the marketplace after a cool-down (default 48 h) for another attempt;payment.collectedis emitted with the incrementalamountand absolutetotalCollected/outstandingAfter. - Mode A (static QR): the partner uploads proof, ops verify it, and
payment.collectedis emitted with the verified amount. - Full clearance: in Mode B a confirmed amount of ≥99% of the
remaining outstanding (1% tolerance) completes the case —
payment.collectedthencase.closedwithstatus: "collected",reason: "full_settlement". In Mode A the same pair fires when ops verify the payment that clears the case.
We got a 409 from payments/confirm. Do we refund?
| Code | Meaning | Refund? |
|---|---|---|
DUPLICATE_CONFIRMATION | Same reference already booked (error.caseId returned) | No — treat as success |
CASE_ALREADY_COLLECTED | Case was already fully collected; this is money not owed | Yes, refund the borrower |
AMOUNT_EXCEEDS_OUTSTANDING | Amount more than 101% of what remained | Refund / adjust the excess |
CASE_CLOSED | Case was recalled or written off first | Yes, refund the borrower |
A 5xx from confirm is safe to retry — the retry resumes and completes.
Full list: errors.
Do you issue receipts to borrowers? No. The regulatory disclosure text you provide is shown on the agent's payment and ID screens, but the platform does not issue PDF receipts on your behalf — receipts remain your system's responsibility.
Security
Can you give us your egress IPs for our firewall?
We do not publish static egress IPs. Authenticate webhooks by their HMAC
signature and your mint endpoint by the Authorization value you registered.
If your policy strictly requires source IPs, contact [email protected]
before go-live. More: security.
How does key rotation affect our webhook receiver? Webhooks are signed with the new secret from the moment of rotation, while your requests are accepted with old or new until the old one is retired. Deploy verification against multiple secrets before you request a rotation. See key security.
Support
- Everything goes to [email protected] — integration questions, sandbox lifecycle events, webhook / event-subscription changes, key rotation and revocation, egress-IP requirements, and security disclosures.
- Include the
X-Request-Idheader of any failing call; it lets us trace the exact request. - There are no automatic delivery-failure or lockout alerts to your side — see "Will you alert us…" above.