Gifts
Purchase Gift Subscription
Purchase a gift subscription that can be redeemed by a recipient via email.
POST
/
v1
/
gifts
/
purchase
Purchase a gift subscription
curl --request POST \
--url https://billing.example.com/v1/gifts/purchase \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"buyer_customer_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"plan_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"duration_months": 2,
"recipient_email": "jsmith@example.com"
}
'import requests
url = "https://billing.example.com/v1/gifts/purchase"
payload = {
"buyer_customer_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"plan_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"duration_months": 2,
"recipient_email": "jsmith@example.com"
}
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({
buyer_customer_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
plan_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
duration_months: 2,
recipient_email: 'jsmith@example.com'
})
};
fetch('https://billing.example.com/v1/gifts/purchase', 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://billing.example.com/v1/gifts/purchase",
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_customer_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'plan_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'duration_months' => 2,
'recipient_email' => 'jsmith@example.com'
]),
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://billing.example.com/v1/gifts/purchase"
payload := strings.NewReader("{\n \"buyer_customer_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"plan_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"duration_months\": 2,\n \"recipient_email\": \"jsmith@example.com\"\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://billing.example.com/v1/gifts/purchase")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"buyer_customer_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"plan_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"duration_months\": 2,\n \"recipient_email\": \"jsmith@example.com\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://billing.example.com/v1/gifts/purchase")
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 \"buyer_customer_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"plan_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"duration_months\": 2,\n \"recipient_email\": \"jsmith@example.com\"\n}"
response = http.request(request)
puts response.read_body{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"tenant_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"code": "<string>",
"plan_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"buyer_customer_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"recipient_email": "<string>",
"status": "purchased",
"redeemed_by_customer_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"redeemed_at": "2023-11-07T05:31:56Z",
"duration_months": 123,
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z"
}{
"error": {
"code": "BAD_REQUEST",
"message": "<string>"
}
}{
"error": {
"code": "BAD_REQUEST",
"message": "<string>"
}
}Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
buyer_customer_id | string (UUID) | Yes | The unique identifier of the customer purchasing the gift. |
plan_id | string (UUID) | Yes | The subscription plan to gift. Must be an active, non-archived plan. |
recipient_email | string | Yes | The email address of the gift recipient. A redemption email will be sent to this address. |
duration_months | integer | Yes | The duration of the gift subscription in months. Minimum 1, maximum 24. |
message | string | No | An optional personal message from the buyer to include in the gift email. Max 500 characters. |
deliver_at | string | No | ISO 8601 timestamp for scheduled delivery. If omitted, the gift email is sent immediately. |
Example Request
curl -X POST https://api.recurso.dev/v1/gifts/purchase \
-H "Authorization: Bearer rsk_live_7f3a9b2c1d4e8f0a" \
-H "Content-Type: application/json" \
-d '{
"buyer_customer_id": "d4e5f6a7-b8c9-4d0e-a1f2-b3c4d5e6f7a8",
"plan_id": "b1c2d3e4-f5a6-4b7c-8d9e-0f1a2b3c4d5e",
"recipient_email": "alex.johnson@example.com",
"duration_months": 6,
"message": "Happy birthday! Enjoy six months on us."
}'
Response
{
"id": "gift_Vm4wR8pNtK",
"buyer_customer_id": "d4e5f6a7-b8c9-4d0e-a1f2-b3c4d5e6f7a8",
"plan_id": "b1c2d3e4-f5a6-4b7c-8d9e-0f1a2b3c4d5e",
"plan_name": "Pro Monthly",
"recipient_email": "alex.johnson@example.com",
"duration_months": 6,
"code": "GIFT-VM4WR8PNTK",
"status": "purchased",
"amount": 29400,
"currency": "USD",
"message": "Happy birthday! Enjoy six months on us.",
"deliver_at": null,
"redeemed_at": null,
"expires_at": "2027-06-23T17:30:00Z",
"created_at": "2026-06-23T17:30:00Z"
}
Response Fields
| Field | Type | Description |
|---|---|---|
code | string | The unique gift redemption code. The recipient uses this to activate their subscription. |
status | string | The gift status. One of: purchased, delivered, redeemed, expired, refunded. |
amount | integer | The total cost charged to the buyer, in smallest currency unit (cents). Calculated as plan price multiplied by duration_months. |
expires_at | string | The gift code expiration date. Defaults to one year from purchase. |
Notes
- The buyer is charged immediately for the full duration of the gift subscription.
- The recipient receives an email with the redemption code and instructions. If
deliver_atis set, the email is scheduled accordingly. - Gift codes expire one year after purchase if not redeemed.
- The recipient does not need an existing account. Redeeming a gift code creates an account if one does not exist.
Refunds for gift subscriptions are only available before the gift is redeemed. Once redeemed, standard cancellation policies apply.
Authorizations
Tenant API key obtained from POST /auth/register or POST /v1/developer/keys.
Body
application/json
Response
Gift purchased.
Redemption code.
Available options:
purchased, redeemed ⌘I
Purchase a gift subscription
curl --request POST \
--url https://billing.example.com/v1/gifts/purchase \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"buyer_customer_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"plan_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"duration_months": 2,
"recipient_email": "jsmith@example.com"
}
'import requests
url = "https://billing.example.com/v1/gifts/purchase"
payload = {
"buyer_customer_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"plan_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"duration_months": 2,
"recipient_email": "jsmith@example.com"
}
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({
buyer_customer_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
plan_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
duration_months: 2,
recipient_email: 'jsmith@example.com'
})
};
fetch('https://billing.example.com/v1/gifts/purchase', 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://billing.example.com/v1/gifts/purchase",
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_customer_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'plan_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'duration_months' => 2,
'recipient_email' => 'jsmith@example.com'
]),
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://billing.example.com/v1/gifts/purchase"
payload := strings.NewReader("{\n \"buyer_customer_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"plan_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"duration_months\": 2,\n \"recipient_email\": \"jsmith@example.com\"\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://billing.example.com/v1/gifts/purchase")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"buyer_customer_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"plan_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"duration_months\": 2,\n \"recipient_email\": \"jsmith@example.com\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://billing.example.com/v1/gifts/purchase")
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 \"buyer_customer_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"plan_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"duration_months\": 2,\n \"recipient_email\": \"jsmith@example.com\"\n}"
response = http.request(request)
puts response.read_body{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"tenant_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"code": "<string>",
"plan_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"buyer_customer_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"recipient_email": "<string>",
"status": "purchased",
"redeemed_by_customer_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"redeemed_at": "2023-11-07T05:31:56Z",
"duration_months": 123,
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z"
}{
"error": {
"code": "BAD_REQUEST",
"message": "<string>"
}
}{
"error": {
"code": "BAD_REQUEST",
"message": "<string>"
}
}