Cheese Store
v2.0.0Welcome to the Cheese Store API reference. This is a live example of how you can use Sourcey to generate beautiful static documentation for your APIs.
The Cheese Store API is organized around REST. It uses resource-oriented URLs, standard HTTP methods, and returns JSON responses. All requests are authenticated using an API key or OAuth2 token.
Getting Started
- Sign up for a developer account at cheesy.sourcey.com
- Generate an API key from your dashboard
- Include the key in your requests as
X-API-Keyheader
Rate Limiting
| Plan | Requests/hour | Burst |
|---|---|---|
| Free | 100 | 10 |
| Pro | 10,000 | 100 |
| Enterprise | Unlimited | 1,000 |
When you exceed the rate limit, the API returns 429 Too Many Requests with a Retry-After header.
Pagination
List endpoints return paginated results. Use cursor and limit query parameters:
{
"items": [...],
"nextCursor": "eyJpZCI6NDJ9",
"hasMore": true
}Hard cheese gouda say cheese. Ricotta cauliflower cheese cheesecake bocconcini edam bocconcini fromage feta. Who moved my cheese bocconcini cheese and wine cottage cheese cheese on toast who moved my cheese caerphilly stinking bishop. Bocconcini cheesy feet the big cheese macaroni cheese cheesy feet mascarpone.
Contact: [email protected]
https://cheesy.sourcey.com/v2Productionhttps://sandbox.cheesy.sourcey.com/v2Sandbox (test data, rate limits relaxed)http://localhost:3000/v2Local developmentAuthentication
api_keyapiKeyAPI key authentication. Include your API key in the X-API-Key header.
Get your key from the developer dashboard.
API Key: X-API-Key in header
cheesy_oauthoauth2OAuth2 authentication for full API access
Authorization: https://cheesy.sourcey.com/oauth/authorize
Scopes: read:cheeses — Read cheese data, write:cheeses — Create and update cheeses, read:orders — View order history, write:orders — Place and manage orders
Authorization: https://cheesy.sourcey.com/oauth/authorize
Token: https://cheesy.sourcey.com/oauth/token
Scopes: read:cheeses — Read cheese data, write:cheeses — Create and update cheeses, read:orders — View order history, write:orders — Place and manage orders
bearer_authhttpJWT token obtained from the /customer/login endpoint
Scheme: bearer (JWT)
Cheese
Cheese endpoints provide access to information and operations relating to the cheeses available in the store.
Cheeses can be filtered by status, tags, and category. Each cheese has a unique ID, name, category, and availability status.
List all cheeses
Returns a paginated list of cheeses in the store. Results can be filtered by status and sorted by name or creation date.
The response includes cursor-based pagination. Use the nextCursor value from the response as the cursor parameter in subsequent requests.
Parameters
cursorstringqueryPagination cursor from a previous response
limitinteger[1, 100]20queryMaximum number of cheeses to return
statusstringavailablependingsoldqueryFilter by availability status
sortstringname-namecreatedAt-createdAtnamequerySort order for results
Response
A paginated list of cheeses
Rate limit exceeded
Authorization
api_keyapiKey in headerAPI key authentication. Include your API key in the X-API-Key header.
Get your key from the developer dashboard.
cheesy_oauthoauth2OAuth2 authentication for full API access
Scopes: read:cheeses
curl -X GET 'https://cheesy.sourcey.com/v2/cheeses'const response = await fetch('https://cheesy.sourcey.com/v2/cheeses', {
method: 'GET',
});
const data = await response.json();const response = await fetch('https://cheesy.sourcey.com/v2/cheeses', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://cheesy.sourcey.com/v2/cheeses')
data = response.json()package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://cheesy.sourcey.com/v2/cheeses", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}require 'net/http'
require 'json'
uri = URI('https://cheesy.sourcey.com/v2/cheeses')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://cheesy.sourcey.com/v2/cheeses")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"items": [
{
"id": 42,
"name": "Gorgonzola",
"category": {
"id": 1,
"name": "Italian Cheese"
},
"photoUrls": [
"https://wannabechef.com/gorgonzola.jpg"
],
"tags": [
{
"id": 1,
"name": "blue"
}
],
"status": "available",
"origin": "Italy",
"pricePerKg": 28.5,
"ageMonths": 12,
"organic": false,
"createdAt": "2024-01-15T09:30:00Z",
"updatedAt": "2024-01-15T09:30:00Z"
}
],
"nextCursor": "string",
"hasMore": true,
"total": 0
}{
"code": 404,
"type": "Not found",
"message": "Your cheese has already been eaten"
}Add a new cheese
Add a new cheese to the store inventory. The cheese name must be unique within its category.
Body
Cheese object to add to the store
namestringrequiredcategoryobjectphotoUrlsArray<string>tagsArray<object>statusstringavailablependingsoldavailableoriginstring | nullpricePerKgnumber<float>ageMonthsinteger[0, 120]organicbooleanfalseResponse
Cheese created successfully
A cheese with this name already exists in the category
The request body failed validation
Authorization
cheesy_oauthoauth2OAuth2 authentication for full API access
Scopes: write:cheeses
curl -X POST 'https://cheesy.sourcey.com/v2/cheeses' \
-H 'Content-Type: application/json' \
-d '{
"name": "Gorgonzola",
"category": {
"name": "Italian Cheese"
},
"status": "available",
"photoUrls": [
"https://wannabechef.com/gorgonzola.jpg"
],
"tags": [
{
"name": "blue"
},
{
"name": "italian"
},
{
"name": "creamy"
}
]
}'const response = await fetch('https://cheesy.sourcey.com/v2/cheeses', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Gorgonzola",
"category": {
"name": "Italian Cheese"
},
"status": "available",
"photoUrls": [
"https://wannabechef.com/gorgonzola.jpg"
],
"tags": [
{
"name": "blue"
},
{
"name": "italian"
},
{
"name": "creamy"
}
]
}),
});
const data = await response.json();const response = await fetch('https://cheesy.sourcey.com/v2/cheeses', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Gorgonzola",
"category": {
"name": "Italian Cheese"
},
"status": "available",
"photoUrls": [
"https://wannabechef.com/gorgonzola.jpg"
],
"tags": [
{
"name": "blue"
},
{
"name": "italian"
},
{
"name": "creamy"
}
]
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"name": "Gorgonzola",
"category": {
"name": "Italian Cheese"
},
"status": "available",
"photoUrls": [
"https://wannabechef.com/gorgonzola.jpg"
],
"tags": [
{
"name": "blue"
},
{
"name": "italian"
},
{
"name": "creamy"
}
]
}
response = requests.post('https://cheesy.sourcey.com/v2/cheeses', json=payload)
data = response.json()package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"name": "Gorgonzola",
"category": {
"name": "Italian Cheese"
},
"status": "available",
"photoUrls": [
"https://wannabechef.com/gorgonzola.jpg"
],
"tags": [
{
"name": "blue"
},
{
"name": "italian"
},
{
"name": "creamy"
}
]
}`)
req, _ := http.NewRequest("POST", "https://cheesy.sourcey.com/v2/cheeses", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}require 'net/http'
require 'json'
uri = URI('https://cheesy.sourcey.com/v2/cheeses')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"name": "Gorgonzola",
"category": {
"name": "Italian Cheese"
},
"status": "available",
"photoUrls": [
"https://wannabechef.com/gorgonzola.jpg"
],
"tags": [
{
"name": "blue"
},
{
"name": "italian"
},
{
"name": "creamy"
}
]
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"name": "Gorgonzola",
"category": {
"name": "Italian Cheese"
},
"status": "available",
"photoUrls": [
"https://wannabechef.com/gorgonzola.jpg"
],
"tags": [
{
"name": "blue"
},
{
"name": "italian"
},
{
"name": "creamy"
}
]
});
let response = client.post("https://cheesy.sourcey.com/v2/cheeses")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"name": "string",
"category": {
"name": "string"
},
"photoUrls": [
"https://example.com"
],
"tags": [
{
"name": "string"
}
],
"status": "available",
"origin": "string",
"pricePerKg": 0,
"ageMonths": 0,
"organic": false
}{
"id": 42,
"name": "Gorgonzola",
"category": {
"id": 1,
"name": "Italian Cheese"
},
"photoUrls": [
"https://wannabechef.com/gorgonzola.jpg"
],
"tags": [
{
"id": 1,
"name": "blue"
}
],
"status": "available",
"origin": "Italy",
"pricePerKg": 28.5,
"ageMonths": 12,
"organic": false,
"createdAt": "2024-01-15T09:30:00Z",
"updatedAt": "2024-01-15T09:30:00Z"
}{
"code": 404,
"type": "Not found",
"message": "Your cheese has already been eaten"
}{
"code": 422,
"type": "Validation error",
"message": "Your cheese is not mouldy enough",
"errors": [
{
"field": "string",
"message": "string"
}
]
}Update an existing cheese
Replace an existing cheese with updated data. The cheese ID in the body must match an existing cheese.
Body
Cheese object with updated fields
idinteger<int64>requiredUnique identifier
namestringrequiredName of the cheese
categoryobjectphotoUrlsArray<string>URLs of cheese photos
tagsArray<object>Classification tags
statusstringavailablependingsoldrequiredAvailability status in the store
originstring | nullCountry of origin (null if unknown)
pricePerKgnumber<float>Price per kilogram in USD
ageMonthsinteger[0, 120]Aging period in months
organicbooleanfalseWhether the cheese is certified organic
createdAtstring<date-time>When the cheese was added to the store
updatedAtstring<date-time>When the cheese was last updated
Response
Cheese updated successfully
The requested resource was not found
The request body failed validation
Authorization
cheesy_oauthoauth2OAuth2 authentication for full API access
Scopes: write:cheeses
curl -X PUT 'https://cheesy.sourcey.com/v2/cheeses' \
-H 'Content-Type: application/json' \
-d '{
"id": 42,
"name": "Gorgonzola",
"category": {
"id": 1,
"name": "Italian Cheese"
},
"photoUrls": [
"https://wannabechef.com/gorgonzola.jpg"
],
"tags": [
{
"id": 1,
"name": "blue"
}
],
"status": "available",
"origin": "Italy",
"pricePerKg": 28.5,
"ageMonths": 12,
"organic": false,
"createdAt": "2024-01-15T09:30:00Z",
"updatedAt": "2024-01-15T09:30:00Z"
}'const response = await fetch('https://cheesy.sourcey.com/v2/cheeses', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"id": 42,
"name": "Gorgonzola",
"category": {
"id": 1,
"name": "Italian Cheese"
},
"photoUrls": [
"https://wannabechef.com/gorgonzola.jpg"
],
"tags": [
{
"id": 1,
"name": "blue"
}
],
"status": "available",
"origin": "Italy",
"pricePerKg": 28.5,
"ageMonths": 12,
"organic": false,
"createdAt": "2024-01-15T09:30:00Z",
"updatedAt": "2024-01-15T09:30:00Z"
}),
});
const data = await response.json();const response = await fetch('https://cheesy.sourcey.com/v2/cheeses', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"id": 42,
"name": "Gorgonzola",
"category": {
"id": 1,
"name": "Italian Cheese"
},
"photoUrls": [
"https://wannabechef.com/gorgonzola.jpg"
],
"tags": [
{
"id": 1,
"name": "blue"
}
],
"status": "available",
"origin": "Italy",
"pricePerKg": 28.5,
"ageMonths": 12,
"organic": false,
"createdAt": "2024-01-15T09:30:00Z",
"updatedAt": "2024-01-15T09:30:00Z"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"id": 42,
"name": "Gorgonzola",
"category": {
"id": 1,
"name": "Italian Cheese"
},
"photoUrls": [
"https://wannabechef.com/gorgonzola.jpg"
],
"tags": [
{
"id": 1,
"name": "blue"
}
],
"status": "available",
"origin": "Italy",
"pricePerKg": 28.5,
"ageMonths": 12,
"organic": False,
"createdAt": "2024-01-15T09:30:00Z",
"updatedAt": "2024-01-15T09:30:00Z"
}
response = requests.put('https://cheesy.sourcey.com/v2/cheeses', json=payload)
data = response.json()package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"id": 42,
"name": "Gorgonzola",
"category": {
"id": 1,
"name": "Italian Cheese"
},
"photoUrls": [
"https://wannabechef.com/gorgonzola.jpg"
],
"tags": [
{
"id": 1,
"name": "blue"
}
],
"status": "available",
"origin": "Italy",
"pricePerKg": 28.5,
"ageMonths": 12,
"organic": false,
"createdAt": "2024-01-15T09:30:00Z",
"updatedAt": "2024-01-15T09:30:00Z"
}`)
req, _ := http.NewRequest("PUT", "https://cheesy.sourcey.com/v2/cheeses", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}require 'net/http'
require 'json'
uri = URI('https://cheesy.sourcey.com/v2/cheeses')
request = Net::HTTP::Put.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"id": 42,
"name": "Gorgonzola",
"category": {
"id": 1,
"name": "Italian Cheese"
},
"photoUrls": [
"https://wannabechef.com/gorgonzola.jpg"
],
"tags": [
{
"id": 1,
"name": "blue"
}
],
"status": "available",
"origin": "Italy",
"pricePerKg": 28.5,
"ageMonths": 12,
"organic": false,
"createdAt": "2024-01-15T09:30:00Z",
"updatedAt": "2024-01-15T09:30:00Z"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"id": 42,
"name": "Gorgonzola",
"category": {
"id": 1,
"name": "Italian Cheese"
},
"photoUrls": [
"https://wannabechef.com/gorgonzola.jpg"
],
"tags": [
{
"id": 1,
"name": "blue"
}
],
"status": "available",
"origin": "Italy",
"pricePerKg": 28.5,
"ageMonths": 12,
"organic": false,
"createdAt": "2024-01-15T09:30:00Z",
"updatedAt": "2024-01-15T09:30:00Z"
});
let response = client.put("https://cheesy.sourcey.com/v2/cheeses")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"id": 42,
"name": "Gorgonzola",
"category": {
"id": 1,
"name": "Italian Cheese"
},
"photoUrls": [
"https://wannabechef.com/gorgonzola.jpg"
],
"tags": [
{
"id": 1,
"name": "blue"
}
],
"status": "available",
"origin": "Italy",
"pricePerKg": 28.5,
"ageMonths": 12,
"organic": false,
"createdAt": "2024-01-15T09:30:00Z",
"updatedAt": "2024-01-15T09:30:00Z"
}{
"id": 42,
"name": "Gorgonzola",
"category": {
"id": 1,
"name": "Italian Cheese"
},
"photoUrls": [
"https://wannabechef.com/gorgonzola.jpg"
],
"tags": [
{
"id": 1,
"name": "blue"
}
],
"status": "available",
"origin": "Italy",
"pricePerKg": 28.5,
"ageMonths": 12,
"organic": false,
"createdAt": "2024-01-15T09:30:00Z",
"updatedAt": "2024-01-15T09:30:00Z"
}{
"code": 404,
"type": "Not found",
"message": "Your cheese has already been eaten"
}{
"code": 422,
"type": "Validation error",
"message": "Your cheese is not mouldy enough",
"errors": [
{
"field": "string",
"message": "string"
}
]
}Find cheeses by status
Multiple status values can be provided as comma-separated strings. Returns all cheeses matching any of the given statuses.
Parameters
statusArray<string>availablependingsoldrequiredqueryStatus values to filter by
Response
Matching cheeses
Invalid status value provided
Authorization
cheesy_oauthoauth2OAuth2 authentication for full API access
Scopes: read:cheeses
curl -X GET 'https://cheesy.sourcey.com/v2/cheeses/findByStatus'const response = await fetch('https://cheesy.sourcey.com/v2/cheeses/findByStatus', {
method: 'GET',
});
const data = await response.json();const response = await fetch('https://cheesy.sourcey.com/v2/cheeses/findByStatus', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://cheesy.sourcey.com/v2/cheeses/findByStatus')
data = response.json()package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://cheesy.sourcey.com/v2/cheeses/findByStatus", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}require 'net/http'
require 'json'
uri = URI('https://cheesy.sourcey.com/v2/cheeses/findByStatus')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://cheesy.sourcey.com/v2/cheeses/findByStatus")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}[
{
"id": 42,
"name": "Gorgonzola",
"category": {
"id": 1,
"name": "Italian Cheese"
},
"photoUrls": [
"https://wannabechef.com/gorgonzola.jpg"
],
"tags": [
{
"id": 1,
"name": "blue"
}
],
"status": "available",
"origin": "Italy",
"pricePerKg": 28.5,
"ageMonths": 12,
"organic": false,
"createdAt": "2024-01-15T09:30:00Z",
"updatedAt": "2024-01-15T09:30:00Z"
}
]{
"code": 404,
"type": "Not found",
"message": "Your cheese has already been eaten"
}Get cheese by ID
Returns detailed information about a specific cheese, including its category, tags, and current availability status.
Parameters
cheeseIdinteger<int64>requiredpathUnique identifier for the cheese
Response
Cheese details
The requested resource was not found
Authorization
api_keyapiKey in headerAPI key authentication. Include your API key in the X-API-Key header.
Get your key from the developer dashboard.
curl -X GET 'https://cheesy.sourcey.com/v2/cheeses/{cheeseId}'const response = await fetch('https://cheesy.sourcey.com/v2/cheeses/{cheeseId}', {
method: 'GET',
});
const data = await response.json();const response = await fetch('https://cheesy.sourcey.com/v2/cheeses/{cheeseId}', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://cheesy.sourcey.com/v2/cheeses/{cheeseId}')
data = response.json()package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://cheesy.sourcey.com/v2/cheeses/{cheeseId}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}require 'net/http'
require 'json'
uri = URI('https://cheesy.sourcey.com/v2/cheeses/{cheeseId}')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://cheesy.sourcey.com/v2/cheeses/{cheeseId}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"id": 42,
"name": "Gorgonzola",
"category": {
"id": 1,
"name": "Italian Cheese"
},
"photoUrls": [
"https://wannabechef.com/gorgonzola.jpg"
],
"tags": [
{
"id": 1,
"name": "blue"
}
],
"status": "available",
"origin": "Italy",
"pricePerKg": 28.5,
"ageMonths": 12,
"organic": false,
"createdAt": "2024-01-15T09:30:00Z",
"updatedAt": "2024-01-15T09:30:00Z"
}{
"code": 404,
"type": "Not found",
"message": "Your cheese has already been eaten"
}Update cheese with form data
Updates specific fields of a cheese using form data. Only provided fields are updated.
Parameters
cheeseIdinteger<int64>requiredpathUnique identifier for the cheese
namestringqueryUpdated name of the cheese
statusstringavailablependingsoldqueryUpdated status of the cheese
Response
Cheese updated
The requested resource was not found
The request body failed validation
Authorization
cheesy_oauthoauth2OAuth2 authentication for full API access
Scopes: write:cheeses
curl -X POST 'https://cheesy.sourcey.com/v2/cheeses/{cheeseId}'const response = await fetch('https://cheesy.sourcey.com/v2/cheeses/{cheeseId}', {
method: 'POST',
});
const data = await response.json();const response = await fetch('https://cheesy.sourcey.com/v2/cheeses/{cheeseId}', {
method: 'POST',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.post('https://cheesy.sourcey.com/v2/cheeses/{cheeseId}')
data = response.json()package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("POST", "https://cheesy.sourcey.com/v2/cheeses/{cheeseId}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}require 'net/http'
require 'json'
uri = URI('https://cheesy.sourcey.com/v2/cheeses/{cheeseId}')
request = Net::HTTP::Post.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.post("https://cheesy.sourcey.com/v2/cheeses/{cheeseId}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"id": 42,
"name": "Gorgonzola",
"category": {
"id": 1,
"name": "Italian Cheese"
},
"photoUrls": [
"https://wannabechef.com/gorgonzola.jpg"
],
"tags": [
{
"id": 1,
"name": "blue"
}
],
"status": "available",
"origin": "Italy",
"pricePerKg": 28.5,
"ageMonths": 12,
"organic": false,
"createdAt": "2024-01-15T09:30:00Z",
"updatedAt": "2024-01-15T09:30:00Z"
}{
"code": 404,
"type": "Not found",
"message": "Your cheese has already been eaten"
}{
"code": 422,
"type": "Validation error",
"message": "Your cheese is not mouldy enough",
"errors": [
{
"field": "string",
"message": "string"
}
]
}Delete a cheese
Permanently removes a cheese from the store. This action cannot be undone. Any pending orders for this cheese will be cancelled.
Parameters
cheeseIdinteger<int64>requiredpathUnique identifier for the cheese
X-Confirm-DeletebooleanrequiredheaderMust be set to true to confirm deletion
Response
Cheese deleted successfully
The requested resource was not found
Cheese has active orders and cannot be deleted
Authorization
cheesy_oauthoauth2OAuth2 authentication for full API access
Scopes: write:cheeses
curl -X DELETE 'https://cheesy.sourcey.com/v2/cheeses/{cheeseId}'const response = await fetch('https://cheesy.sourcey.com/v2/cheeses/{cheeseId}', {
method: 'DELETE',
});
const data = await response.json();const response = await fetch('https://cheesy.sourcey.com/v2/cheeses/{cheeseId}', {
method: 'DELETE',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.delete('https://cheesy.sourcey.com/v2/cheeses/{cheeseId}')
data = response.json()package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("DELETE", "https://cheesy.sourcey.com/v2/cheeses/{cheeseId}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}require 'net/http'
require 'json'
uri = URI('https://cheesy.sourcey.com/v2/cheeses/{cheeseId}')
request = Net::HTTP::Delete.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.delete("https://cheesy.sourcey.com/v2/cheeses/{cheeseId}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"code": 404,
"type": "Not found",
"message": "Your cheese has already been eaten"
}{
"code": 404,
"type": "Not found",
"message": "Your cheese has already been eaten"
}Upload a cheese image
Upload a photo of the cheese. Supports JPEG, PNG, and WebP formats. Maximum file size is 10MB.
Body
filestring<binary>requiredImage file (JPEG, PNG, or WebP, max 10MB)
captionstringOptional caption for the image
isPrimarybooleanfalseSet as the primary display image
Parameters
cheeseIdinteger<int64>requiredpathID of cheese to upload image for
Response
Image uploaded successfully
File too large (max 10MB)
Unsupported media type
Authorization
cheesy_oauthoauth2OAuth2 authentication for full API access
Scopes: write:cheeses
curl -X POST 'https://cheesy.sourcey.com/v2/cheeses/{cheeseId}/uploadImage' \
-H 'Content-Type: multipart/form-data' \
-d '{
"file": "<binary>",
"caption": "string",
"isPrimary": false
}'const response = await fetch('https://cheesy.sourcey.com/v2/cheeses/{cheeseId}/uploadImage', {
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
},
body: JSON.stringify({
"file": "<binary>",
"caption": "string",
"isPrimary": false
}),
});
const data = await response.json();const response = await fetch('https://cheesy.sourcey.com/v2/cheeses/{cheeseId}/uploadImage', {
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
},
body: JSON.stringify({
"file": "<binary>",
"caption": "string",
"isPrimary": false
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"file": "<binary>",
"caption": "string",
"isPrimary": False
}
response = requests.post('https://cheesy.sourcey.com/v2/cheeses/{cheeseId}/uploadImage', json=payload)
data = response.json()package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"file": "<binary>",
"caption": "string",
"isPrimary": false
}`)
req, _ := http.NewRequest("POST", "https://cheesy.sourcey.com/v2/cheeses/{cheeseId}/uploadImage", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}require 'net/http'
require 'json'
uri = URI('https://cheesy.sourcey.com/v2/cheeses/{cheeseId}/uploadImage')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'multipart/form-data'
request.body = '{
"file": "<binary>",
"caption": "string",
"isPrimary": false
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"file": "<binary>",
"caption": "string",
"isPrimary": false
});
let response = client.post("https://cheesy.sourcey.com/v2/cheeses/{cheeseId}/uploadImage")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"file": "<binary>",
"caption": "string",
"isPrimary": false
}{
"imageUrl": "https://example.com",
"thumbnailUrl": "https://example.com",
"size": 0
}{
"code": 404,
"type": "Not found",
"message": "Your cheese has already been eaten"
}{
"code": 404,
"type": "Not found",
"message": "Your cheese has already been eaten"
}Store
Store endpoints provide access to cheese store orders and inventory management. Orders track the purchase lifecycle from placement through delivery.
Get store inventory
Returns a map of cheese status codes to quantities, representing the current inventory levels.
Response
Inventory counts by status
Authorization
api_keyapiKey in headerAPI key authentication. Include your API key in the X-API-Key header.
Get your key from the developer dashboard.
curl -X GET 'https://cheesy.sourcey.com/v2/store/inventory'const response = await fetch('https://cheesy.sourcey.com/v2/store/inventory', {
method: 'GET',
});
const data = await response.json();const response = await fetch('https://cheesy.sourcey.com/v2/store/inventory', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://cheesy.sourcey.com/v2/store/inventory')
data = response.json()package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://cheesy.sourcey.com/v2/store/inventory", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}require 'net/http'
require 'json'
uri = URI('https://cheesy.sourcey.com/v2/store/inventory')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://cheesy.sourcey.com/v2/store/inventory")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{}Place a cheese order
Place an order to purchase cheese from the store. The cheese must be in available status.
Orders are processed asynchronously. Use the returned order ID to check status via GET /store/order/{orderId}.
Body
Order details
itemsArray<object>requiredshippingAddressobjectrequirednotesstring | nullResponse
Order placed successfully
The request body failed validation
Authorization
cheesy_oauthoauth2OAuth2 authentication for full API access
Scopes: write:orders
curl -X POST 'https://cheesy.sourcey.com/v2/store/order' \
-H 'Content-Type: application/json' \
-d '{
"items": [
{
"cheeseId": 42,
"quantity": 3
},
{
"cheeseId": 17,
"quantity": 1
}
],
"shippingAddress": {
"street": "123 Cheese Lane",
"city": "Cheddarville",
"state": "WI",
"zipCode": "53001",
"country": "US"
},
"notes": "Please wrap each wheel separately"
}'const response = await fetch('https://cheesy.sourcey.com/v2/store/order', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"items": [
{
"cheeseId": 42,
"quantity": 3
},
{
"cheeseId": 17,
"quantity": 1
}
],
"shippingAddress": {
"street": "123 Cheese Lane",
"city": "Cheddarville",
"state": "WI",
"zipCode": "53001",
"country": "US"
},
"notes": "Please wrap each wheel separately"
}),
});
const data = await response.json();const response = await fetch('https://cheesy.sourcey.com/v2/store/order', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"items": [
{
"cheeseId": 42,
"quantity": 3
},
{
"cheeseId": 17,
"quantity": 1
}
],
"shippingAddress": {
"street": "123 Cheese Lane",
"city": "Cheddarville",
"state": "WI",
"zipCode": "53001",
"country": "US"
},
"notes": "Please wrap each wheel separately"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"items": [
{
"cheeseId": 42,
"quantity": 3
},
{
"cheeseId": 17,
"quantity": 1
}
],
"shippingAddress": {
"street": "123 Cheese Lane",
"city": "Cheddarville",
"state": "WI",
"zipCode": "53001",
"country": "US"
},
"notes": "Please wrap each wheel separately"
}
response = requests.post('https://cheesy.sourcey.com/v2/store/order', json=payload)
data = response.json()package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"items": [
{
"cheeseId": 42,
"quantity": 3
},
{
"cheeseId": 17,
"quantity": 1
}
],
"shippingAddress": {
"street": "123 Cheese Lane",
"city": "Cheddarville",
"state": "WI",
"zipCode": "53001",
"country": "US"
},
"notes": "Please wrap each wheel separately"
}`)
req, _ := http.NewRequest("POST", "https://cheesy.sourcey.com/v2/store/order", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}require 'net/http'
require 'json'
uri = URI('https://cheesy.sourcey.com/v2/store/order')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"items": [
{
"cheeseId": 42,
"quantity": 3
},
{
"cheeseId": 17,
"quantity": 1
}
],
"shippingAddress": {
"street": "123 Cheese Lane",
"city": "Cheddarville",
"state": "WI",
"zipCode": "53001",
"country": "US"
},
"notes": "Please wrap each wheel separately"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"items": [
{
"cheeseId": 42,
"quantity": 3
},
{
"cheeseId": 17,
"quantity": 1
}
],
"shippingAddress": {
"street": "123 Cheese Lane",
"city": "Cheddarville",
"state": "WI",
"zipCode": "53001",
"country": "US"
},
"notes": "Please wrap each wheel separately"
});
let response = client.post("https://cheesy.sourcey.com/v2/store/order")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"items": [
{
"cheeseId": 0,
"quantity": 1
}
],
"shippingAddress": {
"street": "123 Cheese Lane",
"city": "Cheddarville",
"state": "WI",
"zipCode": "53001",
"country": "US"
},
"notes": "string"
}{
"id": 1001,
"items": [
{
"cheeseId": 42,
"cheeseName": "Gorgonzola",
"quantity": 3,
"pricePerKg": 28.5
},
{
"cheeseId": 17,
"cheeseName": "Brie",
"quantity": 1,
"pricePerKg": 22
}
],
"shippingAddress": {
"street": "123 Cheese Lane",
"city": "Cheddarville",
"state": "WI",
"zipCode": "53001",
"country": "US"
},
"status": "placed",
"notes": "Please wrap each wheel separately",
"total": 114.5,
"shipDate": null,
"createdAt": "2026-03-10T14:30:00Z",
"updatedAt": "2026-03-10T14:30:00Z"
}{
"code": 422,
"type": "Validation error",
"message": "Your cheese is not mouldy enough",
"errors": [
{
"field": "string",
"message": "string"
}
]
}Get order by ID
Retrieve details of a specific order. For testing, use order IDs between 1 and 10.
Parameters
orderIdinteger<int64>requiredpathID of the order
Response
Order details
The requested resource was not found
Authorization
api_keyapiKey in headerAPI key authentication. Include your API key in the X-API-Key header.
Get your key from the developer dashboard.
curl -X GET 'https://cheesy.sourcey.com/v2/store/order/{orderId}'const response = await fetch('https://cheesy.sourcey.com/v2/store/order/{orderId}', {
method: 'GET',
});
const data = await response.json();const response = await fetch('https://cheesy.sourcey.com/v2/store/order/{orderId}', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://cheesy.sourcey.com/v2/store/order/{orderId}')
data = response.json()package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://cheesy.sourcey.com/v2/store/order/{orderId}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}require 'net/http'
require 'json'
uri = URI('https://cheesy.sourcey.com/v2/store/order/{orderId}')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://cheesy.sourcey.com/v2/store/order/{orderId}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"id": 1001,
"items": [
{
"cheeseId": 42,
"cheeseName": "Gorgonzola",
"quantity": 3,
"pricePerKg": 28.5
},
{
"cheeseId": 17,
"cheeseName": "Brie",
"quantity": 1,
"pricePerKg": 22
}
],
"shippingAddress": {
"street": "123 Cheese Lane",
"city": "Cheddarville",
"state": "WI",
"zipCode": "53001",
"country": "US"
},
"status": "placed",
"notes": "Please wrap each wheel separately",
"total": 114.5,
"shipDate": null,
"createdAt": "2026-03-10T14:30:00Z",
"updatedAt": "2026-03-10T14:30:00Z"
}{
"code": 404,
"type": "Not found",
"message": "Your cheese has already been eaten"
}Cancel an order
Cancel a pending order. Orders that have already been shipped cannot be cancelled.
Parameters
orderIdinteger<int64>requiredpathID of the order
Response
Order cancelled successfully
The requested resource was not found
Order has already been shipped
Authorization
cheesy_oauthoauth2OAuth2 authentication for full API access
Scopes: write:orders
curl -X DELETE 'https://cheesy.sourcey.com/v2/store/order/{orderId}'const response = await fetch('https://cheesy.sourcey.com/v2/store/order/{orderId}', {
method: 'DELETE',
});
const data = await response.json();const response = await fetch('https://cheesy.sourcey.com/v2/store/order/{orderId}', {
method: 'DELETE',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.delete('https://cheesy.sourcey.com/v2/store/order/{orderId}')
data = response.json()package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("DELETE", "https://cheesy.sourcey.com/v2/store/order/{orderId}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}require 'net/http'
require 'json'
uri = URI('https://cheesy.sourcey.com/v2/store/order/{orderId}')
request = Net::HTTP::Delete.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.delete("https://cheesy.sourcey.com/v2/store/order/{orderId}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"code": 404,
"type": "Not found",
"message": "Your cheese has already been eaten"
}{
"code": 404,
"type": "Not found",
"message": "Your cheese has already been eaten"
}Customer
Customer endpoints handle account creation, authentication, and profile management.
Customer accounts support OAuth2 login and API key authentication.
Create a customer account
Register a new customer account. The username and email must be unique.
Body
Customer registration details
usernamestringrequiredfirstNamestringlastNamestringemailstring<email>requiredpasswordstring<password>requiredphonestring | nullResponse
Customer account created
Username or email already exists
The request body failed validation
curl -X POST 'https://cheesy.sourcey.com/v2/customer' \
-H 'Content-Type: application/json' \
-d '{
"username": "gordo",
"firstName": "Alotta",
"lastName": "Cheese",
"email": "[email protected]",
"password": "secret123!",
"phone": "+3344556677"
}'const response = await fetch('https://cheesy.sourcey.com/v2/customer', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"username": "gordo",
"firstName": "Alotta",
"lastName": "Cheese",
"email": "[email protected]",
"password": "secret123!",
"phone": "+3344556677"
}),
});
const data = await response.json();const response = await fetch('https://cheesy.sourcey.com/v2/customer', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"username": "gordo",
"firstName": "Alotta",
"lastName": "Cheese",
"email": "[email protected]",
"password": "secret123!",
"phone": "+3344556677"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"username": "gordo",
"firstName": "Alotta",
"lastName": "Cheese",
"email": "[email protected]",
"password": "secret123!",
"phone": "+3344556677"
}
response = requests.post('https://cheesy.sourcey.com/v2/customer', json=payload)
data = response.json()package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"username": "gordo",
"firstName": "Alotta",
"lastName": "Cheese",
"email": "[email protected]",
"password": "secret123!",
"phone": "+3344556677"
}`)
req, _ := http.NewRequest("POST", "https://cheesy.sourcey.com/v2/customer", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}require 'net/http'
require 'json'
uri = URI('https://cheesy.sourcey.com/v2/customer')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"username": "gordo",
"firstName": "Alotta",
"lastName": "Cheese",
"email": "[email protected]",
"password": "secret123!",
"phone": "+3344556677"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"username": "gordo",
"firstName": "Alotta",
"lastName": "Cheese",
"email": "[email protected]",
"password": "secret123!",
"phone": "+3344556677"
});
let response = client.post("https://cheesy.sourcey.com/v2/customer")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"username": "string",
"firstName": "string",
"lastName": "string",
"email": "[email protected]",
"password": "********",
"phone": "string"
}{
"id": 1,
"username": "gordo",
"firstName": "Alotta",
"lastName": "Cheese",
"email": "[email protected]",
"phone": "+3344556677",
"customerStatus": "gold",
"favouriteCheese": {
"id": 42,
"name": "Gorgonzola",
"category": {
"id": 1,
"name": "Italian Cheese"
},
"photoUrls": [
"https://wannabechef.com/gorgonzola.jpg"
],
"tags": [
{
"id": 1,
"name": "blue"
}
],
"status": "available",
"origin": "Italy",
"pricePerKg": 28.5,
"ageMonths": 12,
"organic": false,
"createdAt": "2024-01-15T09:30:00Z",
"updatedAt": "2024-01-15T09:30:00Z"
},
"createdAt": "2024-01-15T09:30:00Z"
}{
"code": 404,
"type": "Not found",
"message": "Your cheese has already been eaten"
}{
"code": 422,
"type": "Validation error",
"message": "Your cheese is not mouldy enough",
"errors": [
{
"field": "string",
"message": "string"
}
]
}Create multiple customers
Create a batch of customer accounts from an array. Each customer is validated independently - partial success is possible.
Returns the created customers and any validation errors:
{
"created": [...],
"errors": [
{ "index": 2, "message": "Email already exists" }
]
}Body
Array of customer objects to create
Response
Batch creation result
The request body failed validation
curl -X POST 'https://cheesy.sourcey.com/v2/customer/createMultiple' \
-H 'Content-Type: application/json' \
-d '[
{
"username": "string",
"firstName": "string",
"lastName": "string",
"email": "[email protected]",
"password": "********",
"phone": "string"
}
]'const response = await fetch('https://cheesy.sourcey.com/v2/customer/createMultiple', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify([
{
"username": "string",
"firstName": "string",
"lastName": "string",
"email": "[email protected]",
"password": "********",
"phone": "string"
}
]),
});
const data = await response.json();const response = await fetch('https://cheesy.sourcey.com/v2/customer/createMultiple', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify([
{
"username": "string",
"firstName": "string",
"lastName": "string",
"email": "[email protected]",
"password": "********",
"phone": "string"
}
]),
});
const data: Record<string, unknown> = await response.json();import requests
payload = [
{
"username": "string",
"firstName": "string",
"lastName": "string",
"email": "[email protected]",
"password": "********",
"phone": "string"
}
]
response = requests.post('https://cheesy.sourcey.com/v2/customer/createMultiple', json=payload)
data = response.json()package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`[
{
"username": "string",
"firstName": "string",
"lastName": "string",
"email": "[email protected]",
"password": "********",
"phone": "string"
}
]`)
req, _ := http.NewRequest("POST", "https://cheesy.sourcey.com/v2/customer/createMultiple", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}require 'net/http'
require 'json'
uri = URI('https://cheesy.sourcey.com/v2/customer/createMultiple')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '[
{
"username": "string",
"firstName": "string",
"lastName": "string",
"email": "[email protected]",
"password": "********",
"phone": "string"
}
]'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!([
{
"username": "string",
"firstName": "string",
"lastName": "string",
"email": "[email protected]",
"password": "********",
"phone": "string"
}
]);
let response = client.post("https://cheesy.sourcey.com/v2/customer/createMultiple")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}[
{
"username": "string",
"firstName": "string",
"lastName": "string",
"email": "[email protected]",
"password": "********",
"phone": "string"
}
]{
"created": [
{
"id": 1,
"username": "gordo",
"firstName": "Alotta",
"lastName": "Cheese",
"email": "[email protected]",
"phone": "+3344556677",
"customerStatus": "gold",
"favouriteCheese": {
"id": 42,
"name": "Gorgonzola",
"category": {
"id": 1,
"name": "Italian Cheese"
},
"photoUrls": [
"https://wannabechef.com/gorgonzola.jpg"
],
"tags": [
{
"id": 1,
"name": "blue"
}
],
"status": "available",
"origin": "Italy",
"pricePerKg": 28.5,
"ageMonths": 12,
"organic": false,
"createdAt": "2024-01-15T09:30:00Z",
"updatedAt": "2024-01-15T09:30:00Z"
},
"createdAt": "2024-01-15T09:30:00Z"
}
],
"errors": [
{
"index": 0,
"message": "string"
}
]
}{
"code": 422,
"type": "Validation error",
"message": "Your cheese is not mouldy enough",
"errors": [
{
"field": "string",
"message": "string"
}
]
}Customer login
Authenticate a customer and receive a session token. The token expires after 24 hours.
Body
usernamestringrequiredThe customer's username
passwordstring<password>requiredThe customer's password
Response
Login successful
Invalid username or password
curl -X POST 'https://cheesy.sourcey.com/v2/customer/login' \
-H 'Content-Type: application/json' \
-d '{
"username": "string",
"password": "********"
}'const response = await fetch('https://cheesy.sourcey.com/v2/customer/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"username": "string",
"password": "********"
}),
});
const data = await response.json();const response = await fetch('https://cheesy.sourcey.com/v2/customer/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"username": "string",
"password": "********"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"username": "string",
"password": "********"
}
response = requests.post('https://cheesy.sourcey.com/v2/customer/login', json=payload)
data = response.json()package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"username": "string",
"password": "********"
}`)
req, _ := http.NewRequest("POST", "https://cheesy.sourcey.com/v2/customer/login", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}require 'net/http'
require 'json'
uri = URI('https://cheesy.sourcey.com/v2/customer/login')
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"username": "string",
"password": "********"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"username": "string",
"password": "********"
});
let response = client.post("https://cheesy.sourcey.com/v2/customer/login")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"username": "string",
"password": "********"
}{
"token": "string",
"expiresAt": "2024-01-15T09:30:00Z"
}{
"code": 404,
"type": "Not found",
"message": "Your cheese has already been eaten"
}Customer logout
End the current customer session and invalidate the session token.
Response
Logout successful
Authorization
bearer_authhttp (bearer)JWT token obtained from the /customer/login endpoint
curl -X GET 'https://cheesy.sourcey.com/v2/customer/logout'const response = await fetch('https://cheesy.sourcey.com/v2/customer/logout', {
method: 'GET',
});
const data = await response.json();const response = await fetch('https://cheesy.sourcey.com/v2/customer/logout', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://cheesy.sourcey.com/v2/customer/logout')
data = response.json()package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://cheesy.sourcey.com/v2/customer/logout", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}require 'net/http'
require 'json'
uri = URI('https://cheesy.sourcey.com/v2/customer/logout')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://cheesy.sourcey.com/v2/customer/logout")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}Get customer by username
Retrieve a customer's profile by their username.
Parameters
usernamestringrequiredpathThe customer's username
Response
Customer profile
The requested resource was not found
Authorization
api_keyapiKey in headerAPI key authentication. Include your API key in the X-API-Key header.
Get your key from the developer dashboard.
bearer_authhttp (bearer)JWT token obtained from the /customer/login endpoint
curl -X GET 'https://cheesy.sourcey.com/v2/customer/{username}'const response = await fetch('https://cheesy.sourcey.com/v2/customer/{username}', {
method: 'GET',
});
const data = await response.json();const response = await fetch('https://cheesy.sourcey.com/v2/customer/{username}', {
method: 'GET',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.get('https://cheesy.sourcey.com/v2/customer/{username}')
data = response.json()package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://cheesy.sourcey.com/v2/customer/{username}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}require 'net/http'
require 'json'
uri = URI('https://cheesy.sourcey.com/v2/customer/{username}')
request = Net::HTTP::Get.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.get("https://cheesy.sourcey.com/v2/customer/{username}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"id": 1,
"username": "gordo",
"firstName": "Alotta",
"lastName": "Cheese",
"email": "[email protected]",
"phone": "+3344556677",
"customerStatus": "gold",
"favouriteCheese": {
"id": 42,
"name": "Gorgonzola",
"category": {
"id": 1,
"name": "Italian Cheese"
},
"photoUrls": [
"https://wannabechef.com/gorgonzola.jpg"
],
"tags": [
{
"id": 1,
"name": "blue"
}
],
"status": "available",
"origin": "Italy",
"pricePerKg": 28.5,
"ageMonths": 12,
"organic": false,
"createdAt": "2024-01-15T09:30:00Z",
"updatedAt": "2024-01-15T09:30:00Z"
},
"createdAt": "2024-01-15T09:30:00Z"
}{
"code": 404,
"type": "Not found",
"message": "Your cheese has already been eaten"
}Update customer profile
Update a customer's profile. Can only be performed by the authenticated customer.
Body
Updated customer fields
usernamestringrequiredfirstNamestringlastNamestringemailstring<email>requiredpasswordstring<password>requiredphonestring | nullParameters
usernamestringrequiredpathThe customer's username
Response
Customer updated
The requested resource was not found
The request body failed validation
Authorization
bearer_authhttp (bearer)JWT token obtained from the /customer/login endpoint
curl -X PUT 'https://cheesy.sourcey.com/v2/customer/{username}' \
-H 'Content-Type: application/json' \
-d '{
"username": "string",
"firstName": "string",
"lastName": "string",
"email": "[email protected]",
"password": "********",
"phone": "string"
}'const response = await fetch('https://cheesy.sourcey.com/v2/customer/{username}', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"username": "string",
"firstName": "string",
"lastName": "string",
"email": "[email protected]",
"password": "********",
"phone": "string"
}),
});
const data = await response.json();const response = await fetch('https://cheesy.sourcey.com/v2/customer/{username}', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"username": "string",
"firstName": "string",
"lastName": "string",
"email": "[email protected]",
"password": "********",
"phone": "string"
}),
});
const data: Record<string, unknown> = await response.json();import requests
payload = {
"username": "string",
"firstName": "string",
"lastName": "string",
"email": "[email protected]",
"password": "********",
"phone": "string"
}
response = requests.put('https://cheesy.sourcey.com/v2/customer/{username}', json=payload)
data = response.json()package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"username": "string",
"firstName": "string",
"lastName": "string",
"email": "[email protected]",
"password": "********",
"phone": "string"
}`)
req, _ := http.NewRequest("PUT", "https://cheesy.sourcey.com/v2/customer/{username}", body)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}require 'net/http'
require 'json'
uri = URI('https://cheesy.sourcey.com/v2/customer/{username}')
request = Net::HTTP::Put.new(uri)
request['Content-Type'] = 'application/json'
request.body = '{
"username": "string",
"firstName": "string",
"lastName": "string",
"email": "[email protected]",
"password": "********",
"phone": "string"
}'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let body = serde_json::json!({
"username": "string",
"firstName": "string",
"lastName": "string",
"email": "[email protected]",
"password": "********",
"phone": "string"
});
let response = client.put("https://cheesy.sourcey.com/v2/customer/{username}")
.json(&body)
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"username": "string",
"firstName": "string",
"lastName": "string",
"email": "[email protected]",
"password": "********",
"phone": "string"
}{
"id": 1,
"username": "gordo",
"firstName": "Alotta",
"lastName": "Cheese",
"email": "[email protected]",
"phone": "+3344556677",
"customerStatus": "gold",
"favouriteCheese": {
"id": 42,
"name": "Gorgonzola",
"category": {
"id": 1,
"name": "Italian Cheese"
},
"photoUrls": [
"https://wannabechef.com/gorgonzola.jpg"
],
"tags": [
{
"id": 1,
"name": "blue"
}
],
"status": "available",
"origin": "Italy",
"pricePerKg": 28.5,
"ageMonths": 12,
"organic": false,
"createdAt": "2024-01-15T09:30:00Z",
"updatedAt": "2024-01-15T09:30:00Z"
},
"createdAt": "2024-01-15T09:30:00Z"
}{
"code": 404,
"type": "Not found",
"message": "Your cheese has already been eaten"
}{
"code": 422,
"type": "Validation error",
"message": "Your cheese is not mouldy enough",
"errors": [
{
"field": "string",
"message": "string"
}
]
}Delete customer account
Permanently delete a customer account and all associated data. This action cannot be undone.
Parameters
usernamestringrequiredpathThe customer's username
Response
Customer deleted
The requested resource was not found
Authorization
bearer_authhttp (bearer)JWT token obtained from the /customer/login endpoint
curl -X DELETE 'https://cheesy.sourcey.com/v2/customer/{username}'const response = await fetch('https://cheesy.sourcey.com/v2/customer/{username}', {
method: 'DELETE',
});
const data = await response.json();const response = await fetch('https://cheesy.sourcey.com/v2/customer/{username}', {
method: 'DELETE',
});
const data: Record<string, unknown> = await response.json();import requests
response = requests.delete('https://cheesy.sourcey.com/v2/customer/{username}')
data = response.json()package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("DELETE", "https://cheesy.sourcey.com/v2/customer/{username}", nil)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
fmt.Println(string(data))
}require 'net/http'
require 'json'
uri = URI('https://cheesy.sourcey.com/v2/customer/{username}')
request = Net::HTTP::Delete.new(uri)
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }
data = JSON.parse(response.body)use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let response = client.delete("https://cheesy.sourcey.com/v2/customer/{username}")
.send()
.await?
.text()
.await?;
println!("{}", response);
Ok(())
}{
"code": 404,
"type": "Not found",
"message": "Your cheese has already been eaten"
}Models
Cheese
objectidinteger<int64>requiredUnique identifier
namestringrequiredName of the cheese
categoryobjectphotoUrlsArray<string>URLs of cheese photos
tagsArray<object>Classification tags
statusstringavailablependingsoldrequiredAvailability status in the store
originstring | nullCountry of origin (null if unknown)
pricePerKgnumber<float>Price per kilogram in USD
ageMonthsinteger[0, 120]Aging period in months
organicbooleanfalseWhether the cheese is certified organic
createdAtstring<date-time>When the cheese was added to the store
updatedAtstring<date-time>When the cheese was last updated
{
"id": 42,
"name": "Gorgonzola",
"category": {
"id": 1,
"name": "Italian Cheese"
},
"photoUrls": [
"https://wannabechef.com/gorgonzola.jpg"
],
"tags": [
{
"id": 1,
"name": "blue"
}
],
"status": "available",
"origin": "Italy",
"pricePerKg": 28.5,
"ageMonths": 12,
"organic": false,
"createdAt": "2024-01-15T09:30:00Z",
"updatedAt": "2024-01-15T09:30:00Z"
}CheeseInput
objectnamestringrequiredcategoryobjectphotoUrlsArray<string>tagsArray<object>statusstringavailablependingsoldavailableoriginstring | nullpricePerKgnumber<float>ageMonthsinteger[0, 120]organicbooleanfalse{
"name": "string",
"category": {
"name": "string"
},
"photoUrls": [
"https://example.com"
],
"tags": [
{
"name": "string"
}
],
"status": "available",
"origin": "string",
"pricePerKg": 0,
"ageMonths": 0,
"organic": false
}CheeseList
objectPaginated list of cheeses
itemsArray<object>nextCursorstring | nullCursor for the next page (null if no more results)
hasMorebooleanWhether there are more results
totalintegerTotal number of matching cheeses
{
"items": [
{
"id": 42,
"name": "Gorgonzola",
"category": {
"id": 1,
"name": "Italian Cheese"
},
"photoUrls": [
"https://wannabechef.com/gorgonzola.jpg"
],
"tags": [
{
"id": 1,
"name": "blue"
}
],
"status": "available",
"origin": "Italy",
"pricePerKg": 28.5,
"ageMonths": 12,
"organic": false,
"createdAt": "2024-01-15T09:30:00Z",
"updatedAt": "2024-01-15T09:30:00Z"
}
],
"nextCursor": "string",
"hasMore": true,
"total": 0
}Order
objectidinteger<int64>itemsArray<object>shippingAddressobjectstatusstringplacedapprovedshippeddeliveredcancelledOrder lifecycle status
notesstring | nullSpecial instructions for the order
totalnumber<float>Order total in USD
shipDatestring<date-time> | nullEstimated ship date (null if not yet scheduled)
createdAtstring<date-time>updatedAtstring<date-time>{
"id": 1001,
"items": [
{
"cheeseId": 42,
"cheeseName": "Gorgonzola",
"quantity": 3,
"pricePerKg": 28.5
},
{
"cheeseId": 17,
"cheeseName": "Brie",
"quantity": 1,
"pricePerKg": 22
}
],
"shippingAddress": {
"street": "123 Cheese Lane",
"city": "Cheddarville",
"state": "WI",
"zipCode": "53001",
"country": "US"
},
"status": "placed",
"notes": "Please wrap each wheel separately",
"total": 114.5,
"shipDate": null,
"createdAt": "2026-03-10T14:30:00Z",
"updatedAt": "2026-03-10T14:30:00Z"
}OrderInput
objectitemsArray<object>requiredshippingAddressobjectrequirednotesstring | null{
"items": [
{
"cheeseId": 0,
"quantity": 1
}
],
"shippingAddress": {
"street": "123 Cheese Lane",
"city": "Cheddarville",
"state": "WI",
"zipCode": "53001",
"country": "US"
},
"notes": "string"
}OrderItem
objectcheeseIdinteger<int64>cheeseNamestringquantityintegerpricePerKgnumber<float>{
"cheeseId": 0,
"cheeseName": "string",
"quantity": 1,
"pricePerKg": 0
}Address
objectstreetstringrequiredcitystringrequiredstatestring | nullzipCodestringcountrystringrequiredISO 3166-1 alpha-2 country code
{
"street": "123 Cheese Lane",
"city": "Cheddarville",
"state": "WI",
"zipCode": "53001",
"country": "US"
}Customer
objectidinteger<int64>usernamestringfirstNamestringCustomer first name
lastNamestringCustomer last name
emailstring<email>phonestring | nullcustomerStatusstringbronzesilvergoldplatinumCustomer tier based on purchase volume
favouriteCheeseobject | objectThe customer's favourite cheese (by reference or by name)
createdAtstring<date-time>{
"id": 1,
"username": "gordo",
"firstName": "Alotta",
"lastName": "Cheese",
"email": "[email protected]",
"phone": "+3344556677",
"customerStatus": "gold",
"favouriteCheese": {
"id": 42,
"name": "Gorgonzola",
"category": {
"id": 1,
"name": "Italian Cheese"
},
"photoUrls": [
"https://wannabechef.com/gorgonzola.jpg"
],
"tags": [
{
"id": 1,
"name": "blue"
}
],
"status": "available",
"origin": "Italy",
"pricePerKg": 28.5,
"ageMonths": 12,
"organic": false,
"createdAt": "2024-01-15T09:30:00Z",
"updatedAt": "2024-01-15T09:30:00Z"
},
"createdAt": "2024-01-15T09:30:00Z"
}CustomerInput
objectusernamestringrequiredfirstNamestringlastNamestringemailstring<email>requiredpasswordstring<password>requiredphonestring | null{
"username": "string",
"firstName": "string",
"lastName": "string",
"email": "[email protected]",
"password": "********",
"phone": "string"
}