API & webhooks (beta): Pro and Enterprise plans

Reshta API docs

Connect your own site, ERP or accounting software to Reshta: create contacts and deals, record orders, and hear about every change through webhooks. REST and JSON, with one key.

  1. 1Create an API key in ReshtaConnection → Developer
  2. 2Your first requestYour system to Reshtacurl -H "Authorization: Bearer …" …/contacts
  3. 3Receive a webhookReshta to your systemPOST deal.won

What can you build?

Sync your own site or ERPCreate and update contacts, companies and deals in Reshta from your own system.POST /contacts
Leads from your own formsAny form or landing page built outside Reshta creates the contact and deal directly.POST /deals
Orders from your sales systemOrders that do not come from WooCommerce or marketplaces land on the right customer record.POST /orders
React to eventsWhen a deal is won or an order is placed, a signed webhook tells your system.deal.won

Base URL

Every request goes to this address over HTTPS. Bodies are UTF-8 JSON, times are ISO 8601 in UTC, and amounts are integers in rials.

Base URL
URL
https://app.reshta.ir/api/v1/public​

Authentication

Every request carries the business API key in the Authorization header. A business admin creates the key in the Reshta app:

  1. 1Sign in at app.reshta.ir with an admin account; its email must be verified.
  2. 2Open Connection in the side menu, then Developer.
  3. 3Create API key: give it a name and choose the access: Read, or Read & write.
  4. 4Copy the key right away and keep it somewhere safe (a server environment variable).
Auth header
HTTP
Authorization: Bearer rk_live_…​
  • A key acts as the teammate who created it; if the key is revoked or that account is deactivated, requests return 401.
  • A Read key gets 403 on write requests.
  • Never put a key in browser or mobile-app code; call the API only from your own server.

Rate limits

120requests per minutePer key. Above that you get 429 with code rate_limited; the Retry-After header says how many seconds to wait.
30failed attempts per minuteRequests with a wrong key are limited per IP so keys cannot be guessed.
24 hwebhook retriesA failed webhook delivery is retried for about 24 hours.

Idempotency

Every write request (POST and PATCH) must send an Idempotency-Key header: a fresh ID per operation, such as a UUID, up to 255 characters. If the same request arrives again, for example after a network drop, Reshta returns the first response and creates nothing twice.

A write request
POST /orders​Authorization: Bearer rk_live_…​Idempotency-Key: 7f3c2b1e-4a5d-4c6f-9e1a-2b3c4d5e6f70​Content-Type: application/json​
Same key, same bodyThe first response comes back, with an Idempotency-Replayed header; nothing is repeated.
Same key, different body409 with code conflict. Also 409 while the first request is still in progress.
No header400 with code validation_error. Each key is kept for 24 hours.

Errors

Every error has the same shape: a stable code your program can branch on, a message for humans, and details; for validation errors, details names the field.

Every error looks like this
JSON
{​  "error": {​    "code": "validation_error",​    "message": "Invalid request",​    "details": [​      {​        "field": "emails.0.email",​        "message": "Invalid email address"​      }​    ]​  }​}​
validation_error400The body, a parameter or a header is invalid; details names the field.
unauthorized401No key, a wrong or revoked key, or its creator is inactive.
plan_limit_reached402A limit of the business plan was reached.
forbidden403The key has no write access, or its creator may not do this.
not_found404The record does not exist in this business.
conflict409Idempotency-Key reused with another body, or still in progress.
rate_limited429Over 120 requests per minute; see Retry-After.
internal500A Reshta error; try again a little later.
provider_error502An outside provider, such as SMS, failed.

Pagination

Lists are paginated with a cursor, not page numbers. Each response has data and next_cursor; send next_cursor in the next request. When next_cursor is null you have reached the end. The default page size is 50, at most 100.

Next page
HTTP
GET /contacts?limit=50&cursor=eyJpZCI6IjAxOTJjNGU4In0​​{​  "data": [ … ],​  "next_cursor": "eyJpZCI6IjAxOTJjNGY5In0"​}​

Versioning

Added within v1New fields, endpoints and events. Your code must ignore fields it does not know.
Breaking changes → v2Removing a field or changing its meaning only happens in /api/v2, announced in advance in the changelog.

Quickstart

  1. 1Create a Read & write key
  2. 2Put it in RESHTA_API_KEY
  3. 3Create your first contact
Create your first contact
curl https://app.reshta.ir/api/v1/public/contacts \​  -X POST \​  -H "Authorization: Bearer $RESHTA_API_KEY" \​  -H "Idempotency-Key: 7f3c2b1e-4a5d-4c6f-9e1a-2b3c4d5e6f70" \​  -H "Content-Type: application/json" \​  -d '{"first_name":"سارا","last_name":"رضایی","phones":[{"phone":"09121234567","is_primary":true}]}'​
Response
{​  "id": "0192c4e8-7b1a-7c3e-9f20-5d6a1b2c3d4e",​  "first_name": "سارا",​  "last_name": "رضایی",​  "company_id": null,​  "company_name": null,​  "job_title": null,​  "national_id": null,​  "owner_id": "0192a7f0-3b4c-7d5e-8f60-718293a4b5c6",​  "lifecycle_stage": "lead",​  "birthday": null,​  "unsubscribed_email": false,​  "unsubscribed_sms": false,​  "is_sample": false,​  "source": null,​  "marketing_block_reason": null,​  "address": null,​  "custom": {},​  "emails": [],​  "phones": [​    { "id": "0192c4e8-7b1b-7a10-8c21-3d4e5f607182", "phone": "09121234567", "label": null, "is_primary": true }​  ],​  "created_at": "2026-10-26T14:05:12.000Z",​  "updated_at": "2026-10-26T14:05:12.000Z"​}​
Full reference: Create a contact →

Create an API key and send your first request

Keys are created in the Reshta app and shown once. The API and webhooks (beta) are on the Pro and Enterprise plans, and only a business admin can create a key.

  1. 1Sign in at app.reshta.ir
  2. 2Connection → Developer
  3. 3Create API key