Skip to main content
GET /checkout/:shopUrl/payment-intent-resolver is the public endpoint the checkout-spa calls on page load to determine which payment methods to render. It does not require a JWT — shopUrl is the only input, and the response is safe to expose publicly because it contains only payment-method capabilities, never customer state or secrets.
This endpoint is public — no JWT, no IpAllowlistGuard, no GeoBlockGuard. It is rate-limited per IP via the standard public-endpoint policy (60 req/min/IP). Cached at the CDN for 60s keyed on shopUrl.

When to use

Call this once at checkout page load to know which payment renderer to mount. The response tells the FE:
  • Which card processor to use (Stripe / Telr / Paymob / Bonum / null) + the right publishableKey
  • Whether to show PayPal
  • Whether to show crypto (Coinbase Commerce)
  • Whether to show wallet (Apple Pay / Google Pay tokens — routed through Bonum or Stripe depending on the merchant config)
  • The merchant’s checkout currency
  • Resolver meta — the source-of-truth chain the resolver walked (useful for debugging “why am I seeing Stripe instead of Telr?”)

Source-of-truth resolution chain

The resolver walks the following sources in order, returning the first non-null match per payment method:
1

shopPaymentMethodsV2

The merchant’s explicit per-shop payment-method config. If a method is explicitly disabled here, it short-circuits — later sources cannot re-enable it.
2

Partnership preset (when #1575 lands per-merchant config)

If the merchant belongs to a partnership (e.g. shopsadiq-telr-gcc), the preset’s default card processor is applied. Currently in active rollout — once #1575 fully lands per-merchant config, this step becomes the canonical source for partnership merchants.
3

KYB cohort

The merchant’s kybCohort (one of 8 enum values) drives the regional default — e.g. GCC cohorts default to Telr, Mongolia cohorts default to Bonum, US cohorts default to Stripe.
4

PSP breaker

If the candidate PSP’s circuit breaker is open, the resolver falls through to the next viable option. The skipped PSP is recorded in meta.skippedByBreaker[].
5

publishableKey lookup

Final step — fetches the right publishable key from the per-PSP config (per-merchant override if present, else env default).
The full walk is summarized in the meta field of the response, so a FE engineer can inspect a single response and understand exactly why a given renderer was chosen.

GET /checkout/:shopUrl/payment-intent-resolver

Authentication

None — public endpoint. Rate-limited per IP (60 req/min).

Path parameters

ParamTypeRequiredDescription
shopUrlstringYesThe shop’s subdomain (e.g. unstoppable for unstoppable.droplinked.io)

Response — 200 OK

{
  "card": {
    "provider": "telr",
    "label": "Card",
    "accountId": "telr-shopsadiq-master",
    "renderer": "telr-hosted",
    "publishableKey": null
  },
  "paypal": {
    "enabled": true,
    "clientId": "AYxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "currency": "AED",
    "intent": "capture"
  },
  "crypto": {
    "enabled": false,
    "provider": null
  },
  "wallet": {
    "applePay": true,
    "googlePay": true,
    "tokenProvider": "telr"
  },
  "currency": "AED",
  "meta": {
    "shopId": "65f8a1b2c3d4e5f6a7b8c9bb",
    "merchantId": "65f8a1b2c3d4e5f6a7b8c9aa",
    "kybCohort": "A-MoR-Shopsadiq-via-Telr",
    "partnership": "shopsadiq-telr-gcc",
    "resolvedAt": "2026-06-04T12:00:00.000Z",
    "chain": [
      { "step": "shopPaymentMethodsV2", "result": "no-explicit-override" },
      { "step": "partnership-preset",   "result": "telr-via-shopsadiq" },
      { "step": "kyb-cohort",           "result": "skipped (resolved earlier)" },
      { "step": "psp-breaker",          "result": "telr-closed" },
      { "step": "publishable-key",      "result": "telr-hosted-no-publishable-key" }
    ],
    "skippedByBreaker": []
  }
}

Field reference

card — primary card renderer (or null if no card processor is wired)

FieldTypeDescription
providerenum (stripe | telr | paymob | bonum)Which PSP processes the card payment
labelstringHuman-readable label for the renderer (“Card”, “Credit/Debit Card”)
accountIdstringThe PSP-side account / terminal / merchant ID — informational only
rendererenum (stripe-elements | telr-hosted | paymob-iframe | bonum-hosted)Which renderer component the FE should mount
publishableKeystring | nullThe PSP’s client-side publishable key. null when the renderer is hosted-only (Telr, Bonum)

paypal

FieldTypeDescription
enabledbooleanWhether to show the PayPal button
clientIdstring | nullPayPal client ID for the JS SDK
currencystringThree-letter ISO currency for the PayPal order
intentenum (capture | authorize)PayPal intent mode

crypto

FieldTypeDescription
enabledbooleanWhether to show the crypto-pay option
providerenum (coinbase) | nullCrypto processor; only coinbase is currently wired

wallet

FieldTypeDescription
applePaybooleanWhether to render Apple Pay
googlePaybooleanWhether to render Google Pay
tokenProviderenum (stripe | telr | bonum)Which PSP consumes the wallet token

currency

The merchant’s checkout currency. Format three-letter ISO 4217 (USD, AED, MNT, EUR).

meta

Informational only — not consumed by the renderer. Captures kybCohort, partnership, the full resolution chain, and any PSPs skipped because their breaker was open.

Response — 200 OK with no card processor

{
  "card": null,
  "paypal": { "enabled": true, "clientId": "...", "currency": "USD", "intent": "capture" },
  "crypto": { "enabled": false, "provider": null },
  "wallet": { "applePay": false, "googlePay": false, "tokenProvider": null },
  "currency": "USD",
  "meta": { "...": "..." }
}
Returned when the merchant has no card processor wired (e.g. PayPal-only merchant, or every candidate PSP has an open breaker).

Error responses

StatusWhen
404shopUrl does not resolve to an active shop
410Shop exists but is suspended / archived
429Rate limit exceeded for caller IP

Example

curl https://apiv3.droplinked.com/checkout/unstoppable/payment-intent-resolver

JavaScript example

const res = await fetch(
  `https://apiv3.droplinked.com/checkout/${shopUrl}/payment-intent-resolver`
);
const intent = await res.json();

if (intent.card) {
  mountCardRenderer({
    renderer: intent.card.renderer,
    publishableKey: intent.card.publishableKey,
  });
}

if (intent.paypal.enabled) {
  mountPayPalButton({
    clientId: intent.paypal.clientId,
    currency: intent.paypal.currency,
    intent: intent.paypal.intent,
  });
}

if (intent.wallet.applePay || intent.wallet.googlePay) {
  mountWallet({ tokenProvider: intent.wallet.tokenProvider });
}

Debugging

When the FE renders the wrong processor (e.g. Stripe when you expected Telr), inspect the meta.chain field — it explains exactly which step resolved the card processor. The most common reasons for an unexpected provider are:
SymptomLikely cause
Stripe rendered for a GCC merchantshopPaymentMethodsV2 has an explicit Stripe override; remove it
card: null for a merchant that has Telr wiredTelr breaker is open — check PSP health
card.publishableKey: null but renderer is stripe-elementsThe per-merchant Stripe config is missing the publishable key — re-write via aggregate provisioner
  • Bonum admin — per-merchant Bonum config (affects wallet.tokenProvider).
  • Telr admin — Telr reconcile (does not affect resolver output directly, but breaker state does).
  • PSP health — breaker state for every PSP the resolver consults.
  • Aggregate merchant provisioner — partnership-preset writes that drive resolver defaults.