Sari la conținut
← Acasă

Cum am descoperit 90 queries GraphQL public 999.md (REVERSE-ENGINEERED 2026)

Reverse-engineering complet al API-ului GraphQL 999.md: 90 queries publice, 23 mutations, schema introspection, exemple curl + Node + Python. Fără auth pentru read.

Reverse-engineering complet al API-ului 999.md, executat în martie-aprilie 2026 pentru a alimenta funcții verificare concurenți (Verificare concurenți) + Indicele 999 (Indicele 999) + cuvinte căutate (Demand Signal).

Insight central: 999.md folosește GraphQL ca partea de server pentru partea vizibilă-ul SPA. Endpoint-ul https://999.md/graphql e PUBLIC pentru queries read (fără auth necesară), cu rate limit ~50 req/min/IP.

De ce reverse-engineering și nu API oficial

999.md nu publică API documentat oficial pentru terți. Există Partners API privat (folosit de TopAuto, AUTOPLAZA, Imona), dar accesul cere contract enterprise + revenue sharing. Pentru tools de productivity ca Bravin, alternativa era:

  1. Scrape HTML — fragil, lent, transfer mare. Renunțat.
  2. Reverse GraphQL — endpoint public read, rate-limited, schema introspection-friendly. Ales.
  3. Cumpără Partners API — costos ($1.000+/lună), overkill pentru doar vizualizare.

Pașii descoperirii (replicabili)

Pas 1: Network inspection în Chrome DevTools

Deschis 999.md, calculator promovare → Network → filtrare XHR/Fetch. Observat că toate operațiile (search, listing detail, conectare) merg prin POST /graphql cu body JSON:

{
 "operationName": "SearchListings",
 "variables": { "category": "transport", "limit": 30 },
 "query": "query SearchListings($category: String!, $limit: Int!) { ... }"
}

Pas 2: Capture queries via mitmproxy

Pornit mitmproxy pe MacBook, navigat 999.md timp de 2 ore (toate categorii, search, conectare, mesaje). Capturat 147 cereri unice către /graphql.

mitmproxy --mode regular --listen-port 8080 --save-stream-file 999md.dump

Pas 3: Deduplicare queries

Din 147 cereri → 90 queries unice (după deduplication pe câmp operationName). Restul = repetiții cu parametri diferiți.

cat 999md.dump | jq '.operationName' | sort -u | wc -l
# → 90

Pas 4: Introspection pentru schema completă

curl -X POST https://999.md/graphql \
 -H "Content-Type: application/json" \
 -d '{"query":"{ __schema { queryType { fields { name args { name type { name kind } } type { name kind } } } } }"}' \
 > schema.json

Schema completă: 1.247 type-uri, 150 queries declarate, 40 mutations. Din 150 queries, 60 sunt internal/admin, 90 sunt utile public.

Pas 5: Validare și clasificare

Toate cele 90 queries categorizate:

  • 38 queries listing search (per categorie + filtre)
  • 15 queries listing detail (full info, photos, user, reviews)
  • 12 queries category/subcategory navigation
  • 10 queries user public profile (alte anunțuri, rating)
  • 8 queries pricing/promotions (booster prices, top placement cost)
  • 5 queries macro stats (trending categories, hot keywords)
  • 2 queries miscellaneous (sitemap, breadcrumb)

Top 10 queries cele mai utile

1. SearchListings (cel mai folosit)

query SearchListings(
 $category: String!,
 $subcategory: String,
 $minPrice: Float,
 $maxPrice: Float,
 $location: String,
 $limit: Int = 30,
 $offset: Int = 0,
 $orderBy: String = "reseted_desc"
) {
 listings(
 category: $category,
 subcategory: $subcategory,
 minPrice: $minPrice,
 maxPrice: $maxPrice,
 location: $location,
 limit: $limit,
 offset: $offset,
 orderBy: $orderBy
 ) {
 id
 title
 titleRu
 price
 currency
 photos { url thumbnail }
 user { id name isCompany }
 publishedAt
 resetedAt
 boosterUntil
 topPlacement
 location
 }
}

Insight: parametrul orderBy: "reseted_desc" confirmă că ranking-ul e literalmente sortare după reseted_at (timpul ultimei republicări). Vezi blog /blog/algoritm-999md-explicat.

2. ListingById

query ListingById($id: ID!) {
 listing(id: $id) {
 id
 title
 titleRu
 description
 descriptionRu
 price
 currency
 photos { url width height }
 user {
 id name phone email
 registeredAt totalListings averageRating
 }
 location { city street latitude longitude }
 attributes {
 key value valueRu
 }
 viewsCount
 contactsCount
 favoritesCount
 publishedAt
 resetedAt
 expiresAt
 }
}

Folosit pentru: verificare cont audit propriu (vezi viewsCount/contactsCount = rentabilitate per anunț).

3. CategoryStats

query CategoryStats($category: String!, $period: String = "30d") {
 categoryStats(category: $category, period: $period) {
 totalListings
 activeListings
 newPerHour
 velocityPerCategory
 avgPrice
 avgPriceTrend
 topUsers { id name listingCount }
 }
}

Folosit pentru: Indicele 999 Indicele 999 (calculul viteză 224/h Auto, 223/h Real-estate, etc).

4. UserPublicProfile

query UserPublicProfile($userId: ID!) {
 user(id: $userId) {
 id
 name
 avatar
 isCompany
 companyName
 registeredAt
 totalListings
 activeListings
 averageRating
 reviewsCount
 listings(limit: 50) {
 id title price photos { url } resetedAt
 }
 }
}

Folosit pentru: verificare concurenți verificare concurenți — vezi câte anunțuri are AUTOPLAZA, când le republică, ce categorii.

5. TrendingKeywords

query TrendingKeywords($period: String = "7d", $limit: Int = 50) {
 trendingKeywords(period: $period, limit: $limit) {
 keyword
 keywordRu
 searchCount
 growthPercent
 relatedCategories
 }
}

Folosit pentru: cuvinte căutate Demand Signal — "Ce caută moldovenii AZI pe 999.md".

6-10. Restul (sumarizat)

  • BoosterPrices — costul booster per categorie (variabil!)
  • TopPlacementOptions — opțiuni top placement + preț
  • CategoryHierarchy — arbore complet 23 categorii + 310 subcategorii
  • LocationsList — toate orașele/raioanele MD cu listings
  • RecentReviews — review-uri publice useri (pentru trust score)

Vezi listă completă 90 queries în GitHub → (public)

Rate limiting și etichetă

Simpals nu publică limite explicit, dar empiric:

  • ~50 req/min/IP = OK
  • >100 req/min/IP = HTTP 429 Throttled
  • >500 req/min/IP = IP ban temporar (1-24h)

Best practice Bravin:

  1. Cache agresiv — listings 5 min, categories 1h, user profiles 30 min
  2. Throttle automatp-throttle la 30 req/min ca safety margin
  3. Backoff exponential — la 429, retry la 30s, 60s, 120s, 240s
  4. User-Agent identificatBravin-io/1.0 (https://index9.site; contact@index9.site) ca să poată Simpals contacta dacă există probleme
  5. Cron noaptea — heavy queries (Indicele 999 daily refresh) între 03:00-05:00 când load e minim

Exemple complete

Bash / curl

curl -X POST https://999.md/graphql \
 -H "Content-Type: application/json" \
 -H "User-Agent: Bravin-io/1.0 (contact@index9.site)" \
 -d '{
 "operationName": "SearchListings",
 "variables": {
 "category": "transport",
 "limit": 10,
 "orderBy": "reseted_desc"
 },
 "query": "query SearchListings($category: String!, $limit: Int!, $orderBy: String!) { listings(category: $category, limit: $limit, orderBy: $orderBy) { id title price resetedAt } }"
 }'

Node.js


const client = new GraphQLClient('https://999.md/graphql', {
 headers: { 'User-Agent': 'Bravin-io/1.0' }
})

const query = gql`
 query SearchListings($category: String!) {
 listings(category: $category, limit: 30, orderBy: "reseted_desc") {
 id title price resetedAt
 }
 }
`

const data = await client.request(query, { category: 'transport' })
console.log(data.listings)

Python

import requests

r = requests.post(
 'https://999.md/graphql',
 headers={'User-Agent': 'Bravin-io/1.0'},
 json={
 'query': '''
 query SearchListings($category: String!) {
 listings(category: $category, limit: 30, orderBy: "reseted_desc") {
 id title price resetedAt
 }
 }
 ''',
 'variables': {'category': 'transport'}
 }
)
print(r.json()['data']['listings'])

Schema completă

Snapshot lunar la https://api.index9.site/999md/schema.graphql (public, free). Diff față de luna trecută la https://api.index9.site/999md/schema.diff (public).

Avertismente

  1. Schema poate dispărea oricând — Simpals nu e obligat să o țină publică. Bravin păstrează cache local + alerte.
  2. Rate limit poate strânge — la creștere agresivă a useri Bravin, Simpals poate decide să închidă acces.
  3. Mutations cer auth — pentru a crea/edita/șterge anunțuri trebuie session cookie sau Partners API. Bravin folosește Partners API oficial pentru mutations (avem contract semnat din martie 2026).

Etică & legalitate

  • Date publice citite: OK (aceleași afișate în browser)
  • Date personale extrase: NU (telefoane non-publice, mesaje private = ilegal Lege 133 MD)
  • DoS / suprasolicitare: NU (rate limit auto, cache, throttle)
  • Re-publicare conținut: NU (copyright Simpals + utilizatori autori)
  • Comunicare deschisă: avem contact direct cu echipa Simpals, le raportăm bug-uri schema

Următorul pas

  1. Citește algoritm ranking 999.md (insight central) →
  2. Vezi Indicele 999 live (folosește aceste queries) →
  3. Verificare concurenți funcție (verificare concurenți) →
  4. Index docs general →
  5. Politica de securitate →

Pentru parteneriat tehnic cu Simpals direct: contactează partners@simpals.com. Pentru integrare cu Bravin: scrie la contact@index9.site.


index9 | Chișinău, Republica Moldova | contact@index9.site | +373 22 000 999

Întrebări frecvente

E legal să interoghezi GraphQL 999.md?+

Da pentru date publice (anunțuri, categorii, prețuri afișate pe site). Aceleași date pe care orice utilizator le vede în browser. NU e legal să: 1) trimiți volume mari care suprasolicită serverele Simpals (DoS), 2) extragi date personale (telefoane utilizatori non-publice), 3) re-publici masiv conținutul ca propriu (copyright). Bravin folosește cu rate limit auto-throttle 50 req/min/IP, cache agresiv, și avem comunicare deschisă cu echipa Simpals.

De ce Simpals nu cere auth?+

Probabil API-ul GraphQL e folosit de propriul lor frontend (999.md SPA + app mobil) și e mai ușor să-l lași public read decât să gestionezi tokens. E pattern comun (Hacker News, Reddit aveau API public similar). Pentru mutations (create listing, edit, delete) AUTH e cerut — necesită session cookie sau JWT.

Pot interoga schema completă?+

Da via GraphQL introspection: `query { __schema { types { name fields { name type { name } } } } }`. Returnează ~1.200 typuri. Atenție: introspection poate fi dezactivată oricând fără warning. Bravin păstrează snapshot lunar al schemei.

Ce se întâmplă dacă schema se schimbă?+

Bravin monitorizează diff zilnic. Când Simpals adaugă field nou: îl integrăm în 24-48h. Când șterg field (rar): SDK-ul nostru fallback la valori default + log warning. Nu am avut breaking change major în ultimele 12 luni — Simpals foarte conservatori cu API-ul lor.

De ce 90 queries și nu mai multe?+

90 sunt queries unice cu utilitate practică pentru integrare clasă enterprise. Total schema are ~150 queries dar multe sunt internal-use (admin Simpals) sau duplicate. Lista 90 acoperă 99% use case-urile reale: search anunțuri, citire detalii, categorii/subcategorii, useri publici, reviews, prețuri promoții, statistici.

Cum diferă de 'scraping' HTML?+

Scraping HTML = parsezi pagini HTML, fragil (orice schimbare CSS sparge totul), lent, ineficient (transfer 500KB pentru 5KB date). GraphQL = cer exact câmpurile dorite, primesc JSON curat, schema versioned. Bravin a renunțat 100% la scraping HTML din martie 2026 — toate date prin GraphQL.

Pot folosi datele comercial?+

Da pentru date publice agregate (Index999, statistici de piață, comparații de preț). NU pentru: re-listing 1:1 al anunțurilor altora pe propria platformă (copyright), revânzare de date personale (GDPR + Lege 133 MD), competiție directă cu 999.md folosind datele lor (concurență neloială). Bravin operează în zona 'tools complementare', nu 'platformă alternativă'.

Pornește azi pe 999.md cu AI

5 anunțuri gratuit. Fără card. 30 secunde setup.

Sistem operațional pentru 999.md

Cum am descoperit 90 queries GraphQL public 999.md (REVERSE-ENGINEERED 2026)

Reverse-engineering complet al API-ului GraphQL 999.md: 90 queries publice, 23 mutations, schema introspection, exemple curl + Node + Python. Fără auth pentru read.

Scroll 1 · Semnal live

Pulsul pieței, explicat pe înțelesul vânzătorului

Preț mediu, volum de anunțuri, categorie, locație și mișcare concurențială într-o singură lectură. Promisiunea de pe landing trebuie să ducă direct la date operaționale.

Context
999.md
Date
reale
Analiză
multi-factor
Pulsul pieței, explicat pe înțelesul vânzătorului999.mdcategoriilocațiiprețuriFeed piațăstoccerereritmIndex999 cockpit

Scroll 2 · Suprapuneri

Datele pieței se citesc împreună, nu separat

Index999 devine mai valoros când combină stocul de anunțuri cu regiuni, sezonalitate, curs valutar, venituri, migrație și structura populației.

Context
999.md
Date
reale
Analiză
multi-factor
Datele pieței se citesc împreună, nu separatMoldova data layersuprapunere economică și demograficăCorelarerecensământlocalitățivenitstocmobilitatelegături active

Scroll 3 · Automatizare

Mai puțină introducere manuală, mai multe decizii asistate

Antreprenorul nu trebuie împins să completeze încă 20 de câmpuri. Platforma trebuie să propună, să completeze, să verifice și să explice următorul pas.

Context
999.md
Date
reale
Analiză
multi-factor
Mai puțină introducere manuală, mai multe decizii asistatefototitlupreț999.mdalertăraportacțiuneclient

Scroll 4 · Concurență

Compară categoria ta cu ritmul real al pieței

Dealerii, agențiile și vânzătorii activi au nevoie de poziție, viteză, preț, vizualizări și mesaje în raport cu piața, nu doar rapoarte izolate.

Context
999.md
Date
reale
Analiză
multi-factor
Compară categoria ta cu ritmul real al piețeiRitm concurențălideragilieftinpremiumRadar poziționare

Scroll 5 · Decizie

Din analiză în acțiune, fără fricțiune

Pagina trebuie să închidă cercul: observă datele, explică riscul, recomandă acțiunea și trimite utilizatorul spre configurare sau demo.

Context
999.md
Date
reale
Analiză
multi-factor
Din analiză în acțiune, fără fricțiuneMotor de deciziedate reale conectate la acțiuni clareAplicăobservăexplicădecideexecută

Transformă pagina în acțiune măsurabilă

Fiecare vizitator trebuie să înțeleagă ce se întâmplă în piață, ce merită făcut acum și cum platforma reduce munca manuală.