Custom integration

Already have your own payment integration — your own card vault, your own arrangement with a provider, anything? Connect it directly. SubCharge never talks to a payment network on your behalf here: it only calls two HTTPS endpoints you host, both signed with a shared secret you choose.

What you implement

EndpointPurpose
checkoutUrlWe redirect the customer here to capture (and optionally charge) a payment method — your own page, your own flow
chargeUrlWe POST here to request an off-session charge on a previously captured method

Every request we send is signed: X-Signature: t=<unix>,v1=<hex HMAC-SHA256(secret, "t.canonical")> — the same scheme as our outbound webhooks.

1. Checkout redirect

We send the customer's browser to checkoutUrl with a reference, the amount, where to send them back, and a notify_url — all signed. Capture the payment method however you like; it never runs on our page. When you're done, redirect back and separately POST the outcome (step 3) — we never infer success from the browser redirect alone.

2. Off-session charge

POST chargeUrl
X-Signature: t=...,v1=...
Idempotency-Key: chg_...

{ "tokenRef": "...", "amountCents": 12345, "reference": "chg_...", "description": "...", "idempotencyKey": "chg_..." }

Answer synchronously if you can, or just acknowledge with a bare 2xx and settle later via step 3 — we treat that as pending and wait. A 5xx or a dropped connection is treated as unknown, never as failed: we won't charge again until we've heard back one way or the other.

3. Notify us

POST notify_url
X-Signature: t=...,v1=...

{ "status": "succeeded", "reference": "chg_...", "providerPaymentId": "...", "amountCents": 12345 }

status is succeeded, failed (add a declineCategory of soft or hard if you can — hard stops automatic retries) or pending. reference must exactly match what we gave you — an unrecognised reference is a silent 200, not an error, so check your own logs if a notification seems to go missing.

This contract has no status/lookup endpoint, so an unresolved charge can't be automatically retried — make sure your system always eventually sends a notification for every charge it accepts. Refunds and remote token revocation aren't part of this contract either; handle those directly in your own system.