Ginger Payments

Quickstart

Create your first test payment with the Ginger Payments API and hosted payment page in about 10 minutes.

In this quickstart you create an order through the API, pay it on the hosted payment page in test mode, and confirm the result with a webhook and a status request. No money moves.

You need:

  • A Ginger Payments test account.
  • A server that can make HTTPS requests. The examples use cURL, Node.js 18+, Python 3 and PHP.
  • For the webhook step: a URL that's reachable from the internet. On your own machine, use a tunnelling tool to expose your local server.

Get your test API key

  1. Log in to the merchant portal at https://admin.dev.gingerpayments.com.
  2. Create a project in test mode, or open an existing test project.
  3. Go to Settings > API Key and copy the key.

Store the key as an environment variable on your server, so it doesn't end up in your code:

export API_KEY="your-test-api-key"

Keep your API key secret

The API key gives full access to your project. Only use it from your server. Never put it in a browser, mobile app or public repository.

Check your connection

The API uses HTTP Basic authentication: your API key is the username and the password is empty. Retrieve your project to check that the key works:

curl https://api.dev.gingerpayments.com/v1/merchants/self/projects/self/ \
  --user "$API_KEY:"

A 200 OK response with your project details means you're connected. A 401 Unauthorized response means the API key is wrong.

Create an order

Create an order for € 9.95. The amount is in cents.

curl https://api.dev.gingerpayments.com/v1/orders/ \
  --user "$API_KEY:" \
  --header "Content-Type: application/json" \
  --data '{
    "currency": "EUR",
    "amount": 995,
    "merchant_order_id": "QUICKSTART-001",
    "description": "Quickstart test order",
    "return_url": "https://www.example.com/order/QUICKSTART-001",
    "webhook_url": "https://www.example.com/webhook"
  }'

Replace the return_url and webhook_url with URLs of your own server. The API responds with the new order:

{
  "id": "1c969951-f5f1-4290-ae41-6177961fb3cb",
  "currency": "EUR",
  "amount": 995,
  "merchant_order_id": "QUICKSTART-001",
  "description": "Quickstart test order",
  "return_url": "https://www.example.com/order/QUICKSTART-001",
  "webhook_url": "https://www.example.com/webhook",
  "created": "2026-10-12T11:41:57.121017+00:00",
  "modified": "2026-10-12T11:41:57.183822+00:00",
  "order_url": "https://api.dev.gingerpayments.com/pay/1c969951-f5f1-4290-ae41-6177961fb3cb/",
  "status": "new"
}

Save the id: you need it to look up the order later.

FieldRequiredDescription
currencyYesISO 4217 currency code, such as EUR.
amountYesAmount in the smallest currency unit: 995 is € 9.95.
merchant_order_idNoYour own order reference, shown in the merchant portal.
descriptionNoDescription of the order.
return_urlNoWhere your customer goes after paying. Without it, your customer stays on the Ginger Payments result page.
webhook_urlNoWhere status changes are sent. Overrides the webhook URL of the project for this order.

Pay on the hosted payment page

Redirect your customer to the order_url. For this test, open it in your browser.

The hosted payment page shows every payment method that's active in your project. Select one and complete the payment with test details. For test card numbers, see Test data.

After the payment, the browser goes to your return_url.

Don't rely on the redirect alone

Your customer can close the browser before they're redirected, and anyone can open your return_url. Always check the order status from your server before you show a confirmation or deliver.

Handle the webhook

When the order status changes, Ginger Payments sends a POST request to your webhook_url:

{
  "event": "status_changed",
  "order_id": "1c969951-f5f1-4290-ae41-6177961fb3cb",
  "project_id": "b5f39273-44e7-4385-8e08-44612ef3e117"
}

The webhook deliberately doesn't contain the status. See Webhooks for the full delivery rules. Retrieve the order from the API, so you only act on data that comes from Ginger Payments directly:

import express from 'express';

const app = express();
app.use(express.json());

const authorization = `Basic ${Buffer.from(`${process.env.API_KEY}:`).toString('base64')}`;

app.post('/webhook', async (req, res) => {
  try {
    const response = await fetch(`https://api.dev.gingerpayments.com/v1/orders/${req.body.order_id}/`, {
      headers: { Authorization: authorization },
    });
    if (!response.ok) throw new Error(`Status request failed: ${response.status}`);

    const order = await response.json();
    await updateOrderInYourShop(order.merchant_order_id, order.status);
    res.sendStatus(200);
  } catch (error) {
    console.error(error);
    res.sendStatus(500); // Ginger Payments retries the webhook
  }
});

app.listen(3000);

updateOrderInYourShop and update_order_in_your_shop stand for your own code that stores the status.

Keep these rules in mind:

  • Respond fast. Return a 2xx response within 4 seconds. Any other response, or a timeout, counts as a failure.
  • Expect retries. After a failure, Ginger Payments retries every 2 minutes, up to 10 attempts. Your handler can receive the same notification more than once, so make it safe to process twice.
  • Have a backup. A webhook can be delayed or lost. Regularly check the status of orders that aren't final after 10 minutes, or a period that suits your business.
  • Allow the traffic. If a firewall or bot protection runs in front of your server, make sure it doesn't block webhook requests.

Check the status

Retrieve the order to see the result of the payment. Do the same when your customer lands on your return_url:

curl https://api.dev.gingerpayments.com/v1/orders/1c969951-f5f1-4290-ae41-6177961fb3cb/ \
  --user "$API_KEY:"
{
  "id": "1c969951-f5f1-4290-ae41-6177961fb3cb",
  "amount": 995,
  "currency": "EUR",
  "merchant_order_id": "QUICKSTART-001",
  "status": "completed",
  "completed": "2026-10-12T11:43:12.402150+00:00",
  "transactions": [
    {
      "id": "058cf70d-7a84-4957-941c-532c065cef72",
      "payment_method": "credit-card",
      "status": "completed"
    }
  ]
}

The response is shortened. Act on the order status:

StatusWhat to do
completedThe payment succeeded. Confirm the order and deliver.
new, processingNot final yet. Show a "payment pending" message and wait for the next webhook.
cancelled, expired, errorNo payment. Let your customer try again.

You've created, paid and confirmed your first test payment.

Next steps

On this page