Auto Upi API documentation

Auto Upi is a self-serve UPI collection gateway. Create an order from your server, send the customer to the hosted checkout page, and the order is confirmed automatically — no commission, no reconciliation, money straight into your UPI account.

BASE URLhttps://autoupi.in/api/public/v1
FORMATapplication/json
AUTH HEADERX-API-Key

Quickstart

  1. Create an account and sign in to the merchant console.
  2. Connect an account — pick PhonePe or Paytm and complete the setup on the Connect Accounts page.
  3. Generate an API key on the API Keys page. Copy it once; regenerating replaces the old key.
  4. Create an order from your server and redirect the customer to the returned payment_url.
  5. Confirm the payment through the status endpoint or your webhook, then fulfil the order.

Authentication

Every request carries your secret key in the X-API-Key header. Keys start withaupi_live_ and are stored hashed — an old key can never be shown again. Call the API only from your server; never expose the key in browser code.

header
X-API-Key: aupi_live_xxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json

Create order

POST /api/public/v1/create-order

FieldTypeRequiredDescription
amountnumberYesOrder amount in INR, 1 to 10,00,000.
customer_namestringNoShown on the checkout page.
webhook_urlstringNoHTTPS URL that receives the signed payment.paid webhook.
link_typestringNoone_time (default) or reusable.
curl
curl -X POST https://autoupi.in/api/public/v1/create-order \
  -H "X-API-Key: aupi_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{"amount": 1499, "customer_name": "Rahul Sharma", "webhook_url": "https://yoursite.com/autoupi-webhook.php"}'
200 response
{
  "ok": true,
  "order_id": "ORD20260915A1B2C3",
  "slug": "9fkq2wra",
  "amount": 1499,
  "payable_amount": 1499.37,
  "status": "active",
  "payment_url": "https://autoupi.in/pay/9fkq2wra"
}

Always charge payable_amount: it can differ from amount by up to ₹0.99 so each active order stays unique. The customer pays payable_amount; your books are credited with the base amount.

Order status

GET /api/public/v1/order-status?order_id=ORD…

Poll this endpoint from your server (or after the customer returns) to confirm a payment before fulfilment.

curl
curl "https://autoupi.in/api/public/v1/order-status?order_id=ORD20260915A1B2C3" \
  -H "X-API-Key: aupi_live_your_key"
200 response
{
  "ok": true,
  "order": {
    "order_id": "ORD20260915A1B2C3",
    "slug": "9fkq2wra",
    "customer_name": "Rahul Sharma",
    "amount": 1499,
    "payable_amount": 1499.37,
    "status": "paid",
    "payer_name": "RAHUL SHARMA",
    "paid_at": "2026-09-15T10:21:44.120Z",
    "detected_at": "2026-09-15T10:21:52.480Z",
    "expires_at": "2026-09-15T10:26:00.000Z"
  }
}
StatusMeaning
activeWaiting for payment. Links expire 5 minutes after creation.
paidA matching credit alert was detected. Safe to fulfil.
expiredNo payment detected in time. Create a new order.

Webhooks

Each API key ships with a webhook secret (whsec_…) shown on the API Keys page. Pass awebhook_url when creating an order and we POST a signed payment.paid event the moment the order is confirmed as paid.

payload
POST https://yoursite.com/autoupi-webhook.php
X-AutoUpi-Signature: t=1789453200,v1=6f3c…9ab

{
  "event": "payment.paid",
  "order_id": "ORD20260915A1B2C3",
  "amount": 1499,
  "payable_amount": 1499.37,
  "status": "paid",
  "payer_name": "RAHUL SHARMA",
  "paid_at": "2026-09-15T10:21:44.120Z"
}

signed_payload = "{t}." + raw_request_body
v1 = hex(hmac_sha256(webhook_secret, signed_payload))
php
<?php
// autoupi-webhook.php
$secret = "whsec_your_webhook_secret";
$raw    = file_get_contents("php://input");
$header = $_SERVER["HTTP_X_AUTOUPI_SIGNATURE"] ?? "";

parse_str(str_replace(",", "&", $header), $parts);   // t=..., v1=...
$expected = hash_hmac("sha256", $parts["t"] . "." . $raw, $secret);

if (!hash_equals($expected, $parts["v1"] ?? "")) {
  http_response_code(401);
  exit("bad signature");
}

$event = json_decode($raw, true);
if ($event["event"] === "payment.paid") {
  // idempotent: skip if this order_id is already fulfilled
  mark_order_paid($event["order_id"], $event["amount"]);
}
http_response_code(200);
echo "ok";

Always treat delivery as at-least-once and keep your handler idempotent.

PHP integration in 3 files

Copy these three files into any PHP site (WordPress, Laravel, CodeIgniter or plain PHP). Only the API key, webhook secret and your database calls need changing.

1. autoupi.php — tiny helper class
<?php
class AutoUpi {
  private string $key;
  private string $base;

  public function __construct(string $key, string $base = "https://autoupi.in/api/public/v1") {
    $this->key = $key;
    $this->base = $base;
  }

  private function request(string $url, ?array $body = null): array {
    $ch = curl_init($url);
    $headers = ["X-API-Key: {$this->key}"];
    if ($body !== null) {
      $headers[] = "Content-Type: application/json";
      curl_setopt($ch, CURLOPT_POST, true);
      curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
    }
    curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => $headers, CURLOPT_TIMEOUT => 20]);
    $res = json_decode(curl_exec($ch), true);
    curl_close($ch);
    return is_array($res) ? $res : ["ok" => false, "error" => "network_error"];
  }

  public function createOrder(float $amount, string $customer = "", string $webhook = ""): array {
    return $this->request($this->base . "/create-order", [
      "amount" => $amount,
      "customer_name" => $customer,
      "webhook_url" => $webhook,
    ]);
  }

  public function status(string $orderId): array {
    return $this->request($this->base . "/order-status?order_id=" . urlencode($orderId));
  }

  public static function verify(string $raw, string $header, string $secret): bool {
    parse_str(str_replace(",", "&", $header), $p);
    if (empty($p["t"]) || empty($p["v1"])) return false;
    return hash_equals(hash_hmac("sha256", $p["t"] . "." . $raw, $secret), $p["v1"]);
  }
}
2. checkout.php — start a payment
<?php
require "autoupi.php";
$api = new AutoUpi("aupi_live_your_key");

$order = $api->createOrder(1499, "Rahul Sharma", "https://yoursite.com/autoupi-webhook.php");

if (empty($order["ok"])) {
  die("Could not start payment: " . ($order["error"] ?? "unknown"));
}

// store it so the webhook can find the buyer later
save_order($order["order_id"], $_SESSION["user_id"], $order["amount"]);

header("Location: " . $order["payment_url"]);
exit;
3. autoupi-webhook.php — get paid automatically
<?php
require "autoupi.php";

$raw = file_get_contents("php://input");
$sig = $_SERVER["HTTP_X_AUTOUPI_SIGNATURE"] ?? "";

if (!AutoUpi::verify($raw, $sig, "whsec_your_webhook_secret")) {
  http_response_code(401);
  exit("bad signature");
}

$event = json_decode($raw, true);
if (($event["event"] ?? "") === "payment.paid") {
  // amount = your original order value; payable_amount = what the customer actually paid
  mark_order_paid($event["order_id"], $event["amount"]);
}

http_response_code(200);
echo "ok";

No webhook endpoint yet? Poll order-status on your thank-you page instead — the result is the same, just a few seconds slower.

Errors

HTTPCodeFix
401invalid_api_keyKey missing, revoked or replaced by a regenerate.
400invalid_amountAmount must be greater than 0 and up to 10,00,000.
400UPI_NOT_CONFIGUREDSave a UPI ID on Connect Accounts first.
400QUOTA_EXCEEDEDQR limit finished — upgrade to Pro.
400ALL_PAYMENT_SLOTS_BUSYToo many pending orders at the same amount; retry shortly.
404not_foundThe order ID does not belong to this key.

Pricing

No per-transaction commission — you collect straight into your own UPI account.

Free

₹0to get started
  • 3 payment QR codes total
  • 1 merchant account
  • Full REST API access
  • Automatic payment confirmation
Create account

Custom

Talk to ushigh volume
  • Higher QR limits
  • Multiple merchant accounts
  • Self-hosted deployment
  • Dedicated support
Contact sales

FAQ

Do I need a payment gateway account?

No. Money reaches your own UPI account directly; Auto Upi only confirms and records the order.

What if two customers pay the same amount?

They can't — each active order carries its own unique payable_amount.

How long is a link valid?

5 minutes. After that the order becomes expired and moves to Transactions.

Which PHP version do I need?

PHP 7.4 or newer with the cURL extension — no composer package required.

Can I regenerate my API key?

Yes. Regenerating issues a new key and instantly disables the previous one.