Create Payment Link
curl --request POST \
--url https://www.gomry.com/api/v1/checkout_sessions/{checkout_session_id}/payment_link \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: <api-key>' \
--data '{
"buyer": {}
}'import requests
url = "https://www.gomry.com/api/v1/checkout_sessions/{checkout_session_id}/payment_link"
payload = { "buyer": {} }
headers = {
"X-API-KEY": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-KEY': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({buyer: {}})
};
fetch('https://www.gomry.com/api/v1/checkout_sessions/{checkout_session_id}/payment_link', 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://www.gomry.com/api/v1/checkout_sessions/{checkout_session_id}/payment_link",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'buyer' => [
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-KEY: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://www.gomry.com/api/v1/checkout_sessions/{checkout_session_id}/payment_link"
payload := strings.NewReader("{\n \"buyer\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-KEY", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://www.gomry.com/api/v1/checkout_sessions/{checkout_session_id}/payment_link")
.header("X-API-KEY", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"buyer\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://www.gomry.com/api/v1/checkout_sessions/{checkout_session_id}/payment_link")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-KEY"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"buyer\": {}\n}"
response = http.request(request)
puts response.read_body{
"payment_link": {
"status": "<string>",
"url": "<string>",
"amount": 123,
"currency": "<string>",
"expires_at": "<string>",
"refund_reason": "<string>"
}
}Checkout Sessions
Create Payment Link
A hosted page the buyer pays on, for agents that cannot mint a payment token
POST
/
checkout_sessions
/
{checkout_session_id}
/
payment_link
Create Payment Link
curl --request POST \
--url https://www.gomry.com/api/v1/checkout_sessions/{checkout_session_id}/payment_link \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: <api-key>' \
--data '{
"buyer": {}
}'import requests
url = "https://www.gomry.com/api/v1/checkout_sessions/{checkout_session_id}/payment_link"
payload = { "buyer": {} }
headers = {
"X-API-KEY": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-KEY': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({buyer: {}})
};
fetch('https://www.gomry.com/api/v1/checkout_sessions/{checkout_session_id}/payment_link', 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://www.gomry.com/api/v1/checkout_sessions/{checkout_session_id}/payment_link",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'buyer' => [
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-KEY: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://www.gomry.com/api/v1/checkout_sessions/{checkout_session_id}/payment_link"
payload := strings.NewReader("{\n \"buyer\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-KEY", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://www.gomry.com/api/v1/checkout_sessions/{checkout_session_id}/payment_link")
.header("X-API-KEY", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"buyer\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://www.gomry.com/api/v1/checkout_sessions/{checkout_session_id}/payment_link")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-KEY"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"buyer\": {}\n}"
response = http.request(request)
puts response.read_body{
"payment_link": {
"status": "<string>",
"url": "<string>",
"amount": 123,
"currency": "<string>",
"expires_at": "<string>",
"refund_reason": "<string>"
}
}Create Payment Link
Usually you don’t need this call. Every payable session already carries
continue_url, the standard checkout handoff: send that to the buyer and it opens this same payment page with no credential. Use this endpoint when you want the payment page’s own URL and expiry.Requires
checkout: write, with the same credentials as every other checkout endpoint: an organization API key, a self-registered agent token, a Personal Agent Protocol session, or a signed-in person’s OAuth token granted checkout:write, or none at all for a session created without one. Only the credential that created the session can make its link.ready_for_payment with a total above zero. A free order needs no payment: call complete with no payment_data.
Path Parameters
string
required
The session to pay.
Body
The body is optional.object
Fills or replaces the session’s buyer. The payment page is prefilled with this email, and the receipt and tickets are sent to it. Required here if the session has no buyer yet (a signed-in person’s token defaults to their verified email).
Response
200 with the session, carrying payment_link:
object
Show Payment link
Show Payment link
string
open (payable now), paid (tickets issued), refunded (paid, but the order could no longer be honoured), or expired.string
The page to send the buyer. Present only while
status is open.integer
Minor units: exactly the session total, fees included.
string
The session currency.
string
When the link stops accepting payment. Links are open for one hour.
string
Why a payment was refunded. Present only when
status is refunded."payment_link": {
"status": "open",
"url": "https://checkout.stripe.com/c/pay/cs_live_...",
"amount": 1465,
"currency": "usd",
"expires_at": "2026-10-14T18:00:00.000Z"
}
After the buyer pays
Poll Get Checkout Session (every few seconds while the buyer is paying is fine):| What you read | What happened |
|---|---|
status: "completed" and an order | Paid and issued. Show the buyer order.permalink_url; the tickets are emailed too. |
payment_link.status: "refunded" | The buyer paid, but the cart could not be sold (sold out, or the price moved while they paid). The payment was refunded in full and nothing was issued. refund_reason says why. |
payment_link.status: "expired" | Nobody paid in time. Ask for a new link. |
Calling it again
Asking again while the link is open and the total is unchanged returns the same link. If the cart changed, you get a new link and the old one stops accepting payment. Updating the session to a different total also closes an open link, so a buyer can never pay a stale amount. Canceling the session closes its link. A payment that lands at the same instant is refunded.Failures
| Code | Status | What to do |
|---|---|---|
invalid_body | 400 | No buyer email ($.buyer.email). Send buyer. |
invalid_session_state | 409 | Already paid, canceled, expired, free, or not ready (a required answer or address is missing). Read the session. |
amount_mismatch | 409 | The total changed since your last read. Re-read the session, confirm it with your buyer, then ask again. |
sold_out | 409 | Inventory went while the session was open. |

