Skip to content
Linq Copy agent prompt

Create a payment request

POST/v3/payment_requests

Creates a payment request and returns a checkout_url the recipient opens to pay with Apple Pay or card. Funds settle directly to your connected Stripe account. A payment request is independent of any chat; to associate one with a chat for your records, store the chat id in metadata. Requires your connected account to be charges_enabled (returns 403 otherwise).

Set mode: subscription with a recurring price_id from your connected Stripe account to start an auto-renewing subscription instead of a one-time charge — the recipient pays the first invoice at checkout and the response’s stripe object carries the customer and subscription ids for the ongoing lifecycle in your own Stripe account. See the Subscriptions section of the tag overview.

In either mode, pass customer_id to attach the request to an existing Customer on your connected account instead of creating a new one — see Pre-created customers in the tag overview.

Header ParametersExpand Collapse
"Idempotency-Key": optional string
maxLength200
Body ParametersJSONExpand Collapse
amount: optional number

Amount to charge, in the currency’s minor units (e.g. cents). Must be at least the payment provider’s minimum (50 for usd). Required in payment mode; must be omitted in subscription mode (the amount comes from the price).

formatint64
minimum50
currency: optional string

Three-letter ISO 4217 currency code. Only usd is currently supported. Required in payment mode; must be omitted in subscription mode (the currency comes from the price).

customer_id: optional string

Optional id of an existing Customer on your connected Stripe account (cus_...) to attach this request to, instead of a new Customer being created. In payment mode the charge lands on that customer’s payment history; in subscription mode the subscription is created on them. The customer must exist (and not be deleted) on your connected account.

description: optional string

Optional description shown to the recipient at checkout.

maxLength1000
discount: optional object { coupon, label, promotion_code }

Subscription mode only. The coupon or promotion code to apply to this subscription payment. Currently, only accept one coupon or one promo code.

coupon: optional string

The ID of the coupon to apply to this subscription.

maxLength255
label: optional string

Name of the coupon/promo code displayed to customers.

maxLength100
promotion_code: optional string

The ID of a promotion code to apply to this subscription.

from: optional string

Required for rail: natural. The line the request is sent from, in E.164 format. Must be a phone number your organization owns.

metadata: optional map[string]

Optional key/value metadata (up to 49 keys) echoed back on retrieval and on payment.* webhooks, and stamped on the Stripe objects we create on your connected account (the PaymentIntent, and in subscription mode the Subscription and any Customer created for you — a customer you pass via customer_id is never modified) — use it to correlate a request with your own records (e.g. a chat id). Keys starting with linq_ are reserved.

mode: optional "payment" or "subscription"

payment (default) collects a one-time charge for amount + currency. subscription starts an auto-renewing subscription from a recurring price_id on your connected Stripe account: the recipient pays the first invoice at checkout and Stripe renews it automatically from then on.

One of the following:
"payment"
"subscription"
payer_handle: optional string

Required for rail: natural. The payer to bill, in E.164 format.

price_id: optional string

Subscription mode only (required there): id of an active recurring Price on your connected Stripe account (price_...). If you sell through Stripe Payment Links today, pass the same price the link was built from to get the native iMessage checkout for it.

quantity: optional number

Subscription mode only — units of the price to subscribe to.

formatint64
minimum1
maximum999
rail: optional "stripe" or "natural"

Payment rail. stripe (default) is the direct-charge flow that settles to your connected Stripe account. natural collects through the Natural custodial wallet; it requires from + payer_handle and that your organization has completed Natural merchant onboarding.

One of the following:
"stripe"
"natural"
trial_end: optional string

Subscription mode only — end the free trial at a fixed timestamp (must be in the future) instead of a day count. Mutually exclusive with trial_period_days.

formatdate-time
trial_period_days: optional number

Subscription mode only — start with a free trial of this many days. The recipient’s card is still collected at checkout (Apple Pay or card), saved to the subscription, and first charged when the trial ends. Mutually exclusive with trial_end.

formatint64
minimum1
maximum730
ReturnsExpand Collapse
PaymentRequest object { id, amount, checkout_url, 19 more }
id: string

Unique identifier of the payment request.

formatuuid
amount: number

What the recipient is charged at checkout, in the currency’s minor units. In subscription mode this is the first invoice’s amount due — all items after any discounts are applied — so a discount that covers the whole invoice returns 0 and checkout shows $0.00.

formatint64
checkout_url: string

URL the recipient opens to pay: https://zero.linqapp.com/pay/{slug}?session=..., where {slug} is your partner checkout slug.

created_at: string
formatdate-time
currency: string
mode: "payment" or "subscription"

Whether this request collects a one-time charge or starts a subscription.

One of the following:
"payment"
"subscription"
object: string
status: "requested" or "succeeded" or "canceled" or "expired"

Lifecycle status of the payment request.

One of the following:
"requested"
"succeeded"
"canceled"
"expired"
description: optional string
discount: optional object { coupon, label, promotion_code }

Subscription mode — the discount applied, as Stripe applied it.

coupon: optional string

The ID of the coupon applied.

label: optional string

The customer-facing discount description shown at checkout.

promotion_code: optional string

The ID of the promotion code applied, if you passed one.

expires_at: optional string

When an unpaid request auto-expires.

formatdate-time
interval: optional "day" or "week" or "month" or "year"

Subscription mode — how often the subscription renews.

One of the following:
"day"
"week"
"month"
"year"
interval_count: optional number

Subscription mode — intervals per renewal (e.g. 3 + month = quarterly).

formatint64
metadata: optional map[string]
natural: optional object { payment_request_id, transaction_id }

Natural-rail join keys, present when rail: natural.

payment_request_id: optional string

The Natural payment request (prq_...).

transaction_id: optional string

The settled transaction (txn_...).

price_id: optional string

Subscription mode — the recurring price this request subscribes to.

quantity: optional number

Subscription mode — units of the price subscribed to.

formatint64
rail: optional "stripe" or "natural"

The rail this request settled on.

One of the following:
"stripe"
"natural"
stripe: optional object { customer_id, payment_intent_id, subscription_id }

Ids of the Stripe objects created on your connected account — your join keys into your own Stripe Dashboard, webhooks, and API. After a subscription’s first payment succeeds, its ongoing lifecycle (renewals, plan changes, cancellation) is managed in your Stripe account using subscription_id.

customer_id: optional string

The Customer this request is attached to (cus_...). Always set in subscription mode (created for you unless you passed customer_id); set in payment mode only when you passed one.

payment_intent_id: optional string

The PaymentIntent collected at checkout (pi_...).

subscription_id: optional string

Subscription mode — the Subscription (sub_...).

trial_end: optional string

Subscription mode — when the free trial ends and the first charge happens. Present only on trial requests; paid_at/succeeded mean the payment method was collected (no funds move until this time).

formatdate-time
updated_at: optional string
formatdate-time

Create a payment request

curl https://api.linqapp.com/api/partner/v3/payment_requests \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $LINQ_API_V3_API_KEY" \
    -d '{
          "amount": 497,
          "currency": "usd",
          "customer_id": "cus_QAbCdEfGhIjKlMn",
          "description": "Coffee with Ava",
          "from": "+12025550123",
          "payer_handle": "+12025550199",
          "price_id": "price_1QAbCdEfGhIjKlMn",
          "trial_period_days": 14
        }'
{
  "id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
  "amount": 497,
  "checkout_url": "https://zero.linqapp.com/pay/tomo?session=tok_abc123",
  "created_at": "2019-12-27T18:11:19.117Z",
  "currency": "usd",
  "mode": "payment",
  "object": "payment_request",
  "status": "requested",
  "description": "description",
  "discount": {
    "coupon": "LAUNCH50",
    "label": "15 OFF FIRST MONTH",
    "promotion_code": "promo_1QAbCdEfGhIjKlMn"
  },
  "expires_at": "2019-12-27T18:11:19.117Z",
  "interval": "day",
  "interval_count": 0,
  "metadata": {
    "foo": "string"
  },
  "natural": {
    "payment_request_id": "payment_request_id",
    "transaction_id": "transaction_id"
  },
  "paid_at": "2019-12-27T18:11:19.117Z",
  "price_id": "price_id",
  "quantity": 0,
  "rail": "stripe",
  "stripe": {
    "customer_id": "cus_QAbCdEfGhIjKlMn",
    "payment_intent_id": "pi_3QAbCdEfGhIjKlMn",
    "subscription_id": "sub_1QAbCdEfGhIjKlMn"
  },
  "trial_end": "2019-12-27T18:11:19.117Z",
  "updated_at": "2019-12-27T18:11:19.117Z"
}
{
  "error": {
    "status": 400,
    "code": 1002,
    "message": "Phone number must be in E.164 format",
    "doc_url": "https://docs.linqapp.com/channel/imessage/error/codes/1xxx/1002/"
  },
  "success": false
}
{
  "error": {
    "status": 401,
    "code": 2004,
    "message": "Unauthorized - missing or invalid authentication token",
    "doc_url": "https://docs.linqapp.com/channel/imessage/error/codes/2xxx/2004/"
  },
  "success": false
}
{
  "error": {
    "status": 403,
    "code": 2005,
    "message": "Access denied - insufficient permissions for this resource",
    "doc_url": "https://docs.linqapp.com/channel/imessage/error/codes/2xxx/2005/"
  },
  "success": false
}
{
  "error": {
    "status": 409,
    "code": 2013,
    "message": "This chat is unavailable",
    "doc_url": "https://docs.linqapp.com/channel/imessage/error/codes/2xxx/2013/"
  },
  "success": false
}
{
  "error": {
    "status": 500,
    "code": 3006,
    "message": "Internal server error",
    "doc_url": "https://docs.linqapp.com/channel/imessage/error/codes/3xxx/3006/"
  },
  "success": false
}
Returns Examples
{
  "id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
  "amount": 497,
  "checkout_url": "https://zero.linqapp.com/pay/tomo?session=tok_abc123",
  "created_at": "2019-12-27T18:11:19.117Z",
  "currency": "usd",
  "mode": "payment",
  "object": "payment_request",
  "status": "requested",
  "description": "description",
  "discount": {
    "coupon": "LAUNCH50",
    "label": "15 OFF FIRST MONTH",
    "promotion_code": "promo_1QAbCdEfGhIjKlMn"
  },
  "expires_at": "2019-12-27T18:11:19.117Z",
  "interval": "day",
  "interval_count": 0,
  "metadata": {
    "foo": "string"
  },
  "natural": {
    "payment_request_id": "payment_request_id",
    "transaction_id": "transaction_id"
  },
  "paid_at": "2019-12-27T18:11:19.117Z",
  "price_id": "price_id",
  "quantity": 0,
  "rail": "stripe",
  "stripe": {
    "customer_id": "cus_QAbCdEfGhIjKlMn",
    "payment_intent_id": "pi_3QAbCdEfGhIjKlMn",
    "subscription_id": "sub_1QAbCdEfGhIjKlMn"
  },
  "trial_end": "2019-12-27T18:11:19.117Z",
  "updated_at": "2019-12-27T18:11:19.117Z"
}
{
  "error": {
    "status": 400,
    "code": 1002,
    "message": "Phone number must be in E.164 format",
    "doc_url": "https://docs.linqapp.com/channel/imessage/error/codes/1xxx/1002/"
  },
  "success": false
}
{
  "error": {
    "status": 401,
    "code": 2004,
    "message": "Unauthorized - missing or invalid authentication token",
    "doc_url": "https://docs.linqapp.com/channel/imessage/error/codes/2xxx/2004/"
  },
  "success": false
}
{
  "error": {
    "status": 403,
    "code": 2005,
    "message": "Access denied - insufficient permissions for this resource",
    "doc_url": "https://docs.linqapp.com/channel/imessage/error/codes/2xxx/2005/"
  },
  "success": false
}
{
  "error": {
    "status": 409,
    "code": 2013,
    "message": "This chat is unavailable",
    "doc_url": "https://docs.linqapp.com/channel/imessage/error/codes/2xxx/2013/"
  },
  "success": false
}
{
  "error": {
    "status": 500,
    "code": 3006,
    "message": "Internal server error",
    "doc_url": "https://docs.linqapp.com/channel/imessage/error/codes/3xxx/3006/"
  },
  "success": false
}