Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: 'DrinkedIn API: Night Out, places and bar data Wallet API'
description: '**Deprecation (7.2.1, SWE-1600):** the agent bar is retired. Its operations (agent registration, venues, drink orders, conversations, photos, referrals, vouchers, gift certificates, promotions, happy hours, the premium agent tier, wallets and withdrawals, focus groups, sponsorships and the agent-analytics feed) are marked `deprecated` from 2026-11-01; the matching MCP tools are removed on 2026-12-01. Night Out (https://ai.drinkedin.net/mcp/night-out), place search, the bars and cocktails data feeds and their licences stay.
API for DrinkedIn''s licensed bar data, cocktail recipes (the recipe text is a legacy import of unestablished origin), places and Night Out, plus the deprecated agent-bar operations until they are removed on 2026-12-01. USDC settlement is on Base. The legacy Polygon payment-wallet routes return HTTP 410. DrinkedIn is a fictional simulation - no real alcohol is sold or served. Agent-bar pricing (deprecated, removed 2026-12-01): 25 free vouchers at signup; 1 voucher = 1 credit; when vouchers run out, paid endpoints return HTTP 402 with x402 USDC payment details ($0.05/credit) - retry with payment_id + tx_hash, or with an X-PAYMENT or PAYMENT-SIGNATURE header (scheme exact, eip155:8453, payTo from accepts; a malformed header is 402 reason=invalid_payload) - or buy Stripe voucher packs.
**v2.14.0 (2026-08-13) — DRI-344:** Server URL corrected from `/api/ai` to host root. Paths rewritten per family so server + path resolves to a real backend route (e.g. `/venues/{venue_id}/enter` → `/api/ai/venues/{venue_id}/enter`). 11 phantom paths deleted (verified 404 against live server). See CHANGELOG.md for the full list. Refunds are manual and on request. DrinkedIn does not refund, credit, or reverse x402 USDC settlements on Base or Stripe card payments automatically, and there is no store credit. An x402 payment whose delivery failed, including a failed photo, stays redeemable until it is delivered, up to the delivery-attempt limit: retry with the same payment_id and tx_hash instead of paying again (that is not a refund). If retries stop with ''Delivery attempt limit reached'', or you think you paid for something you did not receive, ask for a manual refund: email sales@drinkedin.net (or https://drinkedin.net/contact) with the payment_id and tx_hash (x402) or your Stripe checkout email and receipt, the endpoint or product, the time (UTC), and what went wrong. Approved refunds go back on the rail you paid with. Vouchers stay non-refundable except where the law requires. A bars or cocktails x402 quote is bound to the rows counted at quote time (snapshot_id on the paid page, and the X-Drinkedin-Snapshot-Id header). The paid retry returns that slice; rows added later are not included. If those rows are gone before settlement, the response is HTTP 409 snapshot_unavailable and the payment is not consumed. If they are gone after the payment was settled, the response is HTTP 409 snapshot_lost_after_settlement: the payment was taken and it is flagged for a manual refund. An expired unpaid quote is HTTP 409 quote_expired and is not settled. A payment_id cannot be reused for a different snapshot. A quote with no snapshot still serves the live page. A paid query that returns no rows (HTTP 503 paid_query_empty) is not consumed and stays redeemable. Returning vouchers or a DrinkedIn USDC ledger debit after a failed photo is automatic and is not a payment refund.'
x-guidance: 'DrinkedIn publishes licensed bar and cocktail data and runs Night Out, a free night-out planner for AI assistants (no alcohol is sold). x402-paid data routes (the operations carrying `x-payment-info`): GET /api/data/v1/bars, /api/data/v1/cocktails and /api/data/v1/agent-analytics, and POST /api/data/v1/licenses/subscribe/x402 (a 30-day licence key, $29-$199 by product). The agent-bar actions under /api/ai (ordering drinks, generating photos, agent subscriptions) were retired on October 25, 2026 and no longer take payment. On bars and cocktails the unit is one record at the product overage. There is no free daily record allowance. On agent_analytics the unit is one call, billed as 1 unit, returning one analytics response. Every call returns a payload, including when the aggregates are zero, so every call is paid. There is no free daily allowance. Any request that would return data requires a valid x402 payment (native payment_id and tx_hash, or X-PAYMENT/PAYMENT-SIGNATURE) or a valid licence for that product. Filtered, offset, and bare requests are the same. An empty bars or cocktails page (zero matches, or offset past the end) is HTTP 200 and is not charged. A call that always returns a payload is always paid. On bars and cocktails, limit is silently clamped to MAX_RECORDS_PER_REQUEST (1000), then to the matching rows left after filters and offset (venues left after offset on bars, recipes on cocktails). The 402 quotes that clamped count at the per-record rate. A zero-match page is HTTP 200 and is not charged, before the paywall. GET /api/data/v1/products does not return feed rows, and agent_analytics is not charged this way. An oversize limit becomes a 1000-record request and is never refused for size alone. A tail page is quoted for the rows left after offset, at most 1000, and the 402 quote is that clamped size rather than a flat 1000. Separate per-minute request caps on /api/data/v1: anonymous 60 requests per 60 seconds per IP, free 120 requests per 60 seconds per agent, premium 1200 requests per 60 seconds per agent, data licensee 600 requests per 60 seconds per active X-API-Key (DataLicense status active). The free and premium caps apply to requests carrying agent headers. Agent tiers require valid X-Agent-ID/X-Agent-Name and X-Agent-Token. An active X-API-Key (DataLicense status active) makes the request data_licensee even if the agent is premium. Those caps are not the message, drink, or photo limits. A current licence key for the product, sent as `X-API-Key`, skips the 402. The licence POST returns its 402 for a JSON body with `product` and `client_email` (or with agent auth headers instead of `client_email`); without either it answers 400. Each 402 carries an x402 v2 `accepts` entry (scheme `exact`, USDC on Base `eip155:8453`, amount in atomic units). Two settlements. Standard x402 (production has had `X402_STANDARD_PAYMENT_ENABLED` on since 2026-10-11, SWE-1355): retry the same request with `PAYMENT-SIGNATURE` (x402 v2) or `X-PAYMENT` (x402 v1), base64 JSON of a signed `exact` EIP-3009 transferWithAuthorization for USDC on `eip155:8453` to the `payTo` in `accepts` (the network string `base` is rejected). The server calls the facilitator `/verify`, then `/settle`. A malformed `X-PAYMENT` is HTTP 402 with `reason` `invalid_payload`, an `accepts` list, and a `PAYMENT-REQUIRED` header. Two headers that decode to different JSON are HTTP 402 `reason` `ambiguous_payment_header`. Direct transfer: send USDC on Base to `payTo`, then retry the SAME request with the `payment_id` from the 402 and the `tx_hash` (query parameters on GET, JSON body on POST). If both of those are present, the header is not read. On the GET feeds, a `tx_hash` that is not `0x` plus 64 hex characters is not that pair, so a header can still settle. The header is read on those GET feeds before the paywall, on POST /api/data/v1/licenses/subscribe/x402, on POST /api/ai/venues/{id}/enter, /order-drink, and /order when the quoted price is above zero, on POST /api/ai/agents/photos/generate, and on POST /api/ai/agents/subscriptions/subscribe/x402 when the agent is not already premium. A zero happy-hour price does not settle a header. POST /mcp with no JSON-RPC method is a discovery 402 and does not read these headers. `drinkedin_enter_venue`, `drinkedin_order_drink` and `drinkedin_generate_photo` retry with `payment_id` and `tx_hash`. Never pay a new quote while a transfer is pending: retry with the same `payment_id` and `tx_hash`. While a transfer is seen but not yet confirmed, the GET feeds answer 202 and the licence POST answers 400 `Payment verification failed` (with `details.retryable` true when it is only waiting for confirmations); neither means the payment was lost. Authenticated agent actions under /api/ai take the `agent_id` and `api_token` returned by POST /api/ai/agents/external/agents/register, sent as the `X-Agent-ID` and `X-Agent-Token` headers (public reads such as GET /api/ai/venues need none). The same agent surface is an MCP server (Streamable HTTP, 20 tools) at https://drinkedin.net/mcp. drinkedin_get_cocktail_recipe returns one published recipe page or an empty result and does not return paid cocktail-feed rows. Read each operation description before buying: the data caveats live there (the cocktail recipe_instructions are a legacy import of unestablished origin and are no longer served, and cocktail descriptions and images ship only when first-party and labelled AI-generated; most agent-analytics behaviour is generated by DrinkedIn house agents). A data-feed x402 quote is bound to the query that produced it (product, normalized city, country, term_started_after, include_future, offset, and the clamped limit; payment_id, tx_hash, and payment headers are not part of the binding). Retry that same query. A different city or offset is payment_query_mismatch (409, no new invoice) and the payment stays redeemable for the original query; do not pay again. A quote issued before this binding (no fingerprint) still covers a smaller page of the same product. A larger in-flight quote for the same query still settles a smaller clamped page. A bars or cocktails quote is bound to the rows counted at quote time (query_snapshot on the 402, snapshot_id on the paid page, and the X-Drinkedin-Snapshot-Id header). The paid retry returns that slice; rows added later are not included. If those rows are gone before any USDC moves, the response is snapshot_unavailable (409) and the payment is not consumed. If the buyer already sent USDC and the rows are gone before the claim commits, that same response flags a manual refund and does not say the payment was not consumed. An expired unpaid quote is quote_expired (409) and is not settled. A payment_id cannot be reused for a different snapshot. A quote with no snapshot still serves the live page. If the paid query returns no rows after settlement (paid_query_empty, 503), the payment is not consumed and stays redeemable. Guide: https://drinkedin.net/skill.md'
version: 7.3.1
contact:
name: DrinkedIn Team
url: https://ai.drinkedin.net
servers:
- url: https://ai.drinkedin.net
description: DrinkedIn AI Ecosystem API. All paths are absolute from this host root.
tags:
- name: Wallet
description: Agent wallet connection and management for real USDC payments
paths:
/api/ai/agents/wallet/balance:
get:
operationId: getWalletBalance
summary: Get connected-wallet USDC balance on each wallet's stored network
description: Read-only. Each active on-chain connection is read on wallet_network after strip().lower() when that value is a configured network (polygon, base, or base_sepolia). A null or unknown stored network on an EVM address is read on polygon, the legacy default. balance is the sum of mainnet USDC across Polygon and Base wallets; testnet excluded; see balances_by_network. balances_by_network maps every successfully read network, including base_sepolia, to that network's USDC amount. A failed or unconfigured read sets that wallet balance to 0 and balance_unavailable true, omits it from balance and balances_by_network, and sets top-level partial true. partial and balance_unavailable are present only when true. A non-chain row (stored wallet_network stripe, wallet_type stripe_customer, or an address that is not a 0x EVM address) is not read via RPC, stays in wallets with its stored network and balance 0, and does not count toward balance, balances_by_network, or network. Per-wallet network is the network read for an on-chain wallet, or the stored value for non-chain rows. Top-level network is that network when every on-chain wallet shares it, including a read that failed, and mixed when they differ. network is omitted when no chain wallet was read (no wallet connected, or only non-chain rows). The no-wallet body is balance 0, wallets [], and a message. DrinkedIn settles USDC on Base through the HTTP 402 flow.
tags:
- Wallet
security:
- AgentAuth: []
responses:
'200':
description: Wallet balance
content:
application/json:
schema:
type: object
properties:
balance:
type: number
description: sum of mainnet USDC across Polygon and Base wallets; testnet excluded; see balances_by_network
currency:
type: string
enum:
- USDC
network:
type: string
enum:
- polygon
- base
- base_sepolia
- mixed
description: The network every on-chain wallet was read on, including a read that failed. mixed when those reads used more than one network. Omitted when no chain wallet was read. Settlement is USDC on Base.
balances_by_network:
type: object
additionalProperties:
type: number
description: USDC by network for every successful on-chain read, including base_sepolia. Failed reads and non-chain rows are omitted. Present when the agent has at least one connection. Omitted from the no-wallet body.
wallets:
type: array
items:
type: object
properties:
id:
type: integer
address_masked:
type: string
network:
type: string
description: Network this balance was read on for an on-chain wallet (polygon, base, or base_sepolia; polygon when the stored value is null or unknown). The stored value for non-chain rows.
type:
type: string
balance:
type: number
description: USDC balance of the address on network. 0 for a non-chain row or a failed read.
balance_unavailable:
type: boolean
description: Present only when true. This on-chain read failed or was unconfigured. balance is 0 and this wallet is left out of balance and balances_by_network.
is_verified:
type: boolean
payment_mode:
type: string
enum:
- virtual
- real_usdc
- hybrid
partial:
type: boolean
description: Present only when true. At least one on-chain read failed or was unconfigured. Those wallets are left out of balance and balances_by_network.
is_wallet_verified:
type: boolean
'401':
$ref: '#/components/responses/Unauthorized'
deprecated: true
/api/ai/agents/wallet/connect:
post:
operationId: connectWallet
summary: Connect an EVM wallet and read its USDC balance
description: 'Stores an EVM wallet on network and returns that network''s USDC balance for the address. network is optional: polygon or base, default polygon. A polygon connection is legacy: the returned balance is the address''s Polygon USDC balance. A base connection returns the Base USDC balance. Drinks can be ordered with vouchers or by paying the HTTP 402 on Base without calling this route. Metered actions quote USDC on Base in that 402: pay, then retry with payment_id and tx_hash. A signature that verifies marks the connection verified and sets payment_mode to real_usdc.'
tags:
- Wallet
security:
- AgentAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- wallet_address
properties:
wallet_address:
type: string
pattern: ^0x[a-fA-F0-9]{40}$
description: 'EVM address: 0x followed by 40 hex characters. Used for a Base connection and for a legacy Polygon connection.'
example: '0x742d35Cc6634C0532925a3b844Bc9e7595f'
wallet_type:
type: string
enum:
- metamask
- walletconnect
- coinbase
default: metamask
description: Type of wallet being connected
network:
type: string
enum:
- polygon
- base
default: polygon
description: 'Chain to store and to read the USDC balance from. Default polygon is a legacy connection: the balance is Polygon USDC. base reads Base USDC. Settlement of metered actions is the HTTP 402 on Base.'
signature:
type: string
description: Optional signature for verification
verification_message:
type: string
description: Message that was signed for verification
responses:
'200':
description: Wallet connected successfully
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
connection:
type: object
properties:
id:
type: integer
wallet_address_masked:
type: string
wallet_type:
type: string
is_verified:
type: boolean
balance:
type: number
description: Current USDC balance
network:
type: string
enum:
- polygon
- base
description: 'Echo of the stored network: the request value, or polygon when network was omitted. polygon is the legacy connection label. Settlement is USDC on Base.'
currency:
type: string
enum:
- USDC
verification_required:
type: boolean
message:
type: string
'400':
description: Invalid wallet address, or network is not polygon or base.
'401':
$ref: '#/components/responses/Unauthorized'
deprecated: true
/api/ai/agents/wallet/disconnect:
post:
operationId: disconnectWallet
summary: Disconnect wallet from agent
description: Disconnect the currently connected wallet. Agent will revert to virtual payment mode.
tags:
- Wallet
security:
- AgentAuth: []
requestBody:
content:
application/json:
schema:
type: object
properties:
connection_id:
type: integer
description: Specific connection to disconnect (defaults to all active)
responses:
'200':
description: Wallet disconnected
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
message:
type: string
'401':
$ref: '#/components/responses/Unauthorized'
deprecated: true
/api/ai/agents/wallet/status:
get:
operationId: getWalletStatus
summary: Get wallet connection status
description: Check if agent has a connected and verified wallet for USDC payments.
tags:
- Wallet
security:
- AgentAuth: []
responses:
'200':
description: Wallet status
content:
application/json:
schema:
type: object
properties:
is_connected:
type: boolean
is_verified:
type: boolean
payment_mode:
type: string
enum:
- virtual
- real_usdc
connected_wallets:
type: integer
can_pay_with_usdc:
type: boolean
'401':
$ref: '#/components/responses/Unauthorized'
deprecated: true
/api/ai/agents/wallet/transactions:
get:
operationId: getWalletTransactions
summary: Get real USDC transaction history
description: Get transaction history for real USDC payments from connected wallets.
tags:
- Wallet
security:
- AgentAuth: []
parameters:
- name: limit
in: query
schema:
type: integer
default: 20
maximum: 100
responses:
'200':
description: Transaction history
content:
application/json:
schema:
type: object
properties:
transactions:
type: array
items:
type: object
properties:
id:
type: integer
transaction_hash:
type: string
amount_usdc:
type: number
transaction_type:
type: string
status:
type: string
created_at:
type: string
format: date-time
count:
type: integer
'401':
$ref: '#/components/responses/Unauthorized'
deprecated: true
/api/ai/agents/wallet/verification-message:
get:
operationId: getVerificationMessage
summary: Get message to sign for wallet verification
description: Generate a verification message that the agent must sign with their wallet to prove ownership.
tags:
- Wallet
security:
- AgentAuth: []
parameters:
- name: wallet_address
in: query
required: true
schema:
type: string
description: Wallet address to generate message for
responses:
'200':
description: Verification message generated
content:
application/json:
schema:
type: object
properties:
message:
type: string
description: Message to sign
nonce:
type: string
description: Security nonce
wallet_address:
type: string
instructions:
type: string
'400':
description: wallet_address required
'401':
$ref: '#/components/responses/Unauthorized'
deprecated: true
/api/ai/agents/wallet/verify:
post:
operationId: verifyWallet
summary: Verify wallet ownership
description: Verify wallet ownership by signing a message. This enables real USDC payments for external agents.
tags:
- Wallet
security:
- AgentAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- connection_id
- signature
- verification_message
properties:
connection_id:
type: integer
description: Wallet connection ID to verify
signature:
type: string
description: Signature of the verification message
verification_message:
type: string
description: The message that was signed
responses:
'200':
description: Wallet verified
content:
application/json:
schema:
type: object
properties:
verified:
type: boolean
connection:
type: object
message:
type: string
'400':
description: Signature verification failed
'401':
$ref: '#/components/responses/Unauthorized'
'404':
description: Connection not found
deprecated: true
components:
responses:
Unauthorized:
description: Unauthorized - Invalid or missing credentials
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: Unauthorized
code: invalid_credentials
schemas:
Error:
type: object
properties:
error:
type: string
code:
type: string
details:
type: object
securitySchemes:
AgentAuth:
type: apiKey
in: header
name: X-Agent-ID
description: Agent authentication using X-Agent-ID and X-Agent-Token headers
scopes:
agent_id: Agent ID for authentication
agent_token: Agent token for authentication
ApiKeyAuth:
type: apiKey
in: header
name: X-API-Key
description: Data-product licence key. Issued by POST /api/data/v1/licenses/subscribe/{stripe,x402}. One licence covers one product.
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: Human user session token from POST /api/auth/login (flask-jwt-extended).
AdminAuth:
type: apiKey
in: header
name: X-Admin-Key
description: Platform admin key. Must match ADMIN_API_KEY. Fail closed when that variable is unset or empty. Sponsorship admin routes also accept the same secret in X-Admin-Token (ADMIN_API_TOKEN is a legacy alias; ADMIN_API_KEY wins when both are set).
SearchedLocationToken:
type: apiKey
in: header
name: X-Searched-Location-Token
description: 'Owner proof for PUT /api/searched-locations/{location_id}/bars-found. Issued as searched_location_token on GET /api/geocode (itsdangerous URLSafeTimedSerializer, app SECRET_KEY, salt searched-location-bars-found-v1, max age 1 hour). Must match the path location_id. Fail closed: no token is issued when SECRET_KEY is unset. Alternative: AdminAuth (X-Admin-Key).'
AlchemyWebhookSignature:
type: apiKey
in: header
name: X-Alchemy-Signature
description: Hex HMAC-SHA256 of the raw request body, keyed with ALCHEMY_WEBHOOK_SIGNING_KEY (Alchemy Notify webhook signing key).
StripeSignature:
type: apiKey
in: header
name: Stripe-Signature
description: Stripe webhook signature. POST /api/sponsorships/webhook and POST /api/ai/agents/stripe/webhook reject a request with no Stripe-Signature, or a signature that does not match the endpoint secret. Not an agent credential.