Calling the API
AI agents: read /llms.txt; add .md to any page URL. This page as Markdown: /concepts/calling-the-api.md. Index of every page and the rules for every call: /llms.txt. Guides and concepts in one file: /llms-full.txt. OpenAPI: /openapi.json.
The rest of these docs show requests with curl. This page shows the same pattern in three languages: one helper that every call goes through, a read, and a write.
The helper does five things on every request:
- Sends the key as
Authorization: Bearer YOUR_API_KEY. - Sends JSON with
Content-Type: application/json. - Asks for JSON with
Accept: application/json, so even a wrong path answers JSON. - Asks for exact amounts with
X-Yoprint-Decimal-Format: exact-v1, so values that cannot be represented as exact JSON numbers (such as fractional thousandths or large integers) return as strings (see Money and quantities). - Treats an answer as failed when its status is
4xxor5xxor its body has"success": false, and raises an error that carries the status and the body (see Errors).
The helper only parses JSON. For a file download, such as a CSV export or a PDF, read the response body as bytes instead.
Keep the key in an environment variable, here YOPRINT_API_KEY, never in the code.
The helper
Section titled “The helper”Node.js 18 or later, or any runtime with fetch.
const BASE = 'https://secure.yoprint.com';const TEAM = 'your-team';
export async function yoprint(method, path, body) { const response = await fetch(`${BASE}${path.replace('{team_slug}', TEAM)}`, { method, headers: { Authorization: `Bearer ${process.env.YOPRINT_API_KEY}`, 'Content-Type': 'application/json', Accept: 'application/json', 'X-Yoprint-Decimal-Format': 'exact-v1', }, body: body === undefined ? undefined : JSON.stringify(body), }); if (response.status === 204) return null; // one delete answers with no body const json = await response.json().catch(() => null); if (!response.ok || json === null || json.success === false) { const error = new Error(`YoPrint ${response.status}: ${json?.error?.code ?? json?.message ?? 'error'}`); error.status = response.status; error.body = json; throw error; } return json;}Python 3 with requests.
import osimport requests
BASE = "https://secure.yoprint.com"TEAM = "your-team"
session = requests.Session()session.headers.update({ "Authorization": f"Bearer {os.environ['YOPRINT_API_KEY']}", "Content-Type": "application/json", "Accept": "application/json", "X-Yoprint-Decimal-Format": "exact-v1",})
class YoPrintError(Exception): def __init__(self, status, body): super().__init__(f"YoPrint {status}") self.status = status self.body = body
def yoprint(method, path, body=None): response = session.request( method, BASE + path.replace("{team_slug}", TEAM), json=body, timeout=30 ) if response.status_code == 204: # one delete answers with no body return None try: data = response.json() except ValueError: data = None if not response.ok or data is None or (isinstance(data, dict) and data.get("success") is False): raise YoPrintError(response.status_code, data) return dataPHP 8 with Guzzle 7.
<?phpuse GuzzleHttp\Client;use GuzzleHttp\Exception\RequestException;
const TEAM = 'your-team';
$client = new Client([ 'base_uri' => 'https://secure.yoprint.com', 'timeout' => 30, 'headers' => [ 'Authorization' => 'Bearer ' . getenv('YOPRINT_API_KEY'), 'Content-Type' => 'application/json', 'Accept' => 'application/json', 'X-Yoprint-Decimal-Format' => 'exact-v1', ],]);
function yoprint(Client $client, string $method, string $path, ?array $body = null): ?array{ $options = $body === null ? [] : ['json' => $body]; try { $response = $client->request($method, str_replace('{team_slug}', TEAM, $path), $options); } catch (RequestException $e) { $status = $e->hasResponse() ? $e->getResponse()->getStatusCode() : 0; $error = $e->hasResponse() ? (string) $e->getResponse()->getBody() : $e->getMessage(); throw new RuntimeException("YoPrint {$status}: {$error}", $status, $e); } if ($response->getStatusCode() === 204) { return null; // one delete answers with no body } $json = json_decode((string) $response->getBody(), true); if (!is_array($json) || (array_key_exists('success', $json) && $json['success'] === false)) { $status = $response->getStatusCode(); throw new RuntimeException("YoPrint {$status}: " . (string) $response->getBody(), $status); } return $json;}A read: list customers
Section titled “A read: list customers”/v1/api/store/{team_slug}/customer
const page = await yoprint('GET', '/v1/api/store/{team_slug}/customer?page=1');for (const customer of page.data) { console.log(customer.id, customer.name);}console.log(`Page ${page.pagination.currentPage} of ${page.pagination.totalPages}`);page = yoprint("GET", "/v1/api/store/{team_slug}/customer?page=1")for customer in page["data"]: print(customer["id"], customer["name"])print(f"Page {page['pagination']['currentPage']} of {page['pagination']['totalPages']}")$page = yoprint($client, 'GET', '/v1/api/store/{team_slug}/customer?page=1');foreach ($page['data'] as $customer) { echo $customer['id'], ' ', $customer['name'], PHP_EOL;}echo "Page {$page['pagination']['currentPage']} of {$page['pagination']['totalPages']}", PHP_EOL;A write: create a customer
Section titled “A write: create a customer”/v1/api/store/{team_slug}/customer
A create isn’t safe to repeat: sending it twice makes two customers. The examples don’t retry it. See Retries and duplicates.
try { const created = await yoprint('POST', '/v1/api/store/{team_slug}/customer', { customer: { name: 'Northwind Apparel', tax_exempt: false }, contact: [ { first_name: 'Alex', last_name: 'Rivera', email: 'alex@example.com', send_invoice: true, is_primary: true }, ], }); console.log('Created', created.data.id);} catch (error) { if (error.status === 422) { console.error('Fix these fields:', error.body?.error?.fields); } else { throw error; }}try: created = yoprint("POST", "/v1/api/store/{team_slug}/customer", { "customer": {"name": "Northwind Apparel", "tax_exempt": False}, "contact": [{ "first_name": "Alex", "last_name": "Rivera", "email": "alex@example.com", "send_invoice": True, "is_primary": True, }], }) print("Created", created["data"]["id"])except YoPrintError as error: if error.status == 422: print("Fix these fields:", (error.body or {}).get("error", {}).get("fields")) else: raisetry { $created = yoprint($client, 'POST', '/v1/api/store/{team_slug}/customer', [ 'customer' => ['name' => 'Northwind Apparel', 'tax_exempt' => false], 'contact' => [[ 'first_name' => 'Alex', 'last_name' => 'Rivera', 'email' => 'alex@example.com', 'send_invoice' => true, 'is_primary' => true, ]], ]); echo 'Created ', $created['data']['id'], PHP_EOL;} catch (RuntimeException $e) { if ($e->getCode() === 422) { echo 'Fix the request: ', $e->getMessage(), PHP_EOL; } else { throw $e; }}Check results that aren’t errors
Section titled “Check results that aren’t errors”A few operations answer 200 without doing what you asked. Publishing an order is the main one: check data.valid.
const published = await yoprint('PATCH', '/v2/api/store/{team_slug}/v2/sales_order/V4keXwwxMQyXw7/publish');if (!published.data.valid) { throw new Error(`Not published: ${JSON.stringify(published.data.validation)}`);}See Errors for the others.
Before you go further
Section titled “Before you go further”- Read Errors to handle each status properly.
- Read Pagination before you read whole lists.
- Read What a write also does before you automate changes.
