View as Markdown

llms.txt

This guide isn't available right now

This instance couldn't load its guide catalog. The guide returns as soon as the catalog is readable again.

Back to the guides

No such guide

This instance publishes no guide under that address. It may have been renamed, or it may belong to a feature this installation hasn't enabled.

Back to the guides

That guide is part of the product documentation

This guide is written for someone operating WinkPG through its screens rather than integrating against it, so it lives in the application's own help section instead of here. Sign in to WinkPG and open Help to read it.

Back to the guides

Guides Quickstart

Quickstart: Hosted payment page

Create a hosted page, open a session for one payment, and send the payer to it without card data touching your server.

WinkPG serves the hosted payment page and the payer enters their card on it. Your server never sees a card number, which keeps the card fields out of your PCI scope entirely.

Two objects matter, and getting the difference right before you write anything saves rework. A page is the reusable configuration: how it looks, what it accepts, where it sends the payer afterward. A session is one payer's one visit, carrying the amount and the order reference. Create the page once. Open a session per payment.

You need the base address of your WinkPG deployment and an API key.

1. Create the page

Do this once, then keep the id. Creating a page per payment is the common first mistake and leaves you with a list you can't manage.

curl -X POST "https://your-gateway-host/api/hostedpaymentpages" \
  -H "api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "merchantId": "{merchantId}",
    "name": "Online checkout",
    "isActive": true,
    "allowCustomAmount": false,
    "successRedirectUrl": "https://example.test/thank-you"
  }'

The response carries the page's id. Save it in your configuration next to your API key.

2. Open a session

curl -X POST "https://your-gateway-host/api/hostedpaymentpages/sessions" \
  -H "api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "hostedPageId": "{hostedPageId}",
    "label": "Order 1042",
    "amountMode": "Locked",
    "prefilledFields": { "base_amount": "10.00" },
    "expirySeconds": 900
  }'

If you take commercial cards, prefilledFields also carries po_number, the customer code / purchase order the buying organization reconciles the charge against. It's letters and digits only, up to 25 characters (a reference you write as PO-4471 travels as PO4471). The page decides whether the field is Hidden, Optional or Required, and the key is accepted only on a page that renders the field. A malformed value is rejected when you create the session, not when the payer pays. A prefilled value stays editable so the payer can correct it. See the hosted page's field configuration for where to turn it on.

amountMode decides who sets the figure. Locked fixes it, which is what an order total wants: the field renders read-only and the server checks every submitted payment against the session's amount, so editing the page or replaying the request reaches the same outcome. Suggested pre-fills a figure the payer can still change, and CustomerEntered (the default) leaves the amount to them.

The same two calls in C#:

using var http = new HttpClient { BaseAddress = new Uri("https://your-gateway-host") };
http.DefaultRequestHeaders.Add("api-key", "YOUR_API_KEY");

var pageResponse = await http.PostAsJsonAsync("/api/hostedpaymentpages", new
{
    merchantId = MERCHANT_ID,
    name = "Online checkout",
    isActive = true,
    allowCustomAmount = false,
    successRedirectUrl = "https://example.test/thank-you"
});

pageResponse.EnsureSuccessStatusCode();
var hostedPageId = (await pageResponse.Content.ReadFromJsonAsync<JsonElement>())
    .GetProperty("id").GetString();

var sessionResponse = await http.PostAsJsonAsync("/api/hostedpaymentpages/sessions", new
{
    hostedPageId,
    label = "Order 1042",
    amountMode = "Locked",
    prefilledFields = new Dictionary<string, string> { ["base_amount"] = "10.00" },
    expirySeconds = 900
});

sessionResponse.EnsureSuccessStatusCode();
var sessionId = (await sessionResponse.Content.ReadFromJsonAsync<JsonElement>())
    .GetProperty("id").GetString();

Ask for the address rather than assembling one from the session id. The link is issued for this session, and an assembled one stops working the moment the address scheme changes.

curl "https://your-gateway-host/api/hostedpaymentpages/sessions/{sessionId}/payment-link" \
  -H "api-key: YOUR_API_KEY"

The response body is the address itself, as a plain string:

https://pay.your-environment.example/s/8f14e45fceea167a

4. Send the payer to it

Redirect the browser at that address:

HTTP/1.1 303 See Other
Location: https://pay.your-environment.example/s/8f14e45fceea167a

The payer enters their card on the page WinkPG serves, and is returned to the successRedirectUrl you configured.

Treat that return as a hint that the payment finished, not as proof of it. A payer who pays and then closes the tab never comes back, and nothing about your success page can tell you whether that happened. The webhook is what tells you, and it arrives either way.

5. Reconcile from the webhook

Subscribe to the transaction events, verify the signature on each delivery, and take the transaction id from the body. Then read the transaction the same way any other integration does:

curl "https://your-gateway-host/api/transactions/{transactionId}" \
  -H "api-key: YOUR_API_KEY"

However the payment was collected, the record it produces is one transaction.

Next steps

Reconnecting to the server

Could not reconnect

This session has ended

Attempt 1

Your work on this page is still here. Retrying keeps it; reloading starts the page again.

The server no longer holds this page's state, so it has to be loaded again.