JCPay· Ganap compatibility

Ganap compatibility

Already integrated with Ganap? You don't have to touch your integration code. JCPay exposes a Ganap-shaped endpoint so you change one URL constant and ship. Same request body, same sk: header, same webhook callback shape.

The one-line migration

Replace your base URL:

- https://api.ganap.net
+ https://jcpay.innoserver.cloud

That's it. Your externalId, amount constraints (0 or 200–50000), success/failure redirects, payer email/name, and sk: auth continue to work unchanged.

Create a checkout

curl -X POST "https://jcpay.innoserver.cloud/api/merchant-project/<YOUR_PROJECT_UUID>/webhook-checkout" \
  -H "Content-Type: application/json" \
  -H "sk: sk_gnp_<YOUR_SECRET>" \
  -d '{
    "externalId": "ORDER-123",
    "amount": 500,
    "successRedirectURL": "https://yourgame.example/payment/success",
    "failureRedirectURL": "https://yourgame.example/payment/failed",
    "payerEmail": "player@example.com",
    "payerName": "Player Handle"
  }'

Response is dual-shaped — whichever key your existing Ganap client reads, it still works:

{
  "status": "pending",
  "externalId": "ORDER-123",
  "external_id": "ORDER-123",
  "amount": 500,
  "checkoutUrl":  "https://jcpay.innoserver.cloud/sandbox/checkout/pay_...",
  "checkout_url": "https://jcpay.innoserver.cloud/sandbox/checkout/pay_...",
  "reference":        "mck_...",
  "referenceNumber":  "mck_...",
  "reference_number": "mck_..."
}

Rules

  • externalId must be unique per transaction; doubles as your idempotency key — replays with the same value return the existing payment.
  • amount must be 0 (free) or between 200 and 50000, PHP.
  • Path id accepts either the project UUID or its slug.
  • Authorization is sk: sk_gnp_<secret> — note the custom header name, not Authorization: Bearer.

Webhook callback

When the payment reaches a terminal state, JCPay POSTs a Ganap-shaped payload to your configured webhook URL with the static key in a query param:

POST https://your-domain.example/topup/webhook?key=<YOUR_STATIC_KEY>
Content-Type: application/json

{
  "status": "success",
  "externalId": "ORDER-123",
  "referenceNumber": "mck_...",
  "amount": 500
}

Auth is the query param — no HMAC signature header. Verify that keymatches the one you registered, and use externalId to reconcile against your order.

Status enum

JCPay internalDelivered asWhen
succeededsuccessCustomer paid; funds settled to your ledger.
failedfailedCustomer attempt declined / cancelled.
expiredexpiredCheckout window elapsed without a decision (15 min default).
processingprocessingProvider accepted but not yet finalized. Rare intermediate state.

Delivery + retries

  • Webhook deliveries retry on non-2xx at 1m, 5m, 30m, 2h, 6h, 24h, then mark failed.
  • Delivery timeout: 10 seconds per attempt.
  • No HMAC in this mode. If you want signed webhooks, switch the endpoint to JCPay's native /v1/payments flow (see Webhooks).

Getting a project

Ganap-compat projects are provisioned by the JCPay team today. Give us (a) the merchant account you want to bind, (b) your current Ganap webhook URL, (c) the static key you use on that URL. We return your project_uuid and sk_gnp_<secret>— the secret is shown once.

Upgrading later

Once you're on JCPay, you can migrate to the native /v1/payments API at your own pace to gain HMAC-signed webhooks, Idempotency-Key headers, multiple payment methods per merchant, and a self-service dashboard. Compat mode stays running in parallel — no forced cutover.