Cowdidocs
API ReferenceMerchants

List merchants

GET
/v1/merchants

Lists canonical Sales App merchants with contact details, lifecycle status and timestamps. Requires org:merchants:read, org:merchants:write or org:merchants:admin through a verified user or machine token. Partner tokens read their tenant. user_id narrows the list to the merchants linked to one Cowdi user. Cowdi platform tokens retain the detail API's existing all-tenant view. Impersonated reads mask names, email and phone. Read full merchant details through GET /v1/merchants/{merchantId}.

AuthorizationBearer <token>

Create a client with POST /v1/oauth/clients, then exchange its credentials for an access token. AUTHORIZATION_CODE clients act on behalf of a signed-in user and always use PKCE; CLIENT_CREDENTIALS clients act as themselves. A client may only be granted scopes its creator already holds — read the grantable list from GET /v1/oauth/clients/scopes.

In: header

Query Parameters

status?string

Exact Sales App lifecycle status in uppercase. Omit this parameter to include every status.

Value in

  • "LEAD"
  • "ACTIVE"
  • "INACTIVE"
  • "BLOCKED"
  • "REJECTED"
  • "TEST"
  • "PENDING"
  • "CONTACTED"
  • "PROSPECT"
  • "QUALIFIED"
  • "OPPORTUNITY"
  • "PHONE_VERIFICATION"
  • "PHYSICAL_VERIFICATION"
  • "APPROVED"
  • "DOCUMENT_PENDING"
  • "HOLD"
user_id?string

Cowdi user id the merchant is linked to, matched case-insensitively. Omit this parameter to include every merchant.

Length1 <= length <= 255
q?string

Case-insensitive text search across contact name, business name, email and phone. A complete UUID also matches the canonical id. Nonblank terms require at least 3 characters after trimming. Blank terms disable search. Wildcard characters are literal.

size?integer

Maximum number of merchants per page. Defaults to 20.

Range1 <= value <= 100
Default20
after?string

Opaque cursor from links.next. Cannot be combined with before. Omit for the first page.

before?string

Opaque cursor from links.prev. Cannot be combined with after. Omit for the first page.

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

curl -X GET "https://example.com/v1/merchants"
{  "data": [    {      "id": "650e8400-e29b-41d4-a716-446655440000",      "name": "Jane Merchant",      "business_name": "Acme Supplies",      "phone_number": "+254712345678",      "email": "jane@example.test",      "organization_id": "gilanis",      "status": "OPPORTUNITY",      "created_at": "2026-09-01T12:00:00.000Z",      "updated_at": "2026-09-02T12:00:00.000Z",      "activated_at": "2026-09-03T12:00:00.000Z"    }  ],  "links": {    "next": "/v1/merchants?size=20&after=eyJ0cyI6IjIwMjYtMDktMDFUMTI6MDA6MDBaIiwiaWQiOiI2NTBlODQwMC1lMjliLTQxZDQtYTcxNi00NDY2NTU0NDAwMDAifQ",    "prev": "/v1/merchants?size=20&before=eyJ0cyI6IjIwMjYtMDktMDFUMTI6MDA6MDBaIiwiaWQiOiI2NTBlODQwMC1lMjliLTQxZDQtYTcxNi00NDY2NTU0NDAwMDAifQ"  }}
{  "code": "INVALID_PARAMS",  "description": "user_id must be a UUID",  "identifier": "string",  "invalid_params": [    {      "path": "user_id",      "reason": "must be a UUID",      "sub_code": "string"    }  ]}
{  "code": "INVALID_PARAMS",  "description": "user_id must be a UUID",  "identifier": "string",  "invalid_params": [    {      "path": "user_id",      "reason": "must be a UUID",      "sub_code": "string"    }  ]}
{  "code": "INVALID_PARAMS",  "description": "user_id must be a UUID",  "identifier": "string",  "invalid_params": [    {      "path": "user_id",      "reason": "must be a UUID",      "sub_code": "string"    }  ]}
{  "code": "INVALID_PARAMS",  "description": "user_id must be a UUID",  "identifier": "string",  "invalid_params": [    {      "path": "user_id",      "reason": "must be a UUID",      "sub_code": "string"    }  ]}
{  "code": "INVALID_PARAMS",  "description": "user_id must be a UUID",  "identifier": "string",  "invalid_params": [    {      "path": "user_id",      "reason": "must be a UUID",      "sub_code": "string"    }  ]}

Merge a duplicate user into a user POST

Merge a duplicate user that has only a WorkOS login into the user in the path. The user in the path gets the WorkOS login, the verified email, and the organization memberships. The duplicate user becomes inactive and keeps its history. Requires the `org:users:write` permission on the cowdi organization. Returns 200 with no change when the merge already happened. Returns 409 when the duplicate user has a phone sign-in, an open account, or an active merchant membership. Returns 409 when the user in the path already has a WorkOS login or an email, or when either user is merged into another user.

Create a merchant POST

The canonical merchant-creation API for all products. Requires org:merchants:write. Sales App generates the id; clients cannot supply an id or organization. The verified token selects the tenant (Cowdi uses the organic book). Creates an opportunity with its initial activity and optional employee assignment in one transaction. Reuse idempotency_key with identical details to recover the same id after a timeout. A changed request or a phone/ID owned by another merchant returns 409. user_id links the merchant to an existing Cowdi user (a service onboarding one of its users); one merchant per user per organization, so naming a user already linked there returns that merchant with 200 instead of creating another. Core registration must use the returned id; it does not generate another identity. Product setup, invitations and activation remain separate lifecycle operations.