heruAPI
Point of sale

Add a merchant

LiveServed by the v1 API in development with the same checks as production; production opens on the same contract. The capabilities from before v1 keep running in production at the path your account team gives you.

POST
/merchants

Registers a merchant that will invoice its card sales. The response carries onboarding.url, a page hosted by heru with your brand where the merchant uploads their CSD; send it to them. If you already hold the CSD, upload it with PUT /merchants/{id}/csd instead. merchant.activated tells you when the merchant can invoice.

Needs the merchants:write scope.

Authorization

oauth2 merchants:write
headerAuthorizationBearer <token>

OAuth 2.0 client credentials. Exchange your client_id and client_secret at /oauth/token of the environment for a bearer token valid for one hour. The playground of every operation asks for your own client and keeps it in your browser tab only.

Scope: merchants:write

Header parameters

Idempotency-Key*string

Unique per operation. Retrying with the same key returns the original result for 24 hours.

Lengthlength <= 255

Request body

application/json
  1. body
external_id*string

Your merchant id, e.g. the card-acceptance affiliation.

Lengthlength <= 128
rfc*string

RFC, 12 characters (company) or 13 (individual). The merchant issues the invoices with it.

Match^[A-ZÑ&]{3,4}[0-9]{6}[A-Z0-9]{3}$
legal_name*string

Name exactly as registered with the SAT. For an individual it is the person's name, not the business name.

tax_regime*string

SAT c_RegimenFiscal of the merchant.

postal_code*string

Postal code of the merchant's tax address.

trade_name?string

Business name the customer sees on the self-invoicing page.

slug?string

Short name in the merchant's invoicing link: https://invoice.heru.app/{slug}. Unique across heru. If you leave it out, heru builds it from trade_name (or legal_name). A taken slug answers 409.

Match^[a-z0-9]+(-[a-z0-9]+)*$
Length3 <= length <= 40
email?string

Where heru sends the CSD expiry reminders.

Formatemail
locations?array<>
default_item?

What the invoice says when a charge comes without items: one line for the whole amount. Leave it out if you always send items; then a charge without them answers 422. A merchant that sells at different VAT rates, like a supermarket, should send items in every charge.

Response body

Created

application/json
  1. response
id*string
Match^mer_[0-7][0-9a-hjkmnp-tv-z]{25}$
external_id*string
status*string

pending_csd until the merchant uploads their CSD; active when they can invoice; active_pending_sat while the SAT confirms a new CSD; csd_expiring 30 days before it expires; csd_expired, suspended or closed when they cannot invoice.

Value in"pending_csd""active""active_pending_sat""csd_expiring""csd_expired""suspended""closed"
rfc*string

RFC, 12 characters (company) or 13 (individual). The merchant issues the invoices with it.

Match^[A-ZÑ&]{3,4}[0-9]{6}[A-Z0-9]{3}$
legal_name*string
trade_name?string|null
slug*string

Short name in the merchant's invoicing link.

Match^[a-z0-9]+(-[a-z0-9]+)*$
Length3 <= length <= 40
tax_regime*string
postal_code*string
email?|null
locations?array<>
default_item*|

What the invoice says when a charge comes without items. Null if the merchant has none.

csd*
onboarding*
created_at*string
Formatdate-time
updated_at*string
Formatdate-time
curl -X POST 'https://api.dev.b2b.heru.app/v1/merchants' \  -H 'Idempotency-Key: try-it-0001' \  -H 'Content-Type: application/json' \  -d '{  "external_id": "AFIL-000125",  "rfc": "XAMA620210DQ5",  "legal_name": "ALBA XKARAJAM MENDEZ",  "tax_regime": "612",  "postal_code": "03100",  "trade_name": "Clínica Dental Roma",  "slug": "clinica-dental-roma",  "email": "contacto@clinica-dental-roma.example",  "locations": [    {      "external_id": "SUC-01",      "postal_code": "03100",      "name": "Centro"    }  ],  "default_item": {    "product_code": "85122000",    "unit_code": "E48",    "description": "Consulta y limpieza dental",    "vat_rate": "exempt"  }}'
{  "id": "mer_01m4xnvf23ecb963n48h2j9vxz",  "external_id": "AFIL-000125",  "status": "pending_csd",  "rfc": "XAMA620210DQ5",  "legal_name": "ALBA XKARAJAM MENDEZ",  "trade_name": "Clínica Dental Roma",  "slug": "clinica-dental-roma",  "tax_regime": "612",  "postal_code": "03100",  "email": "contacto@clinica-dental-roma.example",  "locations": [    {      "external_id": "SUC-01",      "name": "Centro",      "postal_code": "03100"    }  ],  "default_item": {    "product_code": "85122000",    "unit_code": "E48",    "description": "Consulta y limpieza dental",    "vat_rate": "exempt"  },  "csd": {    "active": false,    "valid_from": null,    "valid_to": null  },  "onboarding": {    "status": "pending",    "url": "https://onboarding.heru.app/m/7KQ2M9XT4PWB",    "expires_at": "2026-10-21T17:02:41.219Z",    "completed_at": null  },  "created_at": "2026-10-14T17:02:41.219Z",  "updated_at": "2026-10-14T17:02:41.219Z"}
© 2026 Kuarto Inc. (heru)heru.appQuestions about your integration? Contact your heru account team.