Skip to content

API reference

Every Partner API operation, generated from the published OpenAPI description: the scope each one needs, whether sandbox keys can call it, and every status it can return.

Base URL
https://smartremit.ai/api/partner/v1
Authentication
Authorization: Bearer sr_test_… with a sandbox key, or your live key after go-live. The examples below read the key from $SMARTREMIT_TEST_KEY or $SMARTREMIT_LIVE_KEY: export it in your shell first.

Non-custodial remittance orchestration. SmartRemit never holds funds; partners are the licensed money transmitters. Authenticate every request with a Bearer API key: sr_test_… keys work in the sandbox only (they create and see sandbox transactions, which settle on the mock rail), sr_live_… keys after go-live. Errors are JSON { "error": "…" }: match on the HTTP status, not the text. A body that is not valid JSON is treated as an empty object, so it is refused by field validation rather than as malformed input. Rate limit: 120 requests per minute per partner (all keys together) and 120 per minute per key, in fixed UTC calendar minutes.

Corridors

Where this partner can send.

List your corridors

GET /corridors

Data-driven corridor discovery for the partner resolved from the key: the brand, the send-to-India corridors for each allowed send currency, and the full supported destination set.

Scope
corridors:read
Sandbox
Sandbox keys: yes

Responses

List your corridors: responses
StatusMeaningBody
200Corridors available to this partner.See the example belowapplication/json
401Missing or invalid key.Errorapplication/json
403The key lacks corridors:read, or the partner is not active.Errorapplication/json
429Rate limited. Retry after 60 seconds.Errorapplication/json

Example 200 response

{
  "brand": "Example Remit",
  "corridors": [
    {
      "source_country": "US",
      "source_currency": "USD",
      "destination_country": "IN",
      "destination_currency": "INR"
    }
  ],
  "destinations": [
    "IN",
    "MX"
  ]
}

curl

curl -X GET 'https://smartremit.ai/api/partner/v1/corridors' \
  -H "Authorization: Bearer $SMARTREMIT_TEST_KEY"
Try it with a sandbox key

Sandbox keys only (sr_test_…). Never paste a live key.

No response yet

Quotes

FX and fee pricing (nothing is stored).

Price a transfer

POST /quote

FX and fee quote at the platform reference rate. Nothing is stored. Pass destination_country (resolved to its home currency) or destination_currency (default INR); destination_country wins when both are present. Pass sender.phone to price the sender's first transfer at no fee (first_transfer_free: true); this needs a key that also holds transactions:write. Without it, or with an invalid number, the standard fee is shown. The quote is not binding: the transaction's fee is final. Sandbox transfers never use up the free first transfer.

Scope
quote
Sandbox
Sandbox keys: yes

Request body (required, JSON)

{
  "amount_source": 200,
  "source_currency": "USD",
  "destination_country": "IN",
  "sender": {
    "phone": "12025550123"
  }
}

Responses

Price a transfer: responses
StatusMeaningBody
200The quote. first_transfer_free is true when the fee is waived as the sender's first transfer.See the example belowapplication/json
400Invalid request: amount_source is not a positive number, destination_country or destination_currency is not supported, or the amount is outside the allowed range.—
401Missing or invalid key.Errorapplication/json
403The key lacks quote, or the partner is not active.Errorapplication/json
429Rate limited. Retry after 60 seconds.Errorapplication/json
503Live FX is temporarily unavailable. Nothing was stored; retry later.—

Example 200 response

{
  "amount_source": 200,
  "source_currency": "USD",
  "fee_source": 1.99,
  "total_charge_source": 201.99,
  "amount_destination": 17040,
  "destination_currency": "INR",
  "fx_rate": 85.2,
  "first_transfer_free": false
}

curl

curl -X POST 'https://smartremit.ai/api/partner/v1/quote' \
  -H "Authorization: Bearer $SMARTREMIT_TEST_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
  "amount_source": 200,
  "source_currency": "USD",
  "destination_country": "IN",
  "sender": {
    "phone": "12025550123"
  }
}'
Try it with a sandbox key

Sandbox keys only (sr_test_…). Never paste a live key.

No response yet

Beneficiaries

Payout-field validation and stored recipients.

Store a beneficiary

POST /beneficiaries

Validate and store a partner-scoped beneficiary. Payout details are encrypted at rest. Not idempotent: a retry stores a second beneficiary.

Scope
beneficiaries:write
Sandbox
Sandbox keys: no

Request body (required, JSON)

{
  "name": "Ravi Example",
  "country": "IN",
  "payout_method": "bank",
  "fields": {
    "accountNumber": "123456789012",
    "ifsc": "HDFC0001234"
  }
}

Responses

Store a beneficiary: responses
StatusMeaningBody
201Created: { id, name, country, payout_destination }.—
400name is missing or not a clean name (1–80 characters, no brackets or control characters), payout_method is not bank, upi or usdc, or country is missing.—
401Missing or invalid key.Errorapplication/json
403The key lacks beneficiaries:write (test keys never hold it), or the partner is not active.Errorapplication/json
422One or more payout fields are invalid. The error string is a JSON-encoded map of field name to message.—
429Rate limited. Retry after 60 seconds.Errorapplication/json

curl

curl -X POST 'https://smartremit.ai/api/partner/v1/beneficiaries' \
  -H "Authorization: Bearer $SMARTREMIT_LIVE_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
  "name": "Ravi Example",
  "country": "IN",
  "payout_method": "bank",
  "fields": {
    "accountNumber": "123456789012",
    "ifsc": "HDFC0001234"
  }
}'

Validate payout fields

POST /beneficiaries/validate

Stateless payout-field validation for a destination country (a pre-check before creating a beneficiary or a transaction). Nothing is stored.

Scope
beneficiaries:validate
Sandbox
Sandbox keys: yes

Request body (required, JSON)

{
  "country": "IN",
  "fields": {
    "accountNumber": "123456789012",
    "ifsc": "HDFC0001234"
  }
}

Responses

Validate payout fields: responses
StatusMeaningBody
200The fields are valid: { valid: true, payout_destination }.—
400country is required.—
401Missing or invalid key.Errorapplication/json
403The key lacks beneficiaries:validate, or the partner is not active.Errorapplication/json
422One or more fields are invalid. The error string is a JSON-encoded map of field name to message.—
429Rate limited. Retry after 60 seconds.Errorapplication/json

curl

curl -X POST 'https://smartremit.ai/api/partner/v1/beneficiaries/validate' \
  -H "Authorization: Bearer $SMARTREMIT_TEST_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
  "country": "IN",
  "fields": {
    "accountNumber": "123456789012",
    "ifsc": "HDFC0001234"
  }
}'
Try it with a sandbox key

Sandbox keys only (sr_test_…). Never paste a live key.

No response yet

Transactions

Mint, read, list and confirm transfers.

List your transfers

GET /transactions

Newest-first keyset list, scoped to the partner and the environment of the key.

Scope
transactions:read
Sandbox
Sandbox keys: yes

Parameters

List your transfers: parameters
NameInRequiredDescription
limitqueryNoPage size (default 25). Values outside 1–100 are clamped to that range; a non-numeric value uses 25.
cursorqueryNoThe next_cursor of the previous page. Treat it as opaque.

Responses

List your transfers: responses
StatusMeaningBody
200A page of transactions with the next cursor (null on the last page).—
401Missing or invalid key.Errorapplication/json
403The key lacks transactions:read, or the partner is not active.Errorapplication/json
429Rate limited. Retry after 60 seconds.Errorapplication/json

curl

curl -X GET 'https://smartremit.ai/api/partner/v1/transactions' \
  -H "Authorization: Bearer $SMARTREMIT_TEST_KEY"
Try it with a sandbox key

Sandbox keys only (sr_test_…). Never paste a live key.

Optional, 1 to 100.

Optional, from a previous page's next_cursor.

No response yet

Mint a transfer

POST /transactions

Mint a transfer. The Idempotency-Key header is required: once a transaction exists under a key, every request with that key and a valid body returns that same transaction with its current state (the body is validated but not compared). Sanctions screening runs on every mint in every mode; a hit is 422 and the attempt is recorded as blocked. Today screening runs against a built-in reference rule set, not yet a live commercial AML feed. A transaction created without sender.name is held for manual review. client_reference is optional: your own order number, 1 to 64 letters, digits and . _ : / # - characters. It is saved once and comes back in every answer and in the settlements statement. It is also in the settlement instruction when your own rail pays the transaction out (never when another payout partner does). A status callback may send payout_reference (for example a bank UTR) with paid_out; it is saved once. purpose is required: why the money is sent, one of family_support, gift, education, medical, savings, bills, business or other (exactly these lower-case values). A missing or unknown purpose is 422 before the Idempotency-Key is bound, so a corrected retry with the same key succeeds. The purpose is saved, comes back in every answer and is in the settlement instruction's compliance block. purpose_detail is required when purpose is other: the sender's reason in their own words, 10 to 120 characters that say what the money is for. A missing, too short, too long or meaningless purpose_detail is 422 before the Idempotency-Key is bound. When the reason names one of the other purposes (for example school fees), the transaction takes that purpose and keeps the reason. With any other purpose, purpose_detail is ignored. SmartRemit checks every reason, and some transactions are held for review (compliance_status flagged).

Scope
transactions:write
Sandbox
Sandbox keys: yes

Parameters

Mint a transfer: parameters
NameInRequiredDescription
Idempotency-KeyheaderYesA fresh random UUID per transaction, with no personal data. Values beginning draft:, b2binvoice:, sched:, test: or paylink: are reserved and refused with 400.

Request body (required, JSON)

{
  "amount_source": 200,
  "source_currency": "USD",
  "client_reference": "INV-2026-0042",
  "purpose": "family_support",
  "sender": {
    "phone": "+12025550142",
    "name": "Jane Doe",
    "kyc_status": "verified"
  },
  "beneficiary": {
    "name": "Ravi Example",
    "payout_method": "bank",
    "payout_destination": "123456789012|HDFC0001234"
  }
}

Responses

Mint a transfer: responses
StatusMeaningBody
200Replay of an existing Idempotency-Key (same transaction, current state).Transactionapplication/json
201Created.Transactionapplication/json
400Validation failed before the Idempotency-Key was bound: a missing or reserved Idempotency-Key; a missing or invalid amount, sender.phone, beneficiary name or payout destination; a name that is not clean; an unsupported payout_method or destination_country; a client_reference that is not 1 to 64 letters, digits and . _ : / # -; or an amount outside the allowed range. A corrected retry with the same key succeeds.—
401Missing or invalid key.Errorapplication/json
403The key lacks transactions:write, or the partner is not active.Errorapplication/json
404The beneficiary_id was not found for this partner.—
409Idempotency-Key conflict. Retry with a new key.—
422Refused: purpose is missing or is not one of family_support, gift, education, medical, savings, bills, business or other, or purpose is other and purpose_detail is missing, not a string, not 10 to 120 characters or does not say what the money is for (all checked before the Idempotency-Key is bound; a corrected retry with the same key succeeds), the payout destination is a masked display value, the stored beneficiary has no usable name, sender identity verification is required, the transfer exceeds the sender's sending limit, or it was blocked by compliance screening.—
429Rate limited. Retry after 60 seconds.Errorapplication/json
503Live FX is temporarily unavailable, another transfer for this sender is in progress, or new transfers are paused (code sends_paused, with a Retry-After header in seconds). Nothing was minted; a retry may reuse the same Idempotency-Key.Errorapplication/json

curl

curl -X POST 'https://smartremit.ai/api/partner/v1/transactions' \
  -H "Authorization: Bearer $SMARTREMIT_TEST_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H 'Content-Type: application/json' \
  -d '{
  "amount_source": 200,
  "source_currency": "USD",
  "client_reference": "INV-2026-0042",
  "purpose": "family_support",
  "sender": {
    "phone": "+12025550142",
    "name": "Jane Doe",
    "kyc_status": "verified"
  },
  "beneficiary": {
    "name": "Ravi Example",
    "payout_method": "bank",
    "payout_destination": "123456789012|HDFC0001234"
  }
}'

Fetch one transfer

GET /transactions/{id}

Partner-scoped read. A transaction outside your partner or your key's environment is 404.

Scope
transactions:read
Sandbox
Sandbox keys: yes

Parameters

Fetch one transfer: parameters
NameInRequiredDescription
idpathYesThe transaction id.

Responses

Fetch one transfer: responses
StatusMeaningBody
200The transaction.Transactionapplication/json
401Missing or invalid key.Errorapplication/json
403The key lacks transactions:read, or the partner is not active.Errorapplication/json
404Transaction not found.—
429Rate limited. Retry after 60 seconds.Errorapplication/json

curl

curl -X GET 'https://smartremit.ai/api/partner/v1/transactions/{id}' \
  -H "Authorization: Bearer $SMARTREMIT_TEST_KEY"
Try it with a sandbox key

Sandbox keys only (sr_test_…). Never paste a live key.

No response yet

Confirm funds captured

POST /transactions/{id}/confirm

Confirm that funds were captured, which begins settlement. A flagged transfer is held in_review until compliance staff release it. Confirming a transfer that is already paid, delivered or in_review returns it unchanged.

Scope
transactions:write
Sandbox
Sandbox keys: yes

Parameters

Confirm funds captured: parameters
NameInRequiredDescription
idpathYesThe transaction id. A transaction outside your partner or your key's environment is 404.

Responses

Confirm funds captured: responses
StatusMeaningBody
200The transaction after confirmation (paid, in_review, or already settled).Transactionapplication/json
401Missing or invalid key.Errorapplication/json
403The key lacks transactions:write, or the partner is not active.Errorapplication/json
404Transaction not found.—
409The transaction is not awaiting payment (for example, it was cancelled).—
422The transfer was blocked by compliance screening.—
429Rate limited. Retry after 60 seconds.Errorapplication/json

curl

curl -X POST 'https://smartremit.ai/api/partner/v1/transactions/{id}/confirm' \
  -H "Authorization: Bearer $SMARTREMIT_TEST_KEY"

Rates

The partner's own wholesale conversion rates.

Your rate sheet

GET /rates

Your current rates. fresh says whether the rate is still competing (it has a rate and its expiry is in the future). margin_bps is your platform-configured fallback margin.

Scope
rates:read
Sandbox
Sandbox keys: no

Responses

Your rate sheet: responses
StatusMeaningBody
200The rate sheet.See the example belowapplication/json
401Missing or invalid key.Errorapplication/json
403The key lacks rates:read (test keys never hold it), or the partner is not active.Errorapplication/json
429Rate limited. Retry after 60 seconds.Errorapplication/json

Example 200 response

{
  "rates": [
    {
      "source_currency": "USD",
      "destination_currency": "INR",
      "effective_rate": 85.1,
      "expires_at": "2026-09-23T11:00:00.000Z",
      "fresh": true,
      "margin_bps": 150
    }
  ]
}

curl

curl -X GET 'https://smartremit.ai/api/partner/v1/rates' \
  -H "Authorization: Bearer $SMARTREMIT_LIVE_KEY"

Push one corridor rate

PUT /rates

Push the wholesale conversion rate you offer for one corridor. When your fresh rate beats the platform reference rate and your settlement rail is configured, eligible platform transfers are routed to you for settlement. A pushed rate does not change the pricing of your own /quote or /transactions: those stay at the platform reference rate. ttl_seconds defaults to 3600 and is clamped to 60–86400; an expired rate stops competing.

Scope
rates:write
Sandbox
Sandbox keys: no

Request body (required, JSON)

{
  "source_currency": "USD",
  "destination_currency": "INR",
  "effective_rate": 85.1,
  "ttl_seconds": 3600
}

Responses

Push one corridor rate: responses
StatusMeaningBody
200The saved rate.See the example belowapplication/json
400source_currency or destination_currency is unsupported or the two are equal, effective_rate is not a number greater than 0 and less than 100000, or ttl_seconds is not a number.—
401Missing or invalid key.Errorapplication/json
403The key lacks rates:write (test keys never hold it), or the partner is not active.Errorapplication/json
429Rate limited. Retry after 60 seconds.Errorapplication/json

Example 200 response

{
  "source_currency": "USD",
  "destination_currency": "INR",
  "effective_rate": 85.1,
  "expires_at": "2026-09-23T11:00:00.000Z",
  "pushed_at": "2026-09-23T10:00:00.000Z"
}

curl

curl -X PUT 'https://smartremit.ai/api/partner/v1/rates' \
  -H "Authorization: Bearer $SMARTREMIT_LIVE_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
  "source_currency": "USD",
  "destination_currency": "INR",
  "effective_rate": 85.1,
  "ttl_seconds": 3600
}'

Settlements

The settlements statement for reconciliation.

Settlements statement

GET /settlements

The instruction ledger for reconciliation: every live transfer of yours that was paid and sent for settlement in a half-open [from, to) window on paid_at, in UTC. Oldest first. Listed: paid and delivered transfers, and cancelled ones only if a rail was instructed (see refund_status: none, requested, pending, completed or failed). A transfer held for compliance review (in_review) is never listed; once released it appears on its release day, with paid_at set to the release time. totals cover the returned page only (every listed row, cancelled included), per currency, in integer minor units (cents: 20000 = 200.00). The statement never includes payout account details or sender or recipient identity. reference is the transaction id; on the reference rail, provider_ref and payout_reference are simulated. In CSV, a text cell starting with = + - @, a tab or a carriage return is prefixed with ' so a spreadsheet never runs it as a formula. Any partner_id parameter is ignored. Each row ends with client_reference and payout_reference (the last two CSV columns).

Scope
settlements:read
Sandbox
Sandbox keys: no

Parameters

Settlements statement: parameters
NameInRequiredDescription
fromqueryNoWindow start: a date (midnight UTC) or a datetime (no zone means UTC). Default: yesterday.
toqueryNoWindow end (exclusive). The window is at most 31 days.
limitqueryNoPage size, 1–500 (default 100).
cursorqueryNoThe next_cursor of the previous page. Treat it as opaque.
formatqueryNojson (default) or csv. CSV is an attachment with the next cursor in the X-Next-Cursor header.

Responses

Settlements statement: responses
StatusMeaningBody
200The statement page: { settlements, next_cursor, totals, window }, or a CSV attachment.application/json, text/csv
400Invalid query: from or to is not a date or datetime, to is not after from, the window is longer than 31 days, or limit, cursor or format is invalid.—
401Missing or invalid key.Errorapplication/json
403The key lacks settlements:read (test keys never hold it), or the partner is not active.Errorapplication/json
429Rate limited. Retry after 60 seconds.Errorapplication/json

curl

curl -X GET 'https://smartremit.ai/api/partner/v1/settlements' \
  -H "Authorization: Bearer $SMARTREMIT_LIVE_KEY"

Schemas

Error

Error fields
FieldTypeRequiredDescription
errorstringYesHuman-readable message. Match on the HTTP status, not the text.
codestringNoMachine-readable reason, present on some errors only. sends_paused: new transfers are paused for a short time; retry after the Retry-After header.

Transaction

Transaction fields
FieldTypeRequiredDescription
idstringNo
statusstringNoFor example awaiting_payment, paid, in_review, delivered, blocked or cancelled.
compliance_statusstringNocleared, flagged or blocked.
amount_sourcenumberNoMajor units in source_currency.
source_currencystringNoISO 4217.
amount_destinationnumberNoPayout amount in destination_currency.
destination_currencystringNoISO 4217.
destination_countrystringNoISO 3166-1 alpha-2.
fee_sourcenumberNo
total_charge_sourcenumberNo
fx_ratenumberNoDestination units per 1 source unit.
sender_phonestringNo
sender_namestring | nullNo
recipient_namestringNo
funding_methodstringNo
funding_refstring | nullNo
refund_refstring | nullNo
created_atstring (date-time)No
partner_idstringNo
client_referencestring | nullNoYour own order number, exactly as you sent it on create. Write-once.
payout_referencestring | nullNoThe payout partner's confirmation (for example a bank UTR), from its signed status callback. Set once; null until reported.
purposestring | nullNoWhy the money is sent, as given on create. When you sent other with a purpose_detail that names one of the other purposes (for example school fees), this is that purpose. Null only on a transaction made before purpose was required.
purpose_detailstring | nullNoThe sender's reason in their own words, sent with purpose other (10 to 120 characters, spaces tidied). Returned only to the partner that owns the transaction. Null when none was given.