Skip to content

Platform capability

One API across every provider

One request format, one status model and one error model, whichever provider processes the payment. Provider-specific detail is kept for when you need it.

  • Status values that mean the same thing everywhere
  • Errors grouped by cause, with the raw code kept
  • Idempotent by design
Same payment, three providersIllustrative

Three providers report the same successful payment with different field names and status values. Peneu returns one payment object with a single status, the provider name and the provider's own reference kept for traceability.

Status model

One set of statuses

Every provider has its own vocabulary for the same states. Your code only has to deal with these.

Peneu statusMeaningWhat providers call it
createdThe payment exists, with no attempt yet—
processingWith a provider, waiting on the customer or the bankPENDING, initiated, in_progress
authorizedApproved. For cards, capture may followSUCCESS, captured, 00
failedFinal failure, with a category that says whyFAILED, declined, 05
refunded / partially_refundedOne or more refunds completedREFUNDED, refund.processed

The provider examples are illustrative. Mappings are maintained per provider.

Requests and responses

The same shapes, whichever provider is behind them

  • Amounts are integers in paise, so there are no floating-point surprises
  • Illustrative. The full reference is shared with sandbox access
Illustrative
POST /v1/payments
Idempotency-Key: order-10234-1

{
  "amount": 245000,
  "currency": "INR",
  "method": "card",
  "reference_id": "order-10234",
  "metadata": { "cart_id": "c_8812" }
}
GET /v1/payments/pay_7Hq2

{
  "id": "pay_7Hq2",
  "status": "authorized",
  "amount": 245000,
  "reference_id": "order-10234",
  "provider": "provider_b",
  "provider_ref": "9913…",
  "method_details": { "network": "rupay", "last4": "4242" }
}
{
  "error": {
    "type": "payment_failed",
    "category": "issuer_unavailable",
    "message": "The issuing bank did not respond.",
    "retryable": true,
    "provider": "provider_a",
    "provider_code": "91"
  }
}

Design choices

Built for the edge cases

  • 01

    Idempotency keys

    Send the same key twice and you get the same payment back, not a second one. Retries on your side are safe.

  • 02

    Your references, everywhere

    reference_id and metadata travel with the payment into every webhook, export and report.

  • 03

    Provider references kept

    Bank RRNs, UTRs and provider IDs stay on the payment. You'll need them for disputes and support tickets.

  • 04

    Errors grouped by cause

    customer, issuer, provider or risk, plus a retryable flag, so your checkout can decide what to tell the customer.

  • 05

    Separate environments

    Sandbox and production have separate keys and separate data. A test payment can never touch real money.

  • 06

    Provider changes stay on our side

    When a provider changes its API or response codes, the mapping is updated in Peneu. Your integration keeps the same shapes.

Worth knowing

What stays method-specific

The API normalises the lifecycle, not the rules of each payment rail. UPI still needs an app switch or a QR, cards still need authentication, and netbanking still redirects to the bank. The API tells you which next step the method needs, and your checkout shows it.

Some fields only exist for some methods, like a UPI VPA or a card network. They live under method_details instead of being forced into a shape they don't fit.

Evaluating it

Questions to ask about this, of any provider

Use these with any platform, including Peneu. For Peneu, what's available for your business is confirmed during onboarding.

Is there one status model for every provider?
Mapping each provider's statuses yourself is where integration bugs hide.
Are errors normalised, with the original reason kept?
You need a common error to act on and the provider's reason to investigate.
Are money-moving requests idempotent?
Retries after timeouts must not create duplicate charges, refunds or payouts.
How are API keys scoped and rotated?
Keys per environment, kept server-side, and rotated when people leave.

FAQ

Questions about unified api

Can I still see what the provider actually returned?

Yes. The provider name, its reference and its raw response code are kept on every payment and error.

Do I need an idempotency key on every request?

On every request that creates something, like a payment or a refund, yes. It's what makes network retries on your side safe.

How are refunds handled across providers?

Through one refund call against the Peneu payment ID. The refund goes back through the provider that processed the original payment, as it has to.

Read the full reference

Request sandbox access and you'll get test keys and the complete API reference, including the status and error mappings per provider.

Last reviewed . Samples on this page are illustrative.