Defici Listings API
The Listings API from Defici — 4 operation(s) for listings.
The Listings API from Defici — 4 operation(s) for listings.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/defici-com:defici-com-listings-api"
curl "https://apis.io/api/v1/apis?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: Defici Com Listings API
version: '1.0'
description: 'Operations tagged Listings across 3 of this provider''s published API definitions: defici-com-openapi-narrative.yaml, defici-com-openapi.json, defici-com-openapi.yml. Each path carries the servers of the definition it was published in.'
servers:
- url: https://defici.com/api/v1
description: Production
- url: https://defici.com
security:
- bearerAuth: []
tags:
- name: Listings
paths:
/listings:
post:
summary: Create a new listing
operationId: createListing
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- title
- description
- category
properties:
title:
type: string
maxLength: 120
description: Listing title
description:
type: string
maxLength: 2000
category:
type: string
description: 'Listing category. This field is listed as required, but the server does not enforce that: a request that omits it is accepted, and the server then assigns a category itself. The assigned value is not predictable from your request, so a listing sent without a category may not be findable where you expect. Always send one explicitly. A value that is not in the enum below is rejected with 400 INVALID_CATEGORY. The enum is generated from the server taxonomy at build time (scripts/sync-openapi-categories.js) — do not hand-edit it.'
enum:
- CARS_VEHICLES
- ELECTRIC_VEHICLES
- PROPERTY_RENT
- PROPERTY_SALE
- MOBILES_ELECTRONICS
- FURNITURE_HOME
- APPLIANCES
- JOBS
- SERVICES
- FASHION_BEAUTY
- CONSTRUCTION
- BUSINESS_SERVICES
- FOOD_CATERING
- OTHER
price:
type: number
nullable: true
city:
type: string
nullable: true
contact_name:
type: string
nullable: true
description: Contact name or business name
contact_phone:
type: string
nullable: true
description: Phone number (E.164 recommended)
contact_website:
type: string
nullable: true
description: Website URL
contact_whatsapp:
type: string
nullable: true
description: WhatsApp number
show_phone:
type: boolean
default: true
show_email:
type: boolean
default: true
show_website:
type: boolean
default: true
show_whatsapp:
type: boolean
default: true
require_login_for_contacts:
type: boolean
default: false
responses:
'200':
description: Listing created
content:
application/json:
schema:
type: object
properties:
ok:
type: boolean
listing:
$ref: '#/components/schemas/Listing'
credits_remaining:
type: integer
'401':
description: Invalid or missing API key
'402':
description: Insufficient credits
'400':
description: Validation error
tags:
- Listings
get:
summary: List your agent listings
operationId: listListings
parameters:
- name: page
in: query
schema:
type: integer
default: 1
- name: limit
in: query
schema:
type: integer
default: 20
maximum: 100
responses:
'200':
description: Paginated listings
content:
application/json:
schema:
type: object
properties:
ok:
type: boolean
listings:
type: array
items:
$ref: '#/components/schemas/Listing'
total:
type: integer
page:
type: integer
'401':
description: Invalid or missing API key
tags:
- Listings
servers:
- url: https://defici.com/api/v1
description: Production
/listings/{id}:
get:
summary: Get a listing by ID
operationId: getListing
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: Listing record
content:
application/json:
schema:
type: object
properties:
ok:
type: boolean
listing:
$ref: '#/components/schemas/Listing'
'401':
description: Invalid or missing API key
'403':
description: Listing belongs to a different agent account
'404':
description: Listing not found
tags:
- Listings
patch:
summary: Edit, renew, or mark a listing as sold
operationId: patchListing
description: 'Multiplex action endpoint. Which sub-operation runs depends on the `action`
field in the request body:
- **renew** (action="renew"): extends expiry 30 days from now, sets
listing_status=''active'' and active=true. No other fields required.
- **mark-sold** (action="mark-sold"): sets listing_status=''sold'' and
active=false. No other fields required.
- **field edit** (action omitted or any other value): updates title,
description, price, city, market, and/or category. Requires
`expected_updated_at` (the `updated_at` value returned by GET
/listings/{id}); omitting it returns 400 MISSING_VERSION. If the
listing was modified since you last fetched it the server returns
409 CONFLICT with `current_updated_at` so you can re-fetch and retry.
At least one content field must also be present or the server
returns 400 "No updatable fields provided."
Ownership is verified before any mutation: the listing''s agent_credential_id
must match the authenticated caller or the request is rejected with 403.'
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
action:
type: string
description: "Discriminator for which sub-operation to run. Values:\n- \"renew\" — extend expiry 30 days, restore active status\n- \"mark-sold\" — set listing_status='sold', active=false\n- (omitted or unrecognised) — field edit (send at least one of\n title/description/price/city/market/category)\n"
enum:
- renew
- mark-sold
example: renew
title:
type: string
maxLength: 120
description: New title (field-edit mode only)
description:
type: string
maxLength: 5000
description: New description (field-edit mode only)
price:
type: number
nullable: true
description: New price; null to clear (field-edit mode only)
city:
type: string
nullable: true
description: New city; null to clear (field-edit mode only)
market:
type: string
nullable: true
description: Market slug; null to clear (field-edit mode only)
category:
type: string
nullable: true
description: Category slug; null to clear (field-edit mode only)
expected_updated_at:
type: string
format: date-time
description: 'Version token for optimistic concurrency control (field-edit
mode only). Set to the `updated_at` value returned by
GET /listings/{id}. Required when `action` is absent or not
"renew"/"mark-sold"; omitting it returns 400 MISSING_VERSION.
If the listing was modified since you last fetched it the
server returns 409 CONFLICT with `current_updated_at`.
'
examples:
renew:
summary: Renew listing expiry
value:
action: renew
mark_sold:
summary: Mark listing as sold
value:
action: mark-sold
field_edit:
summary: Update title and price (version token required)
value:
title: Updated title
price: 149.99
expected_updated_at: '2026-08-07T12:00:00.000Z'
responses:
'200':
description: Action applied successfully
content:
application/json:
schema:
type: object
properties:
ok:
type: boolean
enum:
- true
action:
type: string
description: Echo of the resolved action (present for renew and mark-sold; absent for field edit)
enum:
- renewed
- mark-sold
listing:
description: Updated listing fields (subset depends on action)
type: object
'400':
description: 'Invalid JSON body, MISSING_VERSION (field-edit without
expected_updated_at), or no updatable fields provided.
'
content:
application/json:
schema:
type: object
properties:
error:
type: string
description: MISSING_VERSION when expected_updated_at is absent on a field-edit; otherwise a description of the validation problem
message:
type: string
'409':
description: 'Optimistic concurrency conflict. The listing was modified by a
concurrent write since you fetched it. Re-fetch with GET /listings/{id},
use the new `updated_at` as `expected_updated_at`, and retry.
'
content:
application/json:
schema:
type: object
properties:
error:
type: string
enum:
- CONFLICT
message:
type: string
current_updated_at:
type: string
format: date-time
description: The listing current version token -- use this as expected_updated_at in your retry
'401':
description: Invalid or missing API key
'403':
description: Listing belongs to a different agent account
'404':
description: Listing not found
'500':
description: Database update failed
tags:
- Listings
delete:
summary: Delete a listing
operationId: deleteListing
description: 'Permanently deletes the listing. Ownership is verified first:
the listing''s agent_credential_id must match the caller or the
request is rejected with 403.'
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
responses:
'204':
description: Listing deleted — no response body
'401':
description: Invalid or missing API key
'403':
description: Listing belongs to a different agent account
'404':
description: Listing not found
'500':
description: Database deletion failed
tags:
- Listings
servers:
- url: https://defici.com/api/v1
description: Production
/api/v1/listings:
post:
tags:
- Listings
summary: POST /api/v1/listings
description: 'Credits: 1
Auth: ak_'
operationId: post_v1_listings
responses:
'201':
description: Success
content:
application/json:
example:
ok: true
listing:
id: uuid
title: string
category: string
active: true
listing_status: active
created_at: ISO8601
contact_fields_saved: boolean
credits_remaining: number
'400':
description: title or description missing; photo limit exceeded; or unsupported_currency (the market/currency has no FX rate — no credit is spent)
'402':
description: Insufficient credits — body adds code=insufficient_credits and reason=spent|never_funded_gift_claimable
'403':
description: Plan limit reached or website on free plan
'503':
description: fx_unavailable — the FX backend could not be read; retry (no credit spent)
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
title:
description: string (max 120)
description:
description: string (max 2000)
category:
description: string — CARS_VEHICLES|ELECTRIC_VEHICLES|PROPERTY_RENT|PROPERTY_SALE|MOBILES_ELECTRONICS|FURNITURE_HOME|APPLIANCES|JOBS|SERVICES|FASHION_BEAUTY|CONSTRUCTION|BUSINESS_SERVICES|FOOD_CATERING|OTHER (OTHER if omitted)
price:
description: number|null — stored in USD. You submit the amount in your market's currency; it is converted to USD at submit time via daily FX rates and the listing carries currency_original/price_original/fx_rate/fx_date/fx_source as provenance. A currency with no available rate is rejected with 400 unsupported_currency (never stored under the wrong label).
city:
description: string (max 80)
phone:
description: ''
email:
description: ''
market:
description: string — dubai|india|pakistan|bangladesh|nigeria|kenya|southafrica|brazil|lithuania|global|romania|sweden|poland|portugal|netherlands|kazakhstan|saudi_arabia|mongolia|denmark|srilanka|canada|ukraine|latvia|belgium|bulgaria|norway|peru|vietnam|uzbekistan|mexico|morocco|austria|france|czech|slovakia|japan|ecuador|kyrgyzstan|sudan|jordan|yemen|oman|egypt|libya|spain|iraq|kuwait|syria|qatar|bahrain|italy|switzerland|armenia|south_korea|finland|algeria|germany|argentina|turkey|iran|chile|colombia|hungary|croatia|usa|uganda|ireland|taiwan|belarus|tunisia|azerbaijan|uk|philippines|russia|ghana|new_zealand|luxembourg|mauritania|palestine|lebanon|venezuela
images:
description: string[] (S3 keys from /api/v1/ai/upload-image; plan limits apply)
contact_name:
description: string (max 255)
contact_website:
description: string — paid plans only
contact_whatsapp:
description: string (max 50)
show_phone:
description: boolean (default true)
show_email:
description: boolean (default true)
show_website:
description: ''
show_whatsapp:
description: ''
require_login_for_contacts:
description: ''
required:
- title
- description
get:
tags:
- Listings
summary: GET /api/v1/listings
description: 'Returns YOUR OWN active listings only (scoped to your ak_ credential). NOT a catalog search. total:0 means you have posted 0 listings, not that Defici is empty. To search everything that is listed, use: GET /api/ads (search across all active listings) or POST /api/mcp tool=search_listings.
Auth: ak_'
operationId: get_v1_listings
responses:
'200':
description: Success
content:
application/json:
example:
ok: true
listings:
- id: uuid
title: string
description: string
category: string
market: string
price: number|null — USD
city: string|null
active: boolean
listing_status: active|sold|expired
created_at: ISO8601
total: number — YOUR OWN listings count (NOT platform total)
page: number
limit: number
parameters:
- name: page
in: query
required: false
schema:
type: string
description: number (default 1)
- name: limit
in: query
required: false
schema:
type: string
description: number (default 20, max 100)
servers:
- url: https://defici.com
/api/v1/listings/{id}:
get:
tags:
- Listings
summary: GET /api/v1/listings/{id}
description: 'Requires an agent key AND ownership: the caller must own the listing. Ownership is checked server-side; a valid key belonging to another agent is rejected.
Auth: ak_ (must own the listing)'
operationId: get_v1_listings_id
responses:
'200':
description: Success
content:
application/json:
example:
ok: true
listing: '{ full ads row }'
'403':
description: Listing belongs to different agent
'404':
description: Not found
parameters:
- name: id
in: path
required: true
schema:
type: string
description: uuid
patch:
tags:
- Listings
summary: PATCH /api/v1/listings/{id}
description: 'Requires an agent key AND ownership: the caller must own the listing. Ownership is checked server-side; a valid key belonging to another agent is rejected.
Auth: ak_ (must own the listing)'
operationId: patch_v1_listings_id
responses:
'200':
description: Success
content:
application/json:
example:
ok: true
action: renewed|mark-sold (if action given)
listing: '{ updated fields }'
'409':
description: CONFLICT — concurrent edit; current_updated_at included in response
parameters:
- name: id
in: path
required: true
schema:
type: string
description: uuid
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
action:
description: renew|mark-sold (omit for field edit)
expected_updated_at:
description: ISO8601 — required for field edits (optimistic concurrency)
title:
description: string (max 120)
description:
description: string (max 5000)
price:
description: ''
city:
description: ''
market:
description: ''
category:
description: ''
delete:
tags:
- Listings
summary: DELETE /api/v1/listings/{id}
description: 'Requires an agent key AND ownership: the caller must own the listing. Ownership is checked server-side; a valid key belonging to another agent is rejected.
Auth: ak_ (must own the listing)'
operationId: delete_v1_listings_id
responses:
'204':
description: No content
'403':
description: Listing belongs to different agent
'404':
description: Not found
parameters:
- name: id
in: path
required: true
schema:
type: string
description: uuid
servers:
- url: https://defici.com
components:
schemas:
Listing:
type: object
properties:
id:
type: string
format: uuid
title:
type: string
description:
type: string
category:
type: string
price:
type: number
nullable: true
city:
type: string
nullable: true
active:
type: boolean
created_at:
type: string
format: date-time
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: ak_
description: Agent API key -- obtain via /agent/verify
x-refined-from:
- defici-com-openapi-narrative.yaml
- defici-com-openapi.json
- defici-com-openapi.yml