curl --request POST \
--url https://api.cope.com/v1/commerce/products/{product_id}/attachments \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"access_pending": false,
"access_trial": true,
"filename": "Quiet Launch Playbook.pdf",
"upload_token": "<upload_token from POST /v1/commerce/uploads>"
}
'import requests
url = "https://api.cope.com/v1/commerce/products/{product_id}/attachments"
payload = {
"access_pending": False,
"access_trial": True,
"filename": "Quiet Launch Playbook.pdf",
"upload_token": "<upload_token from POST /v1/commerce/uploads>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
access_pending: false,
access_trial: true,
filename: 'Quiet Launch Playbook.pdf',
upload_token: '<upload_token from POST /v1/commerce/uploads>'
})
};
fetch('https://api.cope.com/v1/commerce/products/{product_id}/attachments', 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/products/{product_id}/attachments",
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([
'access_pending' => false,
'access_trial' => true,
'filename' => 'Quiet Launch Playbook.pdf',
'upload_token' => '<upload_token from POST /v1/commerce/uploads>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$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/products/{product_id}/attachments"
payload := strings.NewReader("{\n \"access_pending\": false,\n \"access_trial\": true,\n \"filename\": \"Quiet Launch Playbook.pdf\",\n \"upload_token\": \"<upload_token from POST /v1/commerce/uploads>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
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/products/{product_id}/attachments")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"access_pending\": false,\n \"access_trial\": true,\n \"filename\": \"Quiet Launch Playbook.pdf\",\n \"upload_token\": \"<upload_token from POST /v1/commerce/uploads>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.cope.com/v1/commerce/products/{product_id}/attachments")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"access_pending\": false,\n \"access_trial\": true,\n \"filename\": \"Quiet Launch Playbook.pdf\",\n \"upload_token\": \"<upload_token from POST /v1/commerce/uploads>\"\n}"
response = http.request(request)
puts response.read_bodyAttach a downloadable file
Step three of three. A product holds at most 5 downloadable files. The content type is checked again here against the file allow-list. Attaching a file takes the product off sale and back to review (status inactive, approval_status review) until COPE approves it and it is published again. The one exception is an approved product of a business COPE trusts to skip re-review, which keeps its status and approval. An upload whose bytes have not arrived yet is refused with 409 upload_not_completed; attach again once it has.
Requires the products 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/products/{product_id}/attachments \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"access_pending": false,
"access_trial": true,
"filename": "Quiet Launch Playbook.pdf",
"upload_token": "<upload_token from POST /v1/commerce/uploads>"
}
'import requests
url = "https://api.cope.com/v1/commerce/products/{product_id}/attachments"
payload = {
"access_pending": False,
"access_trial": True,
"filename": "Quiet Launch Playbook.pdf",
"upload_token": "<upload_token from POST /v1/commerce/uploads>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
access_pending: false,
access_trial: true,
filename: 'Quiet Launch Playbook.pdf',
upload_token: '<upload_token from POST /v1/commerce/uploads>'
})
};
fetch('https://api.cope.com/v1/commerce/products/{product_id}/attachments', 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/products/{product_id}/attachments",
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([
'access_pending' => false,
'access_trial' => true,
'filename' => 'Quiet Launch Playbook.pdf',
'upload_token' => '<upload_token from POST /v1/commerce/uploads>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$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/products/{product_id}/attachments"
payload := strings.NewReader("{\n \"access_pending\": false,\n \"access_trial\": true,\n \"filename\": \"Quiet Launch Playbook.pdf\",\n \"upload_token\": \"<upload_token from POST /v1/commerce/uploads>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
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/products/{product_id}/attachments")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"access_pending\": false,\n \"access_trial\": true,\n \"filename\": \"Quiet Launch Playbook.pdf\",\n \"upload_token\": \"<upload_token from POST /v1/commerce/uploads>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.cope.com/v1/commerce/products/{product_id}/attachments")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"access_pending\": false,\n \"access_trial\": true,\n \"filename\": \"Quiet Launch Playbook.pdf\",\n \"upload_token\": \"<upload_token from POST /v1/commerce/uploads>\"\n}"
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
Optional. At most 255 characters of valid UTF-8 with no NUL byte. When sent, a retry that carries the same key and the same body returns the original response instead of performing the write a second time, and the same key with a different body is refused with 409 idempotency_conflict. Keys are remembered for 24 hours. A returned original response carries the header Idempotent-Replayed: true. Without the header the write is performed every time it is sent.
255Path Parameters
product_id public identifier.
^prod_[A-Za-z0-9]{8,32}$"prod_A1b2C3d4"
Body
Token returned by the upload session, after the bytes have been uploaded.
Grants buyers access to this file while their payment is still pending.
Grants buyers access to this file during a trial period.
Overrides the file name stored with the upload.
Response
Successful response
Show child attributes
Show child attributes
Was this page helpful?