Partner Integration — API Delta Reference
Internal working reference for updating interstice-digital.gitbook.io/partner-integration.
Exposure model Changed
The GitBook currently documents the orchestrator REST API (services/api) as
directly internet-facing, on the reasoning that it is coordination-only (holds no keys, signs
no transactions). That exposure model has been superseded — deemed indefensible for a service
with ~40+ endpoints, including admin/internal routes, whose isolation is enforced per-route in
application code rather than by network boundary.
swap-api is intended to lose its public ALB listener entirely once cp-gateway is live — partners will never hold a credential that reaches it directly.
Authentication Changed
/api/v1/admin/keys/*).isk_<token>), issued and resolved through the identity service — not
swap-api's admin surface. Presented as a bearer token to the gateway only.timestamp.entityId.method.path with a shared
secret. swap-api verifies the HMAC and a 60s replay window before trusting the identity —
and never accepts these headers from a caller that isn't the gateway's own network path.Base URL status Not live
Neither the GitBook nor the current implementation has a working base URL to test against right now:
- The GitBook is explicit that hostnames are not published — environment URLs are meant to be issued per-partner at onboarding.
- The current OpenAPI contract declares a
serversentry, but the host it names is a static documentation/Swagger site with no backend behind it — any non-documentation path falls through to the docs landing page rather than an API response. It should not be published to partners as a working host. - The intended backend (
cp-gateway) has no container image, task definition, or ALB routing yet in any environment — there is nothing to route a real base URL to.
Guidance for the docs rewrite: keep this section host-less. State that the
base URL is assigned per-partner at onboarding once an environment is live, and give the path
shape (/external/cp/v1/*) without a host, exactly as done in the table below.
Endpoint reference Changed
All paths below are relative — prefix with the base URL assigned at onboarding
(see above). Every path lives under /external/cp/v1.
Discovery & profile
| Method & path | Notes | Status |
|---|---|---|
| GET /config | Assets, platform config, network config | contract frozen |
| GET /me | Counterparty profile subset | contract frozen |
| PATCH /me/supported-pairs | LP-only | contract frozen |
| GET /me/fee | Entity-tier fee resolution | contract frozen |
| GET /me/balances | Canton CC balance (locked + unlocked) | contract frozen |
RFQ / quoting New shape
| Method & path | Notes | Status |
|---|---|---|
| GET /rfqs | Open RFQs this LP is eligible to quote | contract frozen |
| GET /rfqs/:id | RFQ detail (404 if not eligible) | contract frozen |
| POST /rfqs/:id/quote | Submit an offered rate | contract frozen |
| DELETE /rfqs/:id/quote/:quoteId | Withdraw a live quote | contract frozen |
| GET /quotes | This LP's outstanding quotes across RFQs | contract frozen |
Replaces the GitBook's rfq/offer → rfq/select/{offerId} →
rfq/finalize three-step flow. See RFQ flow shift below —
this needs a rewritten walkthrough, not a find-and-replace of paths.
Swaps
| Method & path | Notes | Status |
|---|---|---|
| GET /swaps | This entity's swaps | contract frozen |
| GET /swaps/:id | Swap detail (ownership-enforced) | contract frozen |
| GET /swaps/:id/confirmation | Trade confirmation, json or pdf | contract frozen |
| POST /swaps/:id/canton/prepare | Server-prepared unsigned Canton tx (thin-client signing) | contract frozen |
| POST /swaps/:id/canton/execute | Submit the signed tx | contract frozen |
Reports — verified on-chain transitions Expanded
| Method & path | Notes | Status |
|---|---|---|
| POST /swaps/:id/report-hashlock | new not in GitBook's 5-transition list | contract frozen |
| POST /swaps/:id/report-canton-lock | documented in GitBook | contract frozen |
| POST /swaps/:id/report-htlc-refresh | new not in GitBook's 5-transition list | contract frozen |
| POST /swaps/:id/report-eth-lock | documented in GitBook | contract frozen |
| POST /swaps/:id/report-eth-claim | documented in GitBook | contract frozen |
| POST /swaps/:id/report-canton-claim | documented in GitBook | contract frozen |
| POST /swaps/:id/report-refund | documented in GitBook | contract frozen |
| POST /swaps/by-commitment/:commitment/report-htlc-created | new keyed by quote-commitment, not swapId — reported before a swap record exists | contract frozen |
Webhooks
| Method & path | Notes | Status |
|---|---|---|
| POST /webhooks | Register | contract frozen |
| GET /webhooks | List registrations | contract frozen |
| DELETE /webhooks/:id | Remove | contract frozen |
| POST /webhooks/:id/rotate-secret | Rotate signing secret | contract frozen |
| GET /webhooks/deliveries | Delivery log | contract frozen |
| POST /webhooks/deliveries/:id/replay | Replay a delivery | contract frozen |
Retired from the external contract: the GitBook's legacy
/api/v1/quotes/* routes (marked "status undecided" there) do not appear in the new
surface — GET /quotes now means something different (an LP's own outstanding
quotes, not the old quotes resource).
501 —
internal wiring to the real RFQ/swap/report services hasn't landed yet. Don't let the docs
rewrite imply these are callable today.
RFQ flow shift — needs a rewritten walkthrough
This isn't a path rename — the interaction model changed shape:
POST /rfq (institution creates) →
GET /rfq/available →
POST /rfq/{id}/offer (LP) →
POST /rfq/{id}/select/{offerId} (institution) →
POST /rfq/{id}/finalizeGET /rfqs, posts
POST /rfqs/:id/quote (can withdraw via DELETE .../quote/:quoteId
any time before acceptance). Selection/finalization happens on the institution side, outside
the CP contract — see below for how that surfaces to the LP.How an LP integrates — end to end New section
The GitBook has no equivalent walkthrough for the counterparty/LP side specifically — it describes the RFQ mechanics but not the flow an LP's own systems actually run. Quote solicitation supports two modes depending on the LP's own infra; everything downstream of a submitted quote (steps 4–6) is identical either way.
GET /rfqs for open RFQs it's eligible to price — filtered by its configured
supported-pairs and entity tier. The LP decides, on its own schedule, which
open RFQs to price.Poll (A): GET /rfqs returns eligible open RFQs.
Call (B): the platform would POST the RFQ terms to the LP's
registered quote endpoint the moment a taker requests one — no LP-side discovery step at
all. Only (A) exists in the current contract; (B) is a design option, not a route.
Either way, the LP's market-making stack (its own internal pricing — not part of this API) computes a rate. Under (A) this happens on the LP's own schedule after it sees an open RFQ; under (B) it happens synchronously inside the LP's response to the platform's call, so the LP's quoting engine must return within whatever timeout the platform would enforce.
Poll (A): POST /rfqs/:id/quote with the offered rate,
withdrawable via DELETE /rfqs/:id/quote/:quoteId before acceptance.
Call (B): the offer is the LP's synchronous response body to the platform's
inbound call — there's no separate submit step, but also no withdraw window once sent.
Same for both modes from here on. The RFQ engine surfaces the relevant offer(s) to the taker (the institution) on its own side of the marketplace — privacy/anonymization rules determine what the taker sees about the quoting LP.
Acceptance is an institution-side action (outside the CP contract) that finalizes a
swap resource. Gap the LP
surface doesn't currently expose a direct "your quote was accepted" read — this needs to
arrive as a webhook event once the webhook surface is wired, or the LP must poll
GET /swaps for a new swap referencing its accepted quote. (Under Option B, this
same gap applies — a synchronous quote call doesn't imply a synchronous acceptance signal,
since the taker may not accept immediately.)
Once a swap exists, the LP drives its side of settlement entirely through
/external/cp/v1: POST /swaps/:id/canton/prepare +
/canton/execute for its Canton-side leg (thin-client signing — the LP signs a
hash, the platform never holds its key), its own signer for the Ethereum-side leg, and a
report-* call after each verified on-chain step
(report-hashlock → lock → report-htlc-created →
report-{canton,eth}-lock → claim → report-{canton,eth}-claim, or
report-refund on the failure path) until the swap reaches a terminal state.
/external/cp/v1 surface has
no outbound-call mechanism, no LP-side callback registration, and no response-timeout
handling. Treat it as a possible v2 addition, not a current option, until it has its own
PR.Security model — what changed
- Deny-by-default at the edge, not access-checked in application code. The GitBook's security argument rests on the orchestrator being coordination-only; the new model makes non-CP routes structurally unreachable from the internet rather than relying solely on per-route checks.
- Tenant-scoped principal. A partner key resolves to one entity, injected as a signed header — never the cross-tenant internal service credential.
- Instant revocation. Identity-backed key resolution checks authorization status on each call rather than trusting a cached key until TTL expiry.
- WAF exception is an open, tracked launch blocker — LP payloads carry hex hashlocks, addresses, party ids, signatures, and preimages, which trip default managed SQLi/XSS rulesets. Needs a scoped exception for the CP path, validated against a real trade-shaped payload before launch — not yet done.
Known gaps Blocking real testing
- All 28
/external/cp/v1/*handlers return501— contract is frozen, business logic isn't wired. - No container image, ECS task definition, deploy workflow, or ALB routing exists yet for the gateway service in any environment.
- The gateway-to-backend shared signing secret isn't provisioned in any environment's config yet.
- WAF exception for hex-heavy payloads not yet scoped or tested.
- No LP-facing signal for "your quote was accepted" beyond polling — depends on the webhook surface being wired (see step 5 above).
Maintainer notes
Suggested handling per GitBook section:
- Architecture / Overview — replace the "orchestrator is internet-facing" framing with the gateway-fronted model above.
- Integration / Prerequisites, APIs — replace the endpoint tables wholesale; do not just rename paths, the RFQ flow's shape changed (see RFQ flow shift). Add the new "How an LP integrates" walkthrough — nothing in the current GitBook covers the LP-side flow end to end.
- Identity — add the
isk_credential plane and its relationship to the old admin-issued-key model (being retired for external partners). - Security — update the trust-model section; the "you don't need to trust the orchestrator" argument still holds but now for different reasons (network isolation, not just statelessness).
- Reference / Error codes — not evaluated in this pass; revisit once the
handlers are actually wired and returning real error envelopes instead of
501. - Do not publish a base URL in the rewrite until an environment is actually deployed — see Base URL status.