curl --request POST \
--url https://api.cope.com/v1/commerce/subscriptions/{id}/payment-recovery-links \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '{}'import requests
url = "https://api.cope.com/v1/commerce/subscriptions/{id}/payment-recovery-links"
payload = {}
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({})
};
fetch('https://api.cope.com/v1/commerce/subscriptions/{id}/payment-recovery-links', 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.cope.com/v1/commerce/subscriptions/{id}/payment-recovery-links",
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([
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"Idempotency-Key: <idempotency-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://api.cope.com/v1/commerce/subscriptions/{id}/payment-recovery-links"
payload := strings.NewReader("{}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
req.Header.Add("Authorization", "Bearer <token>")
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://api.cope.com/v1/commerce/subscriptions/{id}/payment-recovery-links")
.header("Idempotency-Key", "<idempotency-key>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.cope.com/v1/commerce/subscriptions/{id}/payment-recovery-links")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{}"
response = http.request(request)
puts response.read_bodyCreate a payment recovery link
Creates a link the buyer opens, without logging in, to replace the payment method of an overdue subscription and pay what is overdue. Send it to the buyer yourself, by any channel. It is the same page COPE’s payment-failed email and payment reminders link to.
url carries a secret and is shown once. COPE stores only a digest of it, so it cannot
show the link again. Treat it like a password: send it to the buyer, and do not log or store
it. It stops working after expires_at (7 days), and as soon as the subscription is no longer
overdue — paid, cancelled or ended. Creating a link does not invalidate earlier ones,
including the ones COPE emailed.
Idempotency-Key is required. A repeat with the same key answers 201 with
Idempotent-Replayed: true and a new url for the same link: the secret from the earlier
answer stops working, so a response lost in transit never leaves a working link behind. The
expiry does not move. Only the latest answer under a key works, so do not send concurrent
requests with the same key: both answer 201, and the first url is already dead. A key
binds to one subscription; the same key sent for another subscription creates a separate link
there. A repeat after the link expired is refused with idempotency_key_spent (409); use a
new key.
A subscription with nothing to recover is refused with payment_recovery_not_available
(422), and errors[0].code says why — not_overdue, for example. Treat that set of reasons
as open. At most 10 links are created for one subscription in 24 hours, counting the ones COPE
emails; the next is refused with too_many_payment_recovery_links (429).
Requires the subscriptions permission at write. An API key holds a permission at the lower of its own level (read for a read-only key) and its holder’s role; a key without it is refused with 403.
curl --request POST \
--url https://api.cope.com/v1/commerce/subscriptions/{id}/payment-recovery-links \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '{}'import requests
url = "https://api.cope.com/v1/commerce/subscriptions/{id}/payment-recovery-links"
payload = {}
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({})
};
fetch('https://api.cope.com/v1/commerce/subscriptions/{id}/payment-recovery-links', 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.cope.com/v1/commerce/subscriptions/{id}/payment-recovery-links",
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([
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"Idempotency-Key: <idempotency-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://api.cope.com/v1/commerce/subscriptions/{id}/payment-recovery-links"
payload := strings.NewReader("{}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
req.Header.Add("Authorization", "Bearer <token>")
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://api.cope.com/v1/commerce/subscriptions/{id}/payment-recovery-links")
.header("Idempotency-Key", "<idempotency-key>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.cope.com/v1/commerce/subscriptions/{id}/payment-recovery-links")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{}"
response = http.request(request)
puts response.read_bodyAuthorizations
Bearer credential for the public API: a live COPE API key (ck_live_*; keys issued earlier as cope_sk_live_* keep working). Dashboard sign-in tokens are not accepted.
Headers
Required. At most 255 characters of valid UTF-8 with no NUL byte. The link is bound to this key. A repeat under the same key answers 201 with Idempotent-Replayed: true and a new url for the same link: the secret in any earlier answer stops working, so a response lost in transit leaves no working link behind, and expires_at does not move. Only the latest answer under a key works, so do not send concurrent requests with the same key. A key binds to one subscription. A repeat after the link expired is refused with 409 idempotency_key_spent; send a new key.
255Path Parameters
id public identifier.
^ps_[A-Za-z0-9]{8,32}$"ps_A1b2C3d4E5f6"
Body
The body is of type object.
Response
Successful response
Show child attributes
Show child attributes
Was this page helpful?