API documentation
View as Markdown

Quickstart

This guide takes you from partner credentials to a working integration: a seller connects your application, you receive tokens, you call the API, and you receive webhooks.

Before you start

Demarky registers your application and sends you:

ItemNotes
client_idPublic identifier, shaped app_…
client_secretShown to Demarky staff once and sent to you once. Store it encrypted.
Granted scopesThe ceiling for every seller grant. Requesting anything outside it fails.
Registered redirect URIsMatched exactly, including scheme, host, port, and path

Send Demarky your redirect URI before you start: an unregistered value is rejected at the first step.

1. Send the seller to Demarky

Your application starts the flow. Generate a fresh state and a PKCE code_verifier per attempt, store both against the browser session, and redirect the seller's browser — this is a full-page navigation, not a background request.

https://api.demarky.ai/oauth/authorize
  ?client_id=app_0123456789abcdefghjkmnpqrs
  &redirect_uri=https://partner.example/oauth/callback
  &response_type=code
  &scope=products:read%20pages:write
  &state=ac9f7e2b13c84f0f1d7a
  &code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
  &code_challenge_method=S256
RequirementRule
stateAt least 16 characters of randomness; returned unchanged on success and on error
code_challengeBase64url SHA-256 of your verifier, 43–128 characters
code_challenge_methodS256 only; plain PKCE is rejected
scopeSpace-separated, at least one, all within your registered scopes

The seller signs in to Demarky, reviews the permissions, and approves. Their browser returns to your redirect_uri with code and state. If they decline, it returns with error=access_denied instead.

2. Exchange the code

Validate that state matches what you stored, then exchange the code from your server. The code is single-use and expires in five minutes.

curl -X POST https://api.demarky.ai/oauth/token \
  -u "$DEMARKY_CLIENT_ID:$DEMARKY_CLIENT_SECRET" \
  -d grant_type=authorization_code \
  -d code=dmk_ac_live_xxx \
  -d redirect_uri=https://partner.example/oauth/callback \
  -d code_verifier=your_original_pkce_verifier
{
  "access_token": "dmk_at_live_xxx",
  "token_type": "Bearer",
  "expires_in": 600,
  "refresh_token": "dmk_rt_live_xxx",
  "scope": "products:read pages:write",
  "account_id": "acct_0123456789abcdefghjkmnpqrs",
  "application_id": "app_0123456789abcdefghjkmnpqrs",
  "installation_id": "ins_0123456789abcdefghjkmnpqrs"
}

3. Store the installation

FieldWhy you need it
installation_idYour primary key for this connection; stable across re-consent
account_idGoes in the path of every resource request
access_token + expiryExpires in 10 minutes
refresh_tokenRotates on every use — always persist the newest one
scopeWhat this installation may actually do

There is no endpoint that returns these later. If you lose them, the seller has to reconnect.

4. Call the API

curl -H "Authorization: Bearer dmk_at_live_xxx" \
  https://api.demarky.ai/v1/accounts/acct_0123456789abcdefghjkmnpqrs/products

A 401 with invalid_token means the token expired or the seller disconnected: refresh once and retry, and treat a second failure as disconnected. A 403 with insufficient_scope is permanent for this installation — retrying will not help, because only a new consent can widen a grant.

5. Keep the connection alive

curl -X POST https://api.demarky.ai/oauth/token \
  -u "$DEMARKY_CLIENT_ID:$DEMARKY_CLIENT_SECRET" \
  -d grant_type=refresh_token \
  -d refresh_token=dmk_rt_live_xxx

Three rules decide whether your integration survives in production:

6. Receive webhooks

Webhook endpoints belong to your application, not to individual sellers, and you manage them yourself with your client credentials. Deploy your receiver first — Demarky posts a signed challenge to the URL during registration, and an endpoint whose challenge fails stays in pending_verification.

curl -X POST https://api.demarky.ai/v1/developer/webhook-endpoints \
  -u "$DEMARKY_CLIENT_ID:$DEMARKY_CLIENT_SECRET" \
  -H 'Content-Type: application/json' \
  -d '{"url":"https://partner.example/webhooks/demarky","events":["lead.created"]}'

The challenge arrives as a POST with header Demarky-Event-Type: endpoint.verification and a JSON body containing a challenge nonce. Answer 200 and echo the nonce back, either as the raw body or as {"challenge": "…"}. On a first registration you cannot verify its signature: the endpoint secret is created for that challenge and only returned to you in the response you are still waiting on. Verify signatures on every delivery afterwards, and on re-verification and secret rotation.

The response contains secret exactly once. See Webhooks for the signature scheme, the event catalogue, and delivery semantics.

7. Disconnecting

curl -X POST https://api.demarky.ai/oauth/revoke \
  -u "$DEMARKY_CLIENT_ID:$DEMARKY_CLIENT_SECRET" \
  -d token=dmk_rt_live_xxx

Revoking a refresh token ends the family but leaves already-issued access tokens valid until they expire, so revoke both if that matters to you.

A seller can also disconnect from their Demarky dashboard, and there is no webhook for it. You discover it the same way you discover an expired grant: calls return 401 and the refresh returns invalid_grant. Treat that pair as an uninstall and clean up.