Skip to content

ANS-24114 Align with PayPo API 3.1 - #15

Merged
Wiktor6 merged 2 commits into
masterfrom
paypo-api-3-1-alignment
Sep 24, 2026
Merged

Wiktor6 merged 2 commits into
masterfrom
paypo-api-3-1-alignment

Conversation

@Wiktor6

@Wiktor6 Wiktor6 commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Brings the library in line with the PayPo API 3.1 documentation.

Refunds

  • RefundRequest and Order::refund() accept an optional referenceRefundId. PayPo does not return a refund identifier of its own, so this is the only way to match a refund later on.
  • StatusResponse exposes the refunds list from the extended status response as Refund[], plus findRefund() to look one up by identifier. The list is empty when PayPo has not enabled the extended response for given merchant. Refund::$referenceRefundId is nullable, as refunds created outside of our system have none.

Error handling

  • 4xx responses now throw ApiErrorException, which carries the status code and the parsed error body: code, message and per field validation errors. Until now every failure was reported as ServiceUnavailable, so the reason of a rejected refund or a 409 on cancelling a completed transaction was lost.
  • ServiceUnavailable is still thrown for 5xx responses and connection problems.
  • ApiErrorException extends ServiceUnavailable for backward compatibility, so existing catch blocks keep working. To be dropped in the next major release.

Notifications

  • Notify reads transactionUrl, settlementStatus and message.
  • isSettlementNotify() tells a settlement notification apart from a plain status or amount change.
  • Added the Notify::SIGNATURE_HEADER constant.

Other

  • ConfirmResponse accepts the documented message field. It required statusDescription only, so deserializing a real response failed. Both fields are kept and filled.
  • CreateRequest::setId() sets the optional transaction id.

AC

  • refunds are sent with our own identifier and can be matched back from the status response
  • a rejected request can be told apart from an unreachable API
  • existing calls and catch blocks keep working without changes

- send own refund identifier (referenceRefundId) with a refund request
- expose the refunds list returned by the extended status response
- throw ApiErrorException with the parsed error body for 4xx responses,
  keep ServiceUnavailable for 5xx and connection problems
- read transactionUrl, settlementStatus and message from notifications
- accept the documented message field in ConfirmResponse
- allow setting an optional transaction id on CreateRequest
@yekovalenkoa
yekovalenkoa self-requested a review September 16, 2026 10:51
return new self(
isset($refund['referenceRefundId']) ? (string) $refund['referenceRefundId'] : null,
(int) $refund['amount'],
(string) $refund['created'],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A refund without amount/created raises "Undefined array key" warnings and silently produces amount = 0 with created set to now.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed: an entry without amount/created now throws, surfaced as BadResponseException. Also refunds is now null when PayPo doesn't send the extended status response, so a disabled feature isn't confused with no refunds.

@ropczan
ropczan self-requested a review September 18, 2026 07:45
Comment thread src/PayPo/Response/Error/ApiError.php Outdated
* @param ErrorDetail[] $errors
*/
public function __construct(
public ?int $code,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typing it ?int with a hard cast turns a non-numeric API code such as "REFUND_TOO_HIGH" into 0, and contradicts Response::$code / ConfirmResponse::$code, which are strings

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to ?string, consistent with Response::$code.

{
private const HTTP_METHOD = 'POST';
private const ENDPOINT = '/transactions';
public const REFERENCE_REFUND_ID_MAX_LENGTH = 68;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dead code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed.

Comment thread src/PayPo/Response/Notify.php Outdated
public readonly ?string $message = null,
) {
$this->transactionStatus = OrderStatusEnum::from($transactionStatus);
$this->settlementStatus = null === $settlementStatus ? null : SettlementStatusEnum::from($settlementStatus);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from -> tryFrom

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switched to tryFrom; isSettlementNotify() now depends on the field being present, so an unknown status is still recognized as a settlement notify.

- refunds is null without the extended status response, [] when empty
- refund entry without amount or created raises BadResponseException
- keep ApiError code as string, consistent with Response code
- remove unused REFERENCE_REFUND_ID_MAX_LENGTH
- tryFrom for notify settlementStatus, settlement notify by field
  presence
@Wiktor6
Wiktor6 merged commit b7ff6e0 into master Sep 24, 2026
6 checks passed
@Wiktor6
Wiktor6 deleted the paypo-api-3-1-alignment branch September 24, 2026 12:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants