Shop
5 operations under /v1/shop/agent (GET POST): parameters, status codes, refusal bodies, and the same request in curl, HTTP, Python and TypeScript.
Base URL: https://api.codespar.dev
Every operation below requires a Bearer token. See Authentication.
GET /v1/shop/agent/instruments
https://api.codespar.dev/v1/shop/agent/instrumentsThe calling person's cards, masked
Brand and last four of the CALLING person's active cards, as references an assistant can name; choosing one stays the person's act at Pagar. The list belongs to a verified person: a project API key or an OAuth token carries no person and is refused bearer_token_has_no_person (403), whatever owner says. owner is deprecated and ignored: it no longer selects another person's cards (Shop v0.3). The 403's details say why and what to do, with stable keys: reason: "bearer_has_no_person", list_belongs_to: "authenticated_person", owner_param: "deprecated_ignored" and how_to_list (the person's own session on the dashboard; an MCP session bound to a person by login arrives with Shop v0.3 increment 5). A client holding only a project key has no way to list cards until then.
What an assistant can and cannot do. It proposes a purchase and reads where it stands; it never pays, approves, saves a card or logs in at a store. A verified person presses Pagar on the dashboard and completes what the purchase waits for (the protected card or CVV form, the store login); the purchase then runs through the same executor as the Shop's own chat, at most once at the store. No answer carries a card number, a security code, a cookie or a collect secret. Test projects only in this first delivery; behind SHOP_PURCHASES_ENABLED.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
owner | string | no | Deprecated and ignored (Shop v0.3): the list is always the authenticated person's own; it no longer selects another person's cards. |
Responses
| Status | Body | Description |
|---|---|---|
200 | object | OK |
403 | object | The bearer carries no verified person, or the key does not hold shop:instruments:read. |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
instruments | array of object | yes | — |
curl -X GET https://api.codespar.dev/v1/shop/agent/instruments \
-H "Authorization: Bearer $CODESPAR_API_KEY"GET /v1/shop/agent/instruments HTTP/1.1
Host: api.codespar.dev
Authorization: Bearer $CODESPAR_API_KEYimport os
import requests
res = requests.get(
"https://api.codespar.dev/v1/shop/agent/instruments",
headers={"Authorization": f"Bearer {os.environ['CODESPAR_API_KEY']}"},
)
res.raise_for_status()
data = res.json()const res = await fetch("https://api.codespar.dev/v1/shop/agent/instruments", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.CODESPAR_API_KEY}`,
},
});
const data = await res.json();const r = await cs.api.response("get", "/v1/shop/agent/instruments");
// r.status is one of the documented statuses (200, 403),
// each with its own body shape in r.data; nothing here throws on 403.
if (r.ok) {
console.log(r.data);
}{
"instruments": [
{
"id": "obj_0000000000000000",
"kind": "byo_card",
"brand": "string",
"last4": "string",
"status": "active"
}
]
}POST /v1/shop/agent/purchases
https://api.codespar.dev/v1/shop/agent/purchasesPropose a purchase at a supported store (never an order)
Scope shop:purchases:write. The store, its origin and its prices come from the server's registry and the store's own catalog, never from the request. The same agent_id and idempotency_key with the same intent answers the same purchase (idempotent_replay: true). Instead of merchant and items, offer_id (with an optional quantity) names an offer of this key's research: the store and the SKU come from it and the store quotes it again; a moved price or shipping is offer_stale (409) and an offer that is a comparison is offer_not_purchasable (409), with nothing proposed.
What an assistant can and cannot do. It proposes a purchase and reads where it stands; it never pays, approves, saves a card or logs in at a store. A verified person presses Pagar on the dashboard and completes what the purchase waits for (the protected card or CVV form, the store login); the purchase then runs through the same executor as the Shop's own chat, at most once at the store. No answer carries a card number, a security code, a cookie or a collect secret. Test projects only in this first delivery; behind SHOP_PURCHASES_ENABLED.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
agent_id | string | yes | — |
idempotency_key | string | yes | — |
items | array of object | no | The cart by SKU. Required with merchant; absent with offer_id. |
merchant | string | no | The store id. Required with items; absent with offer_id. |
offer_id | string | no | Shop v0.3: an offer of this key's research (POST /v1/shop/agent/research). The store and the SKU come from it; the store quotes it again. |
payment_method | "card" | "store_on_file" | no | — |
quantity | integer | no | With offer_id: how many units (default 1). |
Responses
| Status | Body | Description |
|---|---|---|
200 | object | OK |
201 | object | OK |
400 | object | The body did not match the schema. |
403 | object | The key does not hold shop:purchases:write. |
404 | object | The offer is not in this key's research. |
409 | object | No mandate permits the store, the project is not Test, or the offer moved or cannot be bought here. |
422 | object | The agent, the store, the rail or an item is not one that can be bought. |
503 | object | Shop purchases are off on this deployment. |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
idempotent_replay | boolean | yes | — |
proposal | object,null | yes | The proposal card as the dashboard shows it. |
purchase | object | yes | — |
curl -X POST https://api.codespar.dev/v1/shop/agent/purchases \
-H "Authorization: Bearer $CODESPAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "agt_0000000000000000",
"merchant": "string",
"items": [
{
"sku_id": "sku_0000000000000000",
"quantity": 0
}
],
"offer_id": "offer_0000000000000000",
"quantity": 0,
"payment_method": "card",
"idempotency_key": "string"
}'POST /v1/shop/agent/purchases HTTP/1.1
Host: api.codespar.dev
Authorization: Bearer $CODESPAR_API_KEY
Content-Type: application/json
{
"agent_id": "agt_0000000000000000",
"merchant": "string",
"items": [
{
"sku_id": "sku_0000000000000000",
"quantity": 0
}
],
"offer_id": "offer_0000000000000000",
"quantity": 0,
"payment_method": "card",
"idempotency_key": "string"
}import os
import requests
res = requests.post(
"https://api.codespar.dev/v1/shop/agent/purchases",
headers={"Authorization": f"Bearer {os.environ['CODESPAR_API_KEY']}"},
json={
"agent_id": "agt_0000000000000000",
"merchant": "string",
"items": [
{
"sku_id": "sku_0000000000000000",
"quantity": 0
}
],
"offer_id": "offer_0000000000000000",
"quantity": 0,
"payment_method": "card",
"idempotency_key": "string"
},
)
res.raise_for_status()
data = res.json()const res = await fetch("https://api.codespar.dev/v1/shop/agent/purchases", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CODESPAR_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"agent_id": "agt_0000000000000000",
"merchant": "string",
"items": [
{
"sku_id": "sku_0000000000000000",
"quantity": 0
}
],
"offer_id": "offer_0000000000000000",
"quantity": 0,
"payment_method": "card",
"idempotency_key": "string"
}),
});
const data = await res.json();const r = await cs.api.response("post", "/v1/shop/agent/purchases", {
body: {
agent_id: "agt_0000000000000000",
merchant: "string",
items: [
{
sku_id: "sku_0000000000000000",
quantity: 0
}
],
offer_id: "offer_0000000000000000",
quantity: 0,
payment_method: "card",
idempotency_key: "string"
}
});
// r.status is one of the documented statuses (200, 403, 422),
// each with its own body shape in r.data; nothing here throws on 403.
if (r.ok) {
console.log(r.data);
}{
"purchase": {
"id": "obj_0000000000000000",
"kind": "purchase",
"state": "drafted",
"run_state": "ready",
"awaiting": {
"reason": "instrument"
},
"merchant": {
"id": "obj_0000000000000000",
"name": "Example"
},
"items": [
{
"sku_id": "sku_0000000000000000",
"name": "Example",
"quantity": 0,
"unit_price_minor": 1
}
],
"total_minor": 1,
"currency": "BRL",
"payment_method": "card",
"order": {
"id": "obj_0000000000000000",
"status": "string",
"amount_minor": 1000
},
"receipt": {
"funding_origin": "external_card",
"wallet_debit": false
},
"failure": {
"code": "string"
},
"next_action": "string"
},
"proposal": {},
"idempotent_replay": true
}GET /v1/shop/agent/purchases/{id}
https://api.codespar.dev/v1/shop/agent/purchases/{id}Where a purchase stands
Scope shop:purchases:read. References and states only: the order the store answered, a receipt marked as external (no Wallet debit), what it waits for.
What an assistant can and cannot do. It proposes a purchase and reads where it stands; it never pays, approves, saves a card or logs in at a store. A verified person presses Pagar on the dashboard and completes what the purchase waits for (the protected card or CVV form, the store login); the purchase then runs through the same executor as the Shop's own chat, at most once at the store. No answer carries a card number, a security code, a cookie or a collect secret. Test projects only in this first delivery; behind SHOP_PURCHASES_ENABLED.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | yes | The purchase proposal id (prp_...), from POST /v1/shop/agent/purchases. |
Responses
| Status | Body | Description |
|---|---|---|
200 | object | OK |
403 | object | The key does not hold shop:purchases:read. |
404 | object | Not Found |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
purchase | object | yes | — |
curl -X GET https://api.codespar.dev/v1/shop/agent/purchases/{id} \
-H "Authorization: Bearer $CODESPAR_API_KEY"GET /v1/shop/agent/purchases/{id} HTTP/1.1
Host: api.codespar.dev
Authorization: Bearer $CODESPAR_API_KEYimport os
import requests
res = requests.get(
"https://api.codespar.dev/v1/shop/agent/purchases/{id}",
headers={"Authorization": f"Bearer {os.environ['CODESPAR_API_KEY']}"},
)
res.raise_for_status()
data = res.json()const res = await fetch("https://api.codespar.dev/v1/shop/agent/purchases/{id}", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.CODESPAR_API_KEY}`,
},
});
const data = await res.json();const r = await cs.api.response("get", "/v1/shop/agent/purchases/{id}", {
path: {
id: "purchase_0000000000000000"
}
});
// r.status is one of the documented statuses (200, 403),
// each with its own body shape in r.data; nothing here throws on 403.
if (r.ok) {
console.log(r.data);
}{
"purchase": {
"id": "obj_0000000000000000",
"kind": "purchase",
"state": "drafted",
"run_state": "ready",
"awaiting": {
"reason": "instrument"
},
"merchant": {
"id": "obj_0000000000000000",
"name": "Example"
},
"items": [
{
"sku_id": "sku_0000000000000000",
"name": "Example",
"quantity": 0,
"unit_price_minor": 1
}
],
"total_minor": 1,
"currency": "BRL",
"payment_method": "card",
"order": {
"id": "obj_0000000000000000",
"status": "string",
"amount_minor": 1000
},
"receipt": {
"funding_origin": "external_card",
"wallet_debit": false
},
"failure": {
"code": "string"
},
"next_action": "string"
}
}POST /v1/shop/agent/research
https://api.codespar.dev/v1/shop/agent/researchResearch a pedido aberto: offers compared, one recommendation
Scope shop:purchases:write (a research proposes nothing). The server consults the sources (registry, the stores the Shop can buy at; vtex and meli, comparison only; default registry in Test, vtex and meli in Live), records every offer with its source and observed_at, computes each total (price plus shipping), and recommends one principal with reason codes and at most three alternatives. lowest_price states the lowest total as "menor preço entre as ofertas consultadas", with the count and window it covers. decisive_unknowns lists the only questions that would change the principal. The research belongs to the project: a key carries no person, and never reaches a person's research. An offer older than 15 minutes is stale: a purchase from it is quoted again, as every purchase from an offer is.
What an assistant can and cannot do. It proposes a purchase and reads where it stands; it never pays, approves, saves a card or logs in at a store. A verified person presses Pagar on the dashboard and completes what the purchase waits for (the protected card or CVV form, the store login); the purchase then runs through the same executor as the Shop's own chat, at most once at the store. No answer carries a card number, a security code, a cookie or a collect secret. Test projects only in this first delivery; behind SHOP_PURCHASES_ENABLED.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
criteria | object | no | — |
query | string | yes | The pedido aberto, as the person said it (e.g. "fone bluetooth"). |
Responses
| Status | Body | Description |
|---|---|---|
201 | object | OK |
400 | object | The body did not match the schema. |
403 | object | The key does not hold shop:purchases:write. |
409 | object | No source of the asked groups exists in this environment. |
503 | object | No source answered, or Shop purchases are off on this deployment. |
Response 201
| Field | Type | Required | Description |
|---|---|---|---|
research | object | yes | The research as CONTRATO-I2 describes it: offers, recommendation, sources. |
curl -X POST https://api.codespar.dev/v1/shop/agent/research \
-H "Authorization: Bearer $CODESPAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": "string",
"criteria": {
"priority": "total",
"max_total_minor": 1,
"sources": [
"registry"
],
"limit": 1000
}
}'POST /v1/shop/agent/research HTTP/1.1
Host: api.codespar.dev
Authorization: Bearer $CODESPAR_API_KEY
Content-Type: application/json
{
"query": "string",
"criteria": {
"priority": "total",
"max_total_minor": 1,
"sources": [
"registry"
],
"limit": 1000
}
}import os
import requests
res = requests.post(
"https://api.codespar.dev/v1/shop/agent/research",
headers={"Authorization": f"Bearer {os.environ['CODESPAR_API_KEY']}"},
json={
"query": "string",
"criteria": {
"priority": "total",
"max_total_minor": 1,
"sources": [
"registry"
],
"limit": 1000
}
},
)
res.raise_for_status()
data = res.json()const res = await fetch("https://api.codespar.dev/v1/shop/agent/research", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CODESPAR_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"query": "string",
"criteria": {
"priority": "total",
"max_total_minor": 1,
"sources": [
"registry"
],
"limit": 1000
}
}),
});
const data = await res.json();const r = await cs.api.response("post", "/v1/shop/agent/research", {
body: {
query: "string",
criteria: {
priority: "total",
max_total_minor: 1,
sources: [
"registry"
],
limit: 1000
}
}
});
// r.status is one of the documented statuses (200, 403),
// each with its own body shape in r.data; nothing here throws on 403.
if (r.ok) {
console.log(r.data);
}{
"research": {}
}GET /v1/shop/agent/research/{id}
https://api.codespar.dev/v1/shop/agent/research/{id}Read a research back
Scope shop:purchases:read. The research this project's keys ran, with each offer's stale computed at the time of the answer.
What an assistant can and cannot do. It proposes a purchase and reads where it stands; it never pays, approves, saves a card or logs in at a store. A verified person presses Pagar on the dashboard and completes what the purchase waits for (the protected card or CVV form, the store login); the purchase then runs through the same executor as the Shop's own chat, at most once at the store. No answer carries a card number, a security code, a cookie or a collect secret. Test projects only in this first delivery; behind SHOP_PURCHASES_ENABLED.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | yes | The research id (srr_...), from POST /v1/shop/agent/research. |
Responses
| Status | Body | Description |
|---|---|---|
200 | object | OK |
403 | object | The key does not hold shop:purchases:read. |
404 | object | Not Found |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
research | object | yes | The research as CONTRATO-I2 describes it: offers, recommendation, sources. |
curl -X GET https://api.codespar.dev/v1/shop/agent/research/{id} \
-H "Authorization: Bearer $CODESPAR_API_KEY"GET /v1/shop/agent/research/{id} HTTP/1.1
Host: api.codespar.dev
Authorization: Bearer $CODESPAR_API_KEYimport os
import requests
res = requests.get(
"https://api.codespar.dev/v1/shop/agent/research/{id}",
headers={"Authorization": f"Bearer {os.environ['CODESPAR_API_KEY']}"},
)
res.raise_for_status()
data = res.json()const res = await fetch("https://api.codespar.dev/v1/shop/agent/research/{id}", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.CODESPAR_API_KEY}`,
},
});
const data = await res.json();const r = await cs.api.response("get", "/v1/shop/agent/research/{id}", {
path: {
id: "research_0000000000000000"
}
});
// r.status is one of the documented statuses (200, 403),
// each with its own body shape in r.data; nothing here throws on 403.
if (r.ok) {
console.log(r.data);
}{
"research": {}
}