Charge a Payment Method
Charge a stored card for a new order, with the shopper absent
POST
/
api
/
v2
/
payment-methods
/
{payment_method_id}
/
charges
Charge a Payment Method
curl --request POST \
--url https://api.example.com/api/v2/payment-methods/{payment_method_id}/chargesimport requests
url = "https://api.example.com/api/v2/payment-methods/{payment_method_id}/charges"
response = requests.post(url)
print(response.text)const options = {method: 'POST'};
fetch('https://api.example.com/api/v2/payment-methods/{payment_method_id}/charges', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/api/v2/payment-methods/{payment_method_id}/charges",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/api/v2/payment-methods/{payment_method_id}/charges"
req, _ := http.NewRequest("POST", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/api/v2/payment-methods/{payment_method_id}/charges")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/v2/payment-methods/{payment_method_id}/charges")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
response = http.request(request)
puts response.read_bodyCharge a Payment Method
Creates an order from the line items you send and charges the stored card for it. The shopper is not involved. Eligibility is checked for these items at the time of the charge, the same way as for a checkout.Endpoint
POST /api/v2/payment-methods/{payment_method_id}/charges
Authentication
Authorization: Bearer glm_test_YOUR_API_KEY
Idempotency-Key: refill-2026-12-order-0042
Idempotency-Key is required and must be 22 to 255 characters. Use one key per order. Sending the same key again returns the first result and never charges twice.
Request Body
{
"reference_id": "refill-2026-12-0042",
"line_items": [
{
"product_id": "RX-100",
"name": "Monthly prescription",
"price": 4500,
"quantity": 1,
"currency": "USD"
}
],
"shipping": 500,
"tax": 0,
"discount": 0,
"metadata": {
"cycle": "2026-12"
}
}
All monetary amounts are integers in cents (e.g., 4995 = $49.95).
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
reference_id | string | Yes | Your ID for this order, up to 50 characters |
line_items | array | Yes | Products being charged. Same fields as Create Checkout Session |
shipping | integer | No | Shipping amount in cents |
tax | integer | No | Tax amount in cents |
discount | integer | No | Discount amount in cents |
metadata | object | No | Custom key-value pairs, returned on the order |
customer | object | No | Defaults to the customer on the checkout that stored the card |
shipping_info | object | No | Defaults to the address on the checkout that stored the card |
billing_info | object | No | Defaults to the address on the checkout that stored the card |
success_url | string | No | Where the shopper returns after paying a declined order through checkout_url |
failure_url | string | No | Where the shopper returns if that payment fails or is cancelled |
test_acquirer_response_code | string | No | Test keys only. Simulates a declined charge, for example "12" |
Response
201 Created. The order, with the payment method that was charged.
{
"success": true,
"message": "Payment method charged",
"data": {
"id": "ord_01ABC...",
"status": "completed",
"payment_status": "captured",
"amount": 5000,
"currency": "usd",
"reference_id": "refill-2026-12-0042",
"customer": {
"email": "jane@example.com",
"name": "Jane Doe"
},
"line_items": [
{
"product_id": "RX-100",
"name": "Monthly prescription",
"quantity": 1,
"unit_amount": 4500,
"amount": 4500,
"currency": "usd",
"is_recurring": false
}
],
"payment_method": {
"id": "pm_fc61f9c445dd477287c47052087dc91c",
"type": "card",
"brand": "visa",
"last4": "1111",
"usage": "off_session",
"status": "active"
},
"created_at": "2026-12-10T09:15:02Z"
}
}
order.completed webhook for this order.
Declined charges
A decline returns422 with PAYMENT_METHOD_010. No money is taken. The order stays open and checkout_url is its hosted checkout page, where the shopper can pay with another card. Gale also sends payment.failed. Gale does not retry a declined charge.
{
"success": false,
"error": {
"code": "PAYMENT_METHOD_010",
"message": "The card was declined. No money was taken.",
"details": {
"decline_code": "6",
"decline_reason": "shopper_correctable",
"retryable": false,
"order_id": "ord_01ABD...",
"checkout_url": "<hosted checkout link for this order>"
}
}
}
Errors
| Status Code | Error Code | Description | What to do |
|---|---|---|---|
| 404 | PAYMENT_METHOD_001 | Unknown ID, a payment method stored in the other mode, or saved payment methods not enabled for the account | Check the ID and the key |
| 422 | PAYMENT_METHOD_002 | Saved payment methods are not enabled for this account in this mode | Contact Gale |
| 422 | PAYMENT_METHOD_003 | The payment method was removed or disabled | Send the shopper a new checkout to store a card |
| 422 | PAYMENT_METHOD_004 | The shopper did not agree to charges you start | Send the shopper a new checkout with setup_future_usage |
| 422 | PAYMENT_METHOD_006 | The order mixes HSA/FSA eligible and non-eligible items | Send one charge per group |
| 422 | PAYMENT_METHOD_007 | An item needs a Letter of Medical Necessity | Send the shopper a checkout |
| 422 | PAYMENT_METHOD_008 | Idempotency-Key header missing or not 22 to 255 characters | Send a valid key |
| 422 | PAYMENT_METHOD_009 | test_acquirer_response_code sent with a live key | Remove the field |
| 422 | PAYMENT_METHOD_010 | The card was declined. No money was taken | Send the shopper checkout_url |
| 503 | PAYMENT_METHOD_011 | The charge was not completed and no money was taken | Retry with the same key, or a new key when error.details.retry_with_new_key is true |
| 503 | PAYMENT_METHOD_012 | The charge is not confirmed | Retry with the same key only. A new key could charge the shopper twice |
| 409 | PAYMENT_METHOD_013 | The key was already used to charge a different payment method | Use a new key |
| 409 | PAYMENT_METHOD_015 | A charge with this key is being processed | Retry shortly with the same key |
Related
⌘I
Charge a Payment Method
curl --request POST \
--url https://api.example.com/api/v2/payment-methods/{payment_method_id}/chargesimport requests
url = "https://api.example.com/api/v2/payment-methods/{payment_method_id}/charges"
response = requests.post(url)
print(response.text)const options = {method: 'POST'};
fetch('https://api.example.com/api/v2/payment-methods/{payment_method_id}/charges', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/api/v2/payment-methods/{payment_method_id}/charges",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/api/v2/payment-methods/{payment_method_id}/charges"
req, _ := http.NewRequest("POST", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/api/v2/payment-methods/{payment_method_id}/charges")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/v2/payment-methods/{payment_method_id}/charges")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
response = http.request(request)
puts response.read_body