Skip to content
New Hire a PD CASH engineer to connect payments to your website: Basic $100 · Advanced $500 · Custom quoteHire an engineer from $100 See plans

Cash App payments API and webhooks

PD CASH is an orchestration layer, not Cash App’s official API. Launch hosted checkout on an approved provider or channel-partner route, then connect signed status and automation.

Free planCash AppCrypto

After reviewApple PayGoogle PayPayPal

No deposit on the free plan. Paid plans need a review, a $10 identity check and a refundable security deposit.

Or sign up with email · By continuing you agree to the Terms, Privacy Policy and Acceptable Use Policy.

create-invoice → payment_url → webhook
// 1. your server creates the invoice
POST https://pd.cash/api/v1/create-invoice
{ "amount": 25.00, "brand_slug": "MyStore",
  "order_reference": "ORDER-12345",
  "webhook_url": "https://yoursite.com/webhook" }

// 2. PD CASH answers in the same request
{ "success": true,
  "payment_url":
    "https://pd.cash/pay/@MyStore/AB12CD34EF56GH78",
  "data": { "invoice": { "status": "pending", … } } }

// 3. customer pays; signed webhook hits your URL
X-Webhook-Event: payment.completed
X-Webhook-Signature: sha256=9f3c…c21e
{ "event": "payment.completed",
  "order_reference": "ORDER-12345",
  "amount": 25.00, "currency": "USD",
  "status": "completed" }

Illustrative exchange, trimmed. Keys and headers match the API reference.

One POST returns a payment URL

The full reference covers every endpoint, webhook signature, and error code.

Request
POST https://pd.cash/api/v1/create-invoice
Content-Type: application/json
X-API-Key: pk_your_api_key_here
X-API-Secret: sk_your_secret_here

{
  "amount": 100.00,
  "brand_slug": "MyStore",
  "order_reference": "ORDER-12345",
  "customer_email": "customer@example.com",
  "webhook_url": "https://yoursite.com/webhook"
}
curl -X POST https://pd.cash/api/v1/create-invoice \
  -H "Content-Type: application/json" \
  -H "X-API-Key: pk_your_api_key_here" \
  -H "X-API-Secret: sk_your_secret_here" \
  -d '{"amount": 100.00, "brand_slug": "MyStore", "order_reference": "ORDER-12345",
       "customer_email": "customer@example.com", "webhook_url": "https://yoursite.com/webhook"}'
const res = await fetch("https://pd.cash/api/v1/create-invoice", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-API-Key": process.env.PD_API_KEY,
    "X-API-Secret": process.env.PD_API_SECRET,
  },
  body: JSON.stringify({
    amount: 100.00, brand_slug: "MyStore", order_reference: "ORDER-12345",
    customer_email: "customer@example.com", webhook_url: "https://yoursite.com/webhook",
  }),
});
const { payment_url } = await res.json();
// send the customer to payment_url; fulfil only on the signed webhook
$ch = curl_init("https://pd.cash/api/v1/create-invoice");
curl_setopt_array($ch, [
  CURLOPT_POST => true,
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    "Content-Type: application/json",
    "X-API-Key: " . getenv("PD_API_KEY"),
    "X-API-Secret: " . getenv("PD_API_SECRET"),
  ],
  CURLOPT_POSTFIELDS => json_encode([
    "amount" => 100.00, "brand_slug" => "MyStore", "order_reference" => "ORDER-12345",
    "customer_email" => "customer@example.com", "webhook_url" => "https://yoursite.com/webhook",
  ]),
]);
$data = json_decode(curl_exec($ch), true);
header("Location: " . $data["payment_url"]); // fulfil only on the signed webhook
import os, requests

r = requests.post(
    "https://pd.cash/api/v1/create-invoice",
    headers={"X-API-Key": os.environ["PD_API_KEY"], "X-API-Secret": os.environ["PD_API_SECRET"]},
    json={"amount": 100.00, "brand_slug": "MyStore", "order_reference": "ORDER-12345",
          "customer_email": "customer@example.com", "webhook_url": "https://yoursite.com/webhook"},
    timeout=15,
)
payment_url = r.json()["payment_url"]
# send the customer to payment_url; fulfil only on the signed webhook
Response200 OK
{
  "success": true,
  "payment_url": "https://pd.cash/pay/@MyStore/AB12CD34EF56GH78",
  "data": {
    "invoice": {
      "id": 123,
      "invoice_id": "AB12CD34EF56GH78",
      "order_reference": "ORDER-12345",
      "amount": 100.00,
      "status": "pending"
    },
    "urls": {
      "payment_page": "https://pd.cash/pay/@MyStore/AB12CD34EF56GH78"
    }
  }
}

Full API reference (sign in) — Sign in to your account to read it.

Where are you starting from?

Pick the line that sounds like you. The path and the next click change to match.

Start on the Free plan

  1. 01Create a free account. It comes with API and sandbox keys.
  2. 02Build against the sandbox and verify the signed payment.completed webhook.
  3. 03Once a route is approved, pilot the customer journey on hosted checkout before you build custom UI.

Or sign up with email · By continuing you agree to the Terms, Privacy Policy and Acceptable Use Policy.

Bring your own keys (BYOK)

  1. 01Tell us which provider you use and your expected volume.
  2. 02We confirm the connection is supported for your account.
  3. 03Connect your credentials. PD CASH adds routing and status visibility on top.

Request a partner-route review

  1. 01Share your business model, region, and expected volume.
  2. 02We review eligibility for the provider or channel-partner route you need.
  3. 03Requested methods stay subject to provider approval for your category, regions, and documents.

Use your category's application route

  1. 01Paid-plan routes have their own application for each category.
  2. 02Apply through the page for your business below.
  3. 03Requested methods stay subject to provider approval for your category, regions, and documents.
Approval decidesBusiness modelJurisdictionDocumentationUnderwritingProvider policyPartner availability

Everything your server gets back

One signed payment.completed delivery, field by field. Pick a field to see what it means and what your handler should do with it.

{
  : "payment.completed",
  : 48213,
  : "AB12CD34EF56GH78",
  : "ORDER-12345",
  : 25.0,
  : "USD",
  : "completed",
  : { "name": "", "email": "" },
  "metadata": { : false },
  : "2026-11-01T14:05:09.000Z"
}

eventstring

The only event PD CASH sends today. The same value arrives in the X-Webhook-Event header.

What to do: Fulfil on payment.completed, and only after the signature check passes.

transaction_idID

PD CASH’s ID for this payment. The X-Webhook-Id header stays the same for the same transaction, webhook and event.

What to do: Store it with the order, skip deliveries you have already processed, and quote it to support.

invoice_idstring

The invoice this payment belongs to. For API checkouts it is the invoice_id that create-invoice returned.

What to do: Match the payment to the invoice you created.

order_referencestring

Your own order ID, echoed back exactly as you sent it to create-invoice.

What to do: Look up the order in your system. This is the key most handlers fulfil on.

amountnumber

The gross amount the customer paid. PD CASH deducts its fees internally; this number is never net of fees.

What to do: Check it equals the order total before you fulfil.

currencystring

Always USD.

What to do: Compare amounts in US dollars.

statusstring

The payment’s status when the delivery was built.

What to do: Treat anything other than completed as not paid.

customerobject

Name and email when they are known. Either can be empty.

What to do: Use it for receipts if present. Never key an order on it.

metadata.is_sandboxboolean

true on deliveries from your sandbox keys. Sits inside metadata.

What to do: Never fulfil a real order from a sandbox delivery.

timestampstring

When PD CASH built the delivery, ISO 8601 with milliseconds.

What to do: Log it next to the order for reconciliation.

Trimmed sample: a few internal fields are left out. Nothing here is stored or sent.

From customer action to server decision

Keep fulfillment behind a provider-backed status instead of trusting the browser or a redirect alone.

Try to fool your own webhook

This is a signed delivery as it reaches your server. Change the body or the secret: your server recomputes the HMAC-SHA256 right here in the browser and decides.

POST /webhook
X-Webhook-Event: payment.completed
X-Webhook-Signature: sha256=952f6dde5e71…

Your server

  1. Signaturerecomputed sha256=952f6dde5e71…
  2. EventX-Webhook-Event is payment.completed
200 OKfulfil("ORDER-12345") runs.

Computed in your browser with Web Crypto. Sample data. Nothing here is stored or sent.

The same check in your code

Every delivery carries X-Webhook-Event and X-Webhook-Signature: sha256=<hex>, an HMAC-SHA256 of the raw body with your signing secret. Compare in constant time, then act on the event. The secret is on your account's API access page; sandbox has its own.

import { createHmac, timingSafeEqual } from 'node:crypto';

app.post('/webhook', express.raw({ type: '*/*' }), (req, res) => {
  const sig  = req.get('X-Webhook-Signature') || '';
  const want = 'sha256=' + createHmac('sha256', process.env.PD_WEBHOOK_SECRET)
                             .update(req.body).digest('hex');
  if (sig.length !== want.length || !timingSafeEqual(Buffer.from(sig), Buffer.from(want))) {
    return res.sendStatus(401);
  }
  const event = JSON.parse(req.body);
  if (req.get('X-Webhook-Event') === 'payment.completed') fulfil(event.order_reference);
  res.sendStatus(200);
});
$raw  = file_get_contents('php://input');
$sig  = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$want = 'sha256=' . hash_hmac('sha256', $raw, getenv('PD_WEBHOOK_SECRET'));
if (!hash_equals($want, $sig)) { http_response_code(401); exit; }

$event = json_decode($raw, true);
if (($_SERVER['HTTP_X_WEBHOOK_EVENT'] ?? '') === 'payment.completed') {
    fulfil($event['order_reference']);
}
http_response_code(200);
import hmac, hashlib, os
from flask import request, abort

@app.post("/webhook")
def webhook():
    want = "sha256=" + hmac.new(os.environ["PD_WEBHOOK_SECRET"].encode(),
                                request.get_data(), hashlib.sha256).hexdigest()
    if not hmac.compare_digest(want, request.headers.get("X-Webhook-Signature", "")):
        abort(401)
    event = request.get_json()
    if request.headers.get("X-Webhook-Event") == "payment.completed":
        fulfil(event["order_reference"])
    return "", 200

Illustrative handlers; fulfil() is yours. Field names match the API reference.

Frequently asked questions

No. PD CASH is an independent payment-orchestration layer, not Cash App or Block. Cash App Pay may be available through supported provider or approved channel-partner routes, subject to underwriting.

Timing varies by business model, jurisdiction, documentation, underwriting, and provider or channel-partner availability. PD CASH does not promise a fixed review or launch time.

No. PD CASH is an API connector and orchestration layer. Merchant settlement happens through the underlying payment provider or approved channel partner.

Yes. Businesses with existing supported provider accounts can connect their own credentials while using PD CASH for routing, observability, and payment management.

Yes. New accounts, including Free, get API keys at no cost under API Access in the dashboard, plus free sandbox keys. The API offers the payment methods enabled on your plan; paid-plan methods still need partner review.

Keep your internal order reference and the provider transaction reference when available, then match them against provider-backed status and your own order records.

No. Eligibility depends on business model, jurisdiction, documentation, underwriting, provider policy, and current provider or channel-partner availability.

Keep reading

All features

How to accept Cash App payments

Compare the real options for accepting Cash App online, from Square and Cash App for Business to hosted payment links and third-party payment orchestration.

Digital goods payment links & API

Sell software, downloads, keys, and memberships with tracked checkout links, verified payment status, and fulfillment triggers your systems can act on.

Map your approved API route

Share your business model, current provider, and integration goal. The review maps the eligible hosted-link and automation path.

No monthly plan fee · API keys at no cost · paid-plan methods are reviewed