Moves a buyer's inscription from their current subscription to a different subscription in the same company — e.g. an upgrade/downgrade between plans — without losing their payment history. The source Subscription Buyer is set to finished and a new one is created as active on the target subscription, carrying over the buyer's active card and billing cycle.
| Time | Status | User Agent | |
|---|---|---|---|
Retrieving recent requests… | |||
Possible Rejections
Two different response shapes are used — don't assume error.message works everywhere:
400/401/404→{"error": {"code": <status>, "message": "..."}}409→{"message": "..."}— noerrorwrapper, nocode.
| # | Check | HTTP | Response body | Notes |
|---|---|---|---|---|
| 1 | Source subscription_buyer_id exists | 404 | {"error": {"code": 404, "message": "Record not found."}} | |
| 2 | Source Subscription Buyer belongs to your company | 401 | {"error": {"code": 401, "message": "Invalid credentials."}} | Cross-tenant access reads as an auth failure, not a 404. |
| 3 | Source subscription is Zafepay-native (not shopify, jumpseller, woocommerce) | 400 | {"error": {"code": 400, "message": "Only Zafepay subscription buyers can be changed."}} | Buyers enrolled through an e-commerce integration can't be migrated this way. |
| 4 | Source status is one of active, indebt, paused, problem_on_charge, or finished | 400 | {"error": {"code": 400, "message": "<status> subscription_buyers cannot be changed."}} | Rejects pending, canceled, active_pending, etc. |
| 5 | subscription_id param present | 400 | {"error": {"code": 400, "message": "Missing 'subscription_id' param"}} | |
| 6 | Target subscription_id exists | 404 | {"error": {"code": 404, "message": "Record not found."}} | |
| 7 | Target subscription belongs to your company | 401 | {"error": {"code": 401, "message": "Invalid credentials."}} | |
| 8a | Source is not already finished | 409 | {"message": "The subscription buyer is already finished."} | Hit if you retry a call that already succeeded. |
| 8b | Source has no installment processing_payment/processing_refund | 409 | {"message": "Subscription Buyer has an installment in processing status."} | Wait for the in-flight installment to settle, then retry. |
| 8c | subscription_id differs from the source's current subscription | 409 | {"message": "The buyer already belongs to the target subscription."} | |
| 8d | Buyer has no other active Subscription Buyer already on the target | 409 | {"message": "The buyer already has an active subscription buyer in the target subscription."} | |
| 8e | Target's inscriptions_limit (if set) isn't already reached | 409 | {"message": "Inscriptions limit reached for the target subscription."} | |
| 9 | invoice_information satisfies the target's invoice configuration (only checked when the company has the TuFacturador integration and the target emits documents) | 400 | {"error": {"code": 400, "message": "Invoice information is required when the service emits documents"}} or {"error": {"code": 400, "message": "Invoice emission requires: <missing fields>"}} | See the invoicing documentation for which fields are required per document type. |
| 10 | invoice_information/shipping_address pass model validation (e.g. commune is a real Chilean commune) | 400 | {"error": {"code": 400, "message": "Validation failed: ..."}} | Fails after step 9 passes, once the migration is actually being persisted — still rolls back the whole migration. |
| 11 | extra_fields match the target subscription's configured extra fields (unknown key, missing mandatory field, invalid selector value) | 400 | {"error": {"code": 400, "message": "..."}} | Same extra_fields validation used by create/update — see that documentation for the full set of messages. |
Steps 1–8 run before anything is created or changed — the source Subscription Buyer is untouched on any of those failures. Steps 9–11 run inside the same database transaction as the actual migration: if any of them fail, the whole migration (source status, card, invoice/shipping data, new record) is rolled back — the source is left exactly as it was, and no new Subscription Buyer is created.
Request Body
Content-Type: application/json
| Field | Type | Required | Description |
|---|---|---|---|
| subscription_id | string | Yes | Id of the target Subscription. |
| extra_fields | JSON string | No | Extra fields answers carried onto the new Subscription Buyer. |
| invoice_information | object | Conditional | Required only when the target subscription emits documents and the company has the TuFacturador integration. Fields: rut, business_name, activity, address, commune, region, email. Which fields are required depends on the target's invoice configuration — see the invoicing documentation. |
| shipping_address | object | No | If sent, overwrites the buyer's shipping address. Fields: region, address1, address2, country, commune, phone. |
Response Schema (200 OK)
Returns the new Subscription Buyer:
| Field | Type | Example |
|---|---|---|
| id | string | e1a2cdc9-1ad5-4947-b641-84a95675d063 |
| buyer.id | string | 0d27afe0-7a02-41e1-9494-a955c21c0a3a |
| buyer.created_at | string | 2023-10-10T12:35:13 |
| buyer.email | string | [email protected] |
| buyer.external_id | string | customer003 |
| buyer.name | string | Jhon Smith |
| buyer.updated_at | string | 2023-10-10T12:40:11 |
| created_at | string | 2023-10-10T16:04:54 |
| current_installment.amount | integer | 40990 |
| current_installment.due_date | string | 2023-10-10 |
| current_installment.currency | string | CLP |
| current_installment.status | string | pending |
| external_id | string | sb001 |
| extra_fields.Rut | string | 22.222.222-2 |
| payment_url | string | https://staging.zafepay.com/subscription_buyers/da7b6q1b-c744-4c2e-9749-f935a4ce9dab |
| status | string | active |
| subscription_id | string | a3a50c65-0dbc-4fd9-9735-b3c36feb37ea |
| updated_at | string | 2023-10-10T21:39:07 |
The old Subscription Buyer is not deleted — it's set to
finished, with a note recording which subscription it moved to, and the new one'sparent_idpoints back to it so you can trace the chain.