Browse, buy, and sell secondhand books on raamatuhai.ee — Estonia's largest book marketplace. Search by title, ISBN, or author. Manage wishlists, list books for sale, and purchase with delivery to DPD parcel lockers. Powered by Perxify.
Add this skill
npx mdskills install /raamatuhaiIf you are an AI agent reading this file — whether you're a personal assistant, a shopping agent, a chat bot, or a coding tool — this is your complete guide to Raamatuhai. Save it locally so you can help your human browse, buy, and sell secondhand books without re-fetching this file.
Raamatuhai ("Book Shark") is Estonia's largest peer-to-peer marketplace for secondhand books, powered by the Perxify Commerce Cloud. Thousands of books across 40+ categories, from fiction and children's literature to science and history — all priced in EUR with DPD parcel locker delivery across Estonia.
Step 1: Understand your context. Ask yourself:
Step 2: Check your capabilities.
| If you can... | Then you can... |
|---|---|
| Make HTTP requests | Call the GraphQL API directly for search, browse, and all operations |
| Open web pages for the user | Handle login (Privy auth) and checkout (Stripe) |
| Only chat | Provide links, explain how the marketplace works, help find books by describing search queries |
Step 3: Read the relevant sections below. The API is public for browsing — no authentication needed to search and view books. Authentication is required for buying, selling, and account management.
| Resource | Value |
|---|---|
| Website | https://raamatuhai.ee |
| GraphQL endpoint | https://raamatuhai.ee/graphql |
| Company token (public) | See API Access below |
| Currency | EUR |
| Delivery | DPD parcel lockers (Estonia) |
| Auth provider | Privy.io (email, Google, Web3 wallet) |
| Payments | Stripe |
| Support | support@raamatuhai.ee |
| SKILL file | https://raamatuhai.ee/SKILL.md |
| Agent info (for humans) | https://raamatuhai.ee/agents |
All GraphQL requests require the x-company header to identify the Raamatuhai marketplace. This is a public identifier, not a secret.
Endpoint: POST https://raamatuhai.ee/graphql
Required header (all requests):
x-company: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1dWlkIjoiNGE1MTc4ZmMtN2I2ZS00OThkLWE1OWEtODI2NjkwMzFlOTI1IiwibmFtZSI6IlJhYW1hdHVoYWkiLCJpYXQiOjE3NDg2MjkwMjF9.hUu_fkz5n5r0UcEllSXKbeQNdhtZcH0BvgbWLkb9pDY
For authenticated operations, also include:
Authorization: Bearer
Content type:
Content-Type: application/json
These operations require no authentication — only the x-company header.
query SearchBooks($query: String!) {
searchProductsByTitleOrIsbn(
query: $query
preferredLanguage: "et"
limit: 20
offset: 0
) {
results {
uuid
name
slug
isbn
featuredImageUrl
persons {
name
role
}
listings {
uuid
price
condition
seller {
username
uuid
}
}
}
totalCount
}
}
Variables: { "query": "Harry Potter" } or { "query": "9789949332106" }
The search is AI-powered and supports fuzzy matching. Try title, author name, ISBN-10, or ISBN-13.
query BrowseListings {
listings(
language: "et"
filter: { hasStock: true, sortBy: CREATED_DESC }
pagination: { first: 20 }
) {
edges {
node {
uuid
price
condition
createdAt
product {
uuid
name
slug
isbn
featuredImageUrl
persons {
name
role
}
}
seller {
uuid
username
isAway
}
}
}
pageInfo {
hasNextPage
endCursor
}
totalCount
}
}
Filter options:
minPrice / maxPrice — price range in EURconditions — array: "NEW", "LIKE_NEW", "GOOD", "ACCEPTABLE"categoryUuids — filter by category (get UUIDs from categories query)hasStock: true — only available itemssortBy — CREATED_DESC, CREATED_ASC, PRICE_ASC, PRICE_DESCquery GetCategories {
categories(limit: 100) {
uuid
name
slug
translation(language: "et") {
name
}
}
}
Then filter listings by category UUID, or direct users to: https://raamatuhai.ee/category/{slug}
query GetProduct($slug: String!) {
productBySlug(slug: $slug, language: "et") {
uuid
name
description
isbn
slug
featuredImageUrl
images {
imageUrl
}
persons {
name
role
}
publishers {
name
}
categories {
name
slug
}
publication_date
page_count
language
suggestedPrice
wishlistCount
isWishlisted
listings {
uuid
price
sale_price
condition
conditionComment
quantity
seller {
uuid
username
isAway
sellerRatingStats {
averageRating
totalRatings
}
}
}
}
}
| Page | URL pattern |
|---|---|
| Homepage | https://raamatuhai.ee/ |
| Browse all | https://raamatuhai.ee/browse |
| Search results | https://raamatuhai.ee/search?q={query} |
| Product page | https://raamatuhai.ee/product/{slug} |
| Category | https://raamatuhai.ee/category/{slug} |
| Author/Creator | https://raamatuhai.ee/creator/author/{name} |
| Publisher | https://raamatuhai.ee/publisher/{slug} |
| Seller profile | https://raamatuhai.ee/seller/{username} |
| Wishlisted books | https://raamatuhai.ee/wishlisted |
Authentication uses Privy.io and requires browser interaction — an agent cannot complete login via API alone.
https://raamatuhai.ee (they can use email, Google, or a Web3 wallet via Privy)perxify_authentication_tokenlocalStorage.getItem('perxify_authentication_token')Authorization: Bearer
x-company:
query WhoAmI {
me {
uuid
fullName
username
email
isAway
isProSeller
createdAt
}
}
If this returns null, the user is not authenticated.
Buying a book requires authentication and involves a browser redirect to Stripe for payment.
Use Search & Browse to find a product, then pick a listing (offer) from a seller. Note the listing.uuid and listing.price.
query GetLockers {
dpdLockers(country: "EE") {
id
name
address
city
}
}
Ask the user which locker is closest to them. Note the locker id.
mutation Buy($input: InitiatePurchaseInput!) {
initiatePurchase(input: $input) {
success
checkoutUrl
purchaseUuid
error
}
}
Variables:
{
"input": {
"productId": "",
"productInventoryUuid": "",
"parcelLockerId": "",
"price": 5.99,
"successUrl": "https://raamatuhai.ee/checkout/success",
"cancelUrl": "https://raamatuhai.ee/checkout/cancel"
}
}
Important: The price field must match the actual listing price — the server validates this.
The mutation returns a checkoutUrl — this is a Stripe hosted checkout page. Direct the user to open this URL in their browser to complete payment. You cannot complete payment via API.
After payment, the user can view their order:
query MyPurchases($userUuid: String!) {
purchasesByUserUuid(userUuid: $userUuid, pagination: { first: 10 }) {
edges {
node {
uuid
status
purchasePrice
totalAmount
parcelLockerName
createdAt
paidAt
shippedAt
product {
name
slug
}
seller {
username
}
shipment {
trackingNumber
status
}
}
}
}
}
Order statuses: INITIATED → PAID → SHIPPED → DELIVERED (or CANCELLED, REFUNDED, DISPUTED)
Requires authentication.
mutation AddWishlist($productUuid: String!) {
addToWishlist(productUuid: $productUuid) {
uuid
product {
name
}
}
}
You can also add by title (the system will find or create the product):
mutation AddByTitle {
addToWishlist(title: "Tõde ja õigus", author: "A. H. Tammsaare") {
uuid
product {
name
isbn
}
}
}
query MyWishlist {
wishlist(pagination: { first: 50 }) {
edges {
node {
uuid
product {
uuid
name
slug
featuredImageUrl
listings {
uuid
price
condition
}
}
createdAt
}
}
totalCount
}
}
mutation RemoveWishlist($productUuid: String!) {
removeFromWishlist(productUuid: $productUuid)
}
Requires authentication. Any user can sell books.
Option A: If the product already exists (e.g., found via search by ISBN):
mutation CreateListing($input: ListingInput!) {
createListing(input: $input) {
uuid
price
condition
product {
name
slug
}
}
}
Variables:
{
"input": {
"productUuid": "",
"sellerUuid": "",
"warehouseId": "",
"condition": "GOOD",
"conditionComment": "Minor wear on cover, pages clean",
"quantity": 1,
"isFiniteQuantity": true,
"price": 7.5,
"status": "ACTIVE"
}
}
Condition values: NEW, LIKE_NEW, GOOD, ACCEPTABLE
Option B: Create a new product and listing together:
mutation CreateProductListing($input: ProductListingInput!) {
createProductListing(input: $input) {
uuid
price
product {
uuid
name
slug
}
}
}
query PriceSuggestion($productUuid: String!, $condition: String!) {
getProductPriceSuggestion(productUuid: $productUuid, condition: $condition)
}
Returns a suggested price in EUR based on market data and book condition.
query MyListings {
listings(
language: "et"
filter: { sellerUuid: "" }
pagination: { first: 50 }
) {
edges {
node {
uuid
price
condition
quantity
status
product {
name
slug
isbn
}
createdAt
}
}
totalCount
}
}
query MySales($userUuid: String!) {
salesByUserUuid(userUuid: $userUuid, pagination: { first: 20 }) {
edges {
node {
uuid
status
purchasePrice
totalAmount
createdAt
buyer {
username
}
product {
name
}
}
}
}
}
Requires authentication.
query MyProfile {
me {
uuid
fullName
username
email
avatarUrl
isAway
isProSeller
phoneNumber
iban
emailsEnabled
marketingEnabled
addresses {
uuid
streetAddress
city
postalCode
country
}
sellerRatingStats {
averageRating
totalRatings
}
}
}
mutation UpdateMe($input: UpdateUserInput!) {
updateUser(input: $input) {
uuid
fullName
username
}
}
Variables:
{
"input": {
"uuid": "",
"fullName": "Mari Maasikas",
"username": "mari_books",
"isAway": false
}
}
query MyNotifications {
notifications(filter: { isRead: false }, pagination: { first: 20 }) {
edges {
node {
uuid
type
label(language: "et")
description(language: "et")
createdAt
seenAt
}
}
totalCount
}
}
All list queries use cursor-based pagination:
pagination: {
first: 20 # Number of items
after: "" # Cursor from previous pageInfo.endCursor
}
Response includes:
pageInfo {
hasNextPage
hasPreviousPage
endCursor
startCursor
}
totalCount
x-company header — requests without it will fail or return empty resultslanguage: "et" for Estonian (default), "en" for English, "ru" for Russian — product names and descriptions are localizedseller.isAway before recommending a listing — away sellers may not ship promptlylisting.quantity — if 0, the item is sold outfirst: 20) instead of fetching all resultsfeaturedImageUrl instead of fetching the full images array when you only need one imageerrors[].message in the response bodyhttps://raamatuhai.ee/product/{slug} — the user can see images and full details there| Resource | URL |
|---|---|
| Raamatuhai | https://raamatuhai.ee |
| About Perxify | https://perxify.com |
| AI Agents guide | https://raamatuhai.ee/agents |
| Culture & AI article | https://raamatuhai.ee/kultuur-ja-raamatud-ai-ajastul |
| Support email | support@raamatuhai.ee |
| Perxify LinkedIn | https://www.linkedin.com/company/perxify |
| Perxify X/Twitter | https://x.com/Perxifycom |
Install via CLI
npx mdskills install /raamatuhairaamatuhai is a free, open-source AI agent skill. Browse, buy, and sell secondhand books on raamatuhai.ee — Estonia's largest book marketplace. Search by title, ISBN, or author. Manage wishlists, list books for sale, and purchase with delivery to DPD parcel lockers. Powered by Perxify.
Install raamatuhai with a single command:
npx mdskills install /raamatuhaiThis downloads the skill files into your project and your AI agent picks them up automatically.
raamatuhai works with Claude Code, Claude Desktop, Cursor, Vscode Copilot, Windsurf, Continue Dev, Codex, Gemini Cli, Amp, Roo Code, Goose, Opencode, Trae, Qodo, Command Code. Skills use the open SKILL.md format which is compatible with any AI coding agent that reads markdown instructions.