Skip to content

Take payments and refunds

Open .md

Read first: Invoices and payments, for how money works on an order, deposits and payment terms, the ways a customer pays, and store credit.

This guide records payments you already received, works out what’s still owed, and refunds, splits or moves that money. It doesn’t charge cards. Customers pay by card in the Customer Portal, and your team charges cards in the web app. The API can refund a card payment through the gateway, but its card charge operations are built for YoPrint’s own payment screens: see Cards and the API. Invoicing an order is a separate guide: see Invoice an order.

  1. 1. Record a paymentCash, a check or a bank transfer you already received
  2. 2. Check the balanceDeposit due, balance due, and what’s been paid
  3. 3. List, change or deleteRead back the order’s payments, fix a reference, or remove one
  4. 4. RefundGive money back, recorded by hand or through the card gateway
  5. 5. Store creditPay an order from credit, or move payments onto it
  6. 6. Split with a payment linkRecord how one payment is allocated across invoices
Steps 1, 3, 4, 5 and 6 change money or its records. Step 2 only reads them.

Get the payment method you were paid with, such as Cash or Bank Transfer. payment_method_id is optional, but without it the payment has no method. Each entry has its name and id:

GET List payment methods /v1/api/store/{team_slug}/setting/payment_method
{ "data": [{ "id": "XbLngLA87AC5t5", "name": "Bank Transfer", "default": false, "trashed": false }] }

Then record the payment:

POST Record a payment on a sales order /v2/api/store/{team_slug}/v2/sales_order/{hash_id}/payment
Terminal window
curl https://secure.yoprint.com/v2/api/store/your-team/v2/sales_order/V4keXwwxMQyXw7/payment \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json" \
-H "X-Yoprint-Decimal-Format: exact-v1" \
-H "Content-Type: application/json" \
-d '{
"amount": 75000,
"date": "2026-11-03",
"payment_method_id": "Kst6z3ULXLBrmN",
"reference_id": "CHK-1001"
}'
  • amount is a whole number of thousandths, not a decimal pair: 75000 is 75.00. A number with decimals, such as 75000.5, is refused with 422 validation_failed, and nothing is recorded. error.fields.amount says “The amount must be a whole number of thousandths of the currency unit, such as 12500 for 12.50.” Its sign is ignored: -75000 also records 75.00. See Money and quantities.
  • date (or created_at) is required. reference_id is your reference, such as a check number. reference_description is a note on the payment.
  • The order must be published: a draft order refuses with 422 (“Payment Action Not Allowed - due to order internal state”).
  • No money moves, no receipt is emailed, and the payment is allocated to the order’s invoices automatically.
  • Fires payment_received.any_amount every time. It also fires payment_received.deposit_amount when the order’s paid total now exactly equals the deposit, and payment_received.full_amount when nothing is left to pay. A payment that goes past the deposit, or overpays, fires neither of those two.
GET Get a sales order or quote /v2/api/store/{team_slug}/v2/sales_order/{order_unique_key}
Terminal window
curl https://secure.yoprint.com/v2/api/store/your-team/v2/sales_order/V4keXwwxMQyXw7 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json" \
-H "X-Yoprint-Decimal-Format: exact-v1"
  • order_balance_due is what’s left to pay: invoiced total minus paid. A decimal pair.
  • deposit_amount_due is what’s left of the deposit: 0 or less means the deposit is paid. A decimal pair.
  • paid_amount is what’s been paid so far. Thousandths, not a decimal pair.
  • See How the balance works and Deposits and payment terms for how each is worked out, and Money and quantities for reading dp.

Example. An order’s lines are worth 600.00, and its terms ask for a 50% deposit, so the deposit is 300.00. Only the tees, 300.00 with no tax, are invoiced so far. After a 300.00 payment, paid_amount is 300000, deposit_amount_due is 0 (the deposit is paid), and order_balance_due is 0 too: the other 300.00 isn’t owed until it’s invoiced.

GET List the payments of a sales order /v2/api/store/{team_slug}/v2/sales_order/{hash_id}/payment

Returns every money record on the order at once, newest first, no pagination: payments, refunds and customer credit moves.

GET Get one payment of a sales order /v2/api/store/{team_slug}/v2/sales_order/{hash_id}/payment/{payment_reference} PUT Update a recorded payment /v2/api/store/{team_slug}/v2/sales_order/{hash_id}/payment/{payment_reference}
{ "date": "2026-11-04", "reference_id": "CHK-1002" }
DELETE Delete a payment or refund /v2/api/store/{team_slug}/v2/sales_order/{hash_id}/payment/{payment_reference}
  • Update changes a payment’s date, references and, on a recorded payment, its method. Delete removes a payment or refund record, and the answer has no data.
  • Card payments can’t be deleted here: refund them, or move their money to customer credit (see below).
What you can change, and what’s blocked
Field On update
date or created_at Required (one of them).
payment_method_id Only on a recorded payment (ORDER_PAYMENT). Send null to clear it. Ignored on other records.
reference_id, reference_description (a note) Yes. Send null to clear either.
amount No. Send the record’s own amount, or leave it out. A different amount is refused (payment_amount_not_editable): delete the payment and record it again instead.

A Customer Portal payment, credit linked to one, or a record synced from an integration such as Shopify can’t be changed or deleted here.

PUT Record a refund of a payment /v2/api/store/{team_slug}/v2/sales_order/{hash_id}/payment/{id}/refund
Terminal window
curl -X PUT https://secure.yoprint.com/v2/api/store/your-team/v2/sales_order/V4keXwwxMQyXw7/payment/hAwWd7vPrqjuHD/refund \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json" \
-H "X-Yoprint-Decimal-Format: exact-v1" \
-H "Content-Type: application/json" \
-d '{
"amount": 25000,
"date": "2026-11-05",
"reference_description": "Returned two shirts"
}'
  • Records that you gave back money outside YoPrint. No money moves, and the refund can’t be more than the payment’s amount minus its own refunds and the credit already spent from it.
  • amount is thousandths: 25000 is 25.00. A number with decimals is refused with 422. Its sign is ignored, and the answer shows the refund as a negative amount (-25000).
  • {id} in the path is the payment’s id. For a card payment, use the card refund below instead: this one only records a refund and returns no money.
  • The money comes first from the payment’s own unallocated amount, then from unspent customer credit issued from it (recorded as ORDER_CREDIT_RECOVERY on the order), then from its invoices, newest first.
  • Fires payment.refund_issued.
PUT Refund a card payment through the gateway /v2/api/store/{team_slug}/v2/sales_order/{hash_id}/payment_gateway_refund/{id}
Terminal window
curl -X PUT https://secure.yoprint.com/v2/api/store/your-team/v2/sales_order/V4keXwwxMQyXw7/payment_gateway_refund/JMQ642WFe4sANJ \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json" \
-H "X-Yoprint-Decimal-Format: exact-v1" \
-H "Content-Type: application/json" \
-d '{
"amount": 25000,
"locking_token": "refund-1001-a"
}'
  • Refunds real money back to the card, through the gateway that took the payment. Send both amount, in thousandths (25000 is 25.00), and a one-time locking_token of your own. Without amount the call fails with HTTP 500 before the gateway is called.
  • Fires payment.refund_issued. If the provider later reports the refund failed, YoPrint gives the money back to the payment (REFUND_REVERSAL) instead of leaving it lost.
POST Pay an order from the customer's credit /v2/api/store/{team_slug}/v2/sales_order/{hash_id}/credit/pay_with_customer_credit
{ "amount": 50000 }

Uses the customer’s credit to pay part of a published order. amount is thousandths (50000 is 50.00). It can’t be 0 or more than the credit available, and a number with decimals is refused with 422. Fires the same payment_received.* events, with the same exact-match rule, as recording a payment.

Despite the operations’ names, this isn’t a card refund: it takes money already paid on the order and keeps it as the customer’s store credit, to spend on another order. The order’s paid amount goes down by that much.

POST Move part of an order's payments to customer credit /v2/api/store/{team_slug}/v2/sales_order/{hash_id}/credit/refund_to_customer_credit PATCH Move all of an order's payments to customer credit /v2/api/store/{team_slug}/v2/sales_order/{hash_id}/credit/refund_all_to_customer_credit
{ "amount": 25000, "reference_description": "Overpayment" }
  • Both need the order published. The first moves part of what’s paid on this order into the customer’s credit, to use on another order. Its amount is thousandths (25000 is 25.00). The second moves everything at once, deleting the order’s payment links first, and takes no amount.
  • Only money not yet allocated to an invoice can move with the first call. Payments are allocated when they’re recorded, so delete the payment link first, or use the second call instead.
  • Neither sends a webhook. A frozen payment (an open dispute or review) blocks both the same way as a card refund, above.
POST Add or take out customer credit /v1/api/store/{team_slug}/customer/{hash_id}/credit
Terminal window
curl https://secure.yoprint.com/v1/api/store/your-team/customer/Rm4rRTDxipKY3n/credit \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json" \
-H "X-Yoprint-Decimal-Format: exact-v1" \
-H "Content-Type: application/json" \
-d '{
"action": "deposit",
"amount": 50000,
"payment_method_id": "6nz3Vu9sFR4dxM",
"reference_id": "CHQ-1001"
}'
  • action is deposit or withdraw. A withdrawal can’t be more than the credit available now (credit held by an open dispute isn’t available).
  • amount is thousandths: 50000 adds 50.00. A number with decimals is refused with 422.
  • It isn’t idempotent: each call adds a new entry. List the credit history before you retry after a timeout.
GET List a customer's credit history /v1/api/store/{team_slug}/customer/{hash_id}/credit

Of the credit operations here, only adding or taking out credit by hand fires a customer_credit webhook (customer_credit.deposited or customer_credit.withdrew). Paying from credit fires the same payment_received.* events as any payment.

Section titled “6. Split a payment across invoices with a payment link”

A payment link records how much of an already-received payment went to which invoice. The web app calls it a payment allocation. It’s not a page or a URL your customer opens, and it moves no money.

GET Get what a new payment link can allocate /v2/api/store/{team_slug}/v2/sales_order/{hash_id}/payment_link/get_create_template

Returns the order’s payments that still have money to allocate, each with transaction_id and unallocated_amount, to build the next call from.

POST Create a payment link for a sales order /v2/api/store/{team_slug}/v2/sales_order/{hash_id}/payment_link
Terminal window
curl https://secure.yoprint.com/v2/api/store/your-team/v2/sales_order/V4keXwwxMQyXw7/payment_link \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json" \
-H "X-Yoprint-Decimal-Format: exact-v1" \
-H "Content-Type: application/json" \
-d '{
"note": "Split deposit",
"unallocated_transactions": [
{
"action": "create",
"transaction_id": "hAwWd7vPrqjuHD",
"invoice_id": "QRbvVd2ZKcvSTB",
"total": { "dp": 3, "value": 50000 }
}
]
}'

Needs at least one entry, each naming a payment and an invoice of the same order.

GET Show one payment link with allocations /v2/api/store/{team_slug}/v2/payment_link/{hash_id}

Returns the link’s own total (dp 4, the sum) and each allocation’s total and unallocated_amount (dp 3).

PUT Update a payment link /v2/api/store/{team_slug}/v2/payment_link/{hash_id}
{
"note": "Deposit split across two invoices",
"allocated_transactions": [
{ "action": "update", "id": "SAo2jTR8BZUnyc", "total": { "dp": 3, "value": 12500 } }
],
"unallocated_transactions": [
{ "action": "create", "transaction_id": "tUq7cR8dTLKFPm", "invoice_id": "7ELS3Vmu6QfJxT", "total": { "dp": 3, "value": 5000 } }
]
}
How update applies the three actions
  • allocated_transactions changes existing allocations by id (update or delete). unallocated_transactions creates new ones. Allocations you leave out stay as they are.
  • Deletes run first, then updates, then creates, so one call can move money from one invoice to another.
  • An update row’s total.dp must be exactly 3, or it’s refused with 422. A create row’s dp isn’t checked. Either way, value is read as thousandths.
DELETE Delete a payment link /v2/api/store/{team_slug}/v2/payment_link/{hash_id}

Deletes the link and its allocations. The payments stay on the order, unallocated, and the invoices simply show less paid: no money moves.

You want to Through the API
Record a card payment you took outside YoPrint, such as on your own terminal Yes. Record it as in step 1, with a payment method such as Credit Card. No money moves.
Refund a card payment that went through the team’s gateway Yes, with a card refund through the gateway. Real money goes back to the card.
Charge a card Not from your own server. See below.
Delete a card payment No. Refund it, or move its money to customer credit.

The reference lists three card operations: Prepare a card payment, Charge a card through the payment gateway, and Start a Square Terminal checkout. They’re marked Internal because they’re built for YoPrint’s own payment screens:

  • Prepare and Charge need a card token or a confirmed payment from the gateway’s own browser library (Stripe, Square, PayPal or Authorize.net), which only a card form in a web page produces.
  • Start a Square Terminal checkout sends the charge to the shop’s Square Terminal, where the customer pays on the device.

Don’t build on them. They still work with any member’s key, and they charge real money, so don’t give a key to anyone you wouldn’t trust with that. See Roles and permissions.

POST Charge a card through the payment gateway /v2/api/store/{team_slug}/v2/sales_order/{hash_id}/payment/{payment_reference}

A card payment a customer makes in the Customer Portal, or that your team takes in the web app, shows up in the order’s payments like any other. Read it with List the payments of a sales order, and refund it through the gateway.

  • Recording a payment has no operation_key. Unlike a shipment create, there’s nothing to make a retry safe: a retried create after a timeout can record the payment twice. List the order’s payments first.
  • A payment link entry can be silently skipped or capped. One asking for more than the payment has left, or targeting an invoice with nothing left to pay, is skipped without an error. One asking for more than an invoice still owes, with enough left on the payment, is capped to what the invoice owes. The link can be created even though nothing inside it was saved: read the response.
  • “Note” is a different field depending on where you are. A payment’s, refund’s or credit move’s note is reference_description. A payment link’s note is note.
  • Update works on a draft order, but the operations around it don’t. Recording a payment, deleting one, and both kinds of refund need the order published. A card refund checks that only after the payment provider has refunded the card.
  • A recorded refund’s {id} must be a payment. A refund or a credit move in its place fails with HTTP 500, not a clean error.
  • A recorded refund returns no money. On a card payment, use Refund a card payment through the gateway, which does.